You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-[Why are we using Snappy for compression?](#why-are-we-using-snappy-for-compression)
103
107
-[Can I get access to unencrypted bytes on the wire for debugging purposes?](#can-i-get-access-to-unencrypted-bytes-on-the-wire-for-debugging-purposes)
104
108
-[What are SSZ type size bounds?](#what-are-ssz-type-size-bounds)
109
+
-[Why is the message size defined in terms of application payload?](#why-is-the-message-size-defined-in-terms-of-application-payload)
110
+
-[Why is there a limit on message sizes at all?](#why-is-there-a-limit-on-message-sizes-at-all)
<!-- END doctoc generated TOC please keep comment here to allow auto update -->
@@ -193,11 +199,10 @@ This section outlines configurations that are used in this spec.
193
199
194
200
| Name | Value | Description |
195
201
|---|---|---|
196
-
|`GOSSIP_MAX_SIZE`|`10 * 2**20` (= 10485760, 10 MiB) | The maximum allowed size of uncompressed gossip messages.|
202
+
|`MAX_PAYLOAD_SIZE`|`10 * 2**20` (= 10485760, 10 MiB) | The maximum allowed size of uncompressed payload in gossipsub messages and RPC chunks|
197
203
|`MAX_REQUEST_BLOCKS`|`2**10` (= 1024) | Maximum number of blocks in a single request |
198
204
|`EPOCHS_PER_SUBNET_SUBSCRIPTION`|`2**8` (= 256) | Number of epochs on a subnet subscription (~27 hours) |
199
205
|`MIN_EPOCHS_FOR_BLOCK_REQUESTS`|`MIN_VALIDATOR_WITHDRAWABILITY_DELAY + CHURN_LIMIT_QUOTIENT // 2` (= 33024, ~5 months) | The minimum epoch range over which a node must serve blocks |
200
-
|`MAX_CHUNK_SIZE`|`10 * 2**20` (=10485760, 10 MiB) | The maximum allowed size of uncompressed req/resp chunked responses. |
201
206
|`ATTESTATION_PROPAGATION_SLOT_RANGE`|`32`| The maximum number of slots during which an attestation can be propagated. |
202
207
|`MAXIMUM_GOSSIP_CLOCK_DISPARITY`|`500`| The maximum **milliseconds** of clock disparity assumed between honest nodes. |
203
208
|`MESSAGE_DOMAIN_INVALID_SNAPPY`|`DomainType('0x00000000')`| 4-byte domain for gossip message-id isolation of *invalid* snappy messages |
@@ -229,6 +234,27 @@ Where
229
234
is entirely independent of the ENR sequence number,
230
235
and will in most cases be out of sync with the ENR sequence number.
231
236
237
+
### Maximum message sizes
238
+
239
+
Maximum message sizes are derived from the maximum payload size that the network can carry according to the following functions:
240
+
241
+
#### `max_compressed_len`
242
+
243
+
```python
244
+
defmax_compressed_len(n: uint64) -> uint64:
245
+
# Worst-case compressed length for a given payload of size n when using snappy:
Clients MUST support the [gossipsub v1](https://github.com/libp2p/specs/blob/master/pubsub/gossipsub/gossipsub-v1.0.md) libp2p Protocol
@@ -268,13 +294,11 @@ This defines both the type of data being sent on the topic and how the data fiel
268
294
-`Encoding` - the encoding strategy describes a specific representation of bytes that will be transmitted over the wire.
269
295
See the [Encodings](#Encodings) section for further details.
270
296
297
+
Clients MUST reject messages with an unknown topic.
298
+
271
299
*Note*: `ForkDigestValue` is composed of values that are not known until the genesis block/state are available.
272
300
Due to this, clients SHOULD NOT subscribe to gossipsub topics until these genesis values are known.
273
301
274
-
Each gossipsub [message](https://github.com/libp2p/go-libp2p-pubsub/blob/master/pb/rpc.proto#L17-L24) has a maximum size of `GOSSIP_MAX_SIZE`.
275
-
Clients MUST reject (fail validation) messages that are over this size limit.
276
-
Likewise, clients MUST NOT emit or propagate messages larger than this limit.
277
-
278
302
The optional `from` (1), `seqno` (3), `signature` (5) and `key` (6) protobuf fields are omitted from the message,
279
303
since messages are identified by content, anonymous, and signed where necessary in the application layer.
280
304
Starting from Gossipsub v1.1, clients MUST enforce this by applying the `StrictNoSign`
@@ -288,6 +312,8 @@ The `message-id` of a gossipsub message MUST be the following 20 byte value comp
288
312
the concatenation of `MESSAGE_DOMAIN_INVALID_SNAPPY` with the raw message data,
289
313
i.e. `SHA256(MESSAGE_DOMAIN_INVALID_SNAPPY + message.data)[:20]`.
290
314
315
+
Where relevant, clients MUST reject messages with `message-id` sizes other than 20 bytes.
316
+
291
317
*Note*: The above logic handles two exceptional cases:
292
318
(1) multiple snappy `data` can decompress to the same value,
293
319
and (2) some message `data` can fail to snappy decompress altogether.
@@ -502,6 +528,16 @@ so [basic snappy block compression](https://github.com/google/snappy/blob/master
502
528
Implementations MUST use a single encoding for gossip.
503
529
Changing an encoding will require coordination between participating implementations.
504
530
531
+
#### Gossipsub size limits
532
+
533
+
Size limits are placed both on the [`RPCMsg`](https://github.com/libp2p/specs/blob/b5f7fce29b32d4c7d0efe37b019936a11e5db872/pubsub/README.md#the-rpc) frame as well as the encoded payload in each [`Message`](https://github.com/libp2p/specs/blob/b5f7fce29b32d4c7d0efe37b019936a11e5db872/pubsub/README.md#the-message).
534
+
535
+
Clients MUST reject and MUST NOT emit or propagate messages whose size exceed the following limits:
536
+
537
+
* The size of the encoded `RPCMsg` (including control messages, framing, topics, etc) must not exceed `max_message_size()`.
538
+
* The size of the compressed payload in the `Message.data` field must not exceed `max_compressed_len(MAX_PAYLOAD_SIZE)`.
539
+
* The size of the uncompressed payload must not exceed `MAX_PAYLOAD_SIZE` or the [type-specific SSZ bound](#what-are-ssz-type-size-bounds), whichever is lower.
540
+
505
541
### The Req/Resp domain
506
542
507
543
#### Protocol identification
@@ -551,7 +587,7 @@ All other response types (non-Lists) send a single `response_chunk`.
551
587
For both `request`s and `response`s, the `encoding-dependent-header` MUST be valid,
552
588
and the `encoded-payload` must be valid within the constraints of the `encoding-dependent-header`.
553
589
This includes type-specific bounds on payload size for some encoding strategies.
554
-
Regardless of these type specific bounds, a global maximum uncompressed byte size of `MAX_CHUNK_SIZE` MUST be applied to all method response chunks.
590
+
Regardless of these type specific bounds, a global maximum uncompressed byte size of `MAX_PAYLOAD_SIZE` MUST be applied to all method response chunks.
555
591
556
592
Clients MUST ensure that lengths are within these bounds; if not, they SHOULD reset the stream immediately.
557
593
Clients tracking peer reputation MAY decrement the score of the misbehaving peer under this circumstance.
@@ -665,15 +701,13 @@ When snappy is applied, it can be passed through a buffered Snappy reader to dec
665
701
666
702
Before reading the payload, the header MUST be validated:
667
703
- The unsigned protobuf varint used for the length-prefix MUST not be longer than 10 bytes, which is sufficient for any `uint64`.
668
-
- The length-prefix is within the expected [size bounds derived from the payload SSZ type](#what-are-ssz-type-size-bounds).
704
+
- The length-prefix is within the expected [size bounds derived from the payload SSZ type](#what-are-ssz-type-size-bounds) or `MAX_PAYLOAD_SIZE`, whichever is smaller.
669
705
670
706
After reading a valid header, the payload MAY be read, while maintaining the size constraints from the header.
671
707
672
-
A reader SHOULD NOT read more than `max_encoded_len(n)` bytes after reading the SSZ length-prefix `n` from the header.
673
-
- For `ssz_snappy` this is: `32 + n + n // 6`.
674
-
This is considered the [worst-case compression result](https://github.com/google/snappy/blob/537f4ad6240e586970fe554614542e9717df7902/snappy.cc#L98) by Snappy.
708
+
A reader MUST NOT read more than `max_compressed_len(n)` bytes after reading the SSZ length-prefix `n` from the header.
675
709
676
-
A reader SHOULD consider the following cases as invalid input:
710
+
A reader MUST consider the following cases as invalid input:
677
711
- Any remaining bytes, after having read the `n` SSZ bytes. An EOF is expected if more bytes are read than required.
678
712
- An early EOF, before fully reading the declared length-prefix worth of SSZ bytes.
679
713
@@ -1430,7 +1464,7 @@ Nevertheless, in the case of `ssz_snappy`, messages are still length-prefixed wi
1430
1464
* Alignment with protocols like gRPC over HTTP/2 that prefix with length
1431
1465
* Sanity checking of message length, and enabling much stricter message length limiting based on SSZ type information,
1432
1466
to provide even more DOS protection than the global message length already does.
1433
-
E.g. a small `Status` message does not nearly require `MAX_CHUNK_SIZE` bytes.
1467
+
E.g. a small `Status` message does not nearly require `MAX_PAYLOAD_SIZE` bytes.
1434
1468
1435
1469
[Protobuf varint](https://developers.google.com/protocol-buffers/docs/encoding#varints) is an efficient technique to encode variable-length (unsigned here) ints.
1436
1470
Instead of reserving a fixed-size field of as many bytes as necessary to convey the maximum possible value, this field is elastic in exchange for 1-bit overhead per byte.
@@ -1679,6 +1713,22 @@ Other types are static, they have a fixed size: no dynamic-length content is inv
1679
1713
For reference, the type bounds can be computed ahead of time, [as per this example](https://gist.github.com/protolambda/db75c7faa1e94f2464787a480e5d613e).
1680
1714
It is advisable to derive these lengths from the SSZ type definitions in use, to ensure that version changes do not cause out-of-sync type bounds.
1681
1715
1716
+
#### Why is the message size defined in terms of application payload?
1717
+
1718
+
When transmitting messages over gossipsub and/or the req/resp domain, we want to ensure that the same payload sizes are supported regardless of the underlying transport, decoupling the consensus layer from libp2p-induced overhead and the particular transmission strategy.
1719
+
1720
+
To derive "encoded size limits" from desired application sizes, we take into account snappy compression and framing overhead.
1721
+
1722
+
In the case of gossipsub, the protocol supports sending multiple application payloads as well as mixing application data with control messages in each gossipsub frame. The limit is set such that at least one max-sized application-level message together with a small amount (1 KiB) of gossipsub overhead is allowed. Implementations are free to pack multiple smaller application messages into a single gossipsub frame, and/or combine it with control messages as they see fit.
1723
+
1724
+
The limit is set on the uncompressed payload size in particular to protect against decompression bombs.
1725
+
1726
+
#### Why is there a limit on message sizes at all?
1727
+
1728
+
The message size limit protects against several forms of DoS and network-based amplification attacks and provides upper bounds for resource (network, memory) usage in the client based on protocol requirements to decode, buffer, cache, store and re-transmit messages which in turn translate into performance and protection tradeoffs, ensuring capacity to handle worst cases during recovery from network instability.
1729
+
1730
+
In particular, blocks—-currently the only message type without a practical SSZ-derived upper bound on size—-cannot be fully verified synchronously as part of gossipsub validity checks. This means that there exist cases where invalid messages signed by a validator may be amplified by the network.
1731
+
1682
1732
## libp2p implementations matrix
1683
1733
1684
1734
This section will soon contain a matrix showing the maturity/state of the libp2p features required
0 commit comments