https://github.com/status-im/nimbus-eth2/pull/4550
The maximum block size is 1.8 MB - depending on who you ask, the blob adds another 128-1024kb on top of that. Data takes time to stream: 1mb on 10mbit = 1 s of streaming - we maintain a gossip mesh of ~8 peers, meaning that if we do nothing else, we need to both send and receive 8x the block+blob amount under time pressure, which is a lot to ask.
Core to the problem is that the block processing can be done independently of the blob - the situation is similar to how the execution processing can be done independently of the consensus processing.
Practically, it means that we can process the block, start gossiping it then process the blob, parallelizing utilization of both block and blob.
10mbit does not mean that the connection is limited to 10mbit: it means that with other things going on (such as sending the data to 8 peers), on the same connection (attestation traffic, transactions etc etc), 10mbit is a good conservative target.
4 main advantages:
the last points in terms of optimization opportunities we discussed with @proto are amplified if instead of sending all blobs in a single sidecar, each blob is sent individually - this gives a "natural" way to grow the number of blobs / block, because we simply send on more topics and, this is the significant point, don't add to the serial "load" - they only add parallel load
The architectural complexity resides in two places:
We already have "similar" code in place: blocks are partially validated and gossiped "optmistically", attestations are "batched" for efficient signature verification meaning we have "delayed sending" and "overflow protection" in place, and have a one-way dependency on the block, etc - this adds very little "new" complexity to any current CL implementation
A block without blob is semantically similar to a block without VALID
execution payload.
Past design notes: https://notes.ethereum.org/RLOGb1hYQ0aWt3hcVgzhgQ?
BlobSidecarsByRoot
class BlobSidecar(Container):
beacon_block_root: Root
beacon_block_slot: Slot
proposer_index: ValidatorIndex
blob_index: uint64 # We need the index of the blob, otherwise we cannot do the gossip protections
block_parent_root: Root
## For verifying the fork of the proposer_index
## TODO: dependent_root? Less information but also less sensitive to reorgs
blob: Blob
kzg_commitment: KZGCommitment
kzg_proof: KZGProof # Allows for quick verification of kzg_commitment
## TODO: aggregation receiver-side?
## TODO: consider aggregate proof in first sidecar
class SignedBlobSidecar(Container):
message: BlobSidecar
signature: Signature
remove global sidecar topic
Clients are expected to form a mesh for all sidecar topics, in addition to the regular beacon_block
topic
Topics follow the same specification as in prior upgrades.
The new topics along with the type of the data
field of a gossipsub message are given in this table:
Name | Message Type |
---|---|
blobs_sidecar_# |
SignedBlobSidecar (new) |
#
denotes the index of the sidecar in the corresponding block
blobs_sidecar
This topic is used to propagate blobs sidecars to all nodes on the networks.
The following validations MUST pass before forwarding the signed_sidecar
on the network.
Alias sidecar = signed_sidecar.message
.
sidecar.beacon_block_slot
is for the MAXIMUM_GOSSIP_CLOCK_DISPARITY
allowance)sidecar.beacon_block_slot == block.slot
.sidecar.proposer_index
matches the expected proposer based on sidecar.block_parent_root
(sidecar.beacon_block_slot, sidecar.proposer_index, sidecar.blob_index)
has never been seenblob_index
matches topic (TODO phrase same as attestation)validate_blobs_sidecar(block.slot, hash_tree_root(block), block.body.blob_kzg_commitments, sidecar)
Protocol ID: /eth2/beacon_chain/req/blobs_sidecar_by_root/1/
Request Content:
class BlobSidecarRequest(Container):
beacon_block_root: Root
blob_index: uint64
(
List[BlobSidecarRequest, MAX_REQUEST_BLOCKS]
)
Response Content:
(
List[BlobSidecar, MAX_REQUEST_BLOCKS]
)
Requests blobs by block root and blob index (= hash_tree_root(SignedBeaconBlock.beacon_block.message)
).
The response is a list of BlobSidecar
whose length is less than or equal to the number of requests.
It may be less in the case that the responding peer is missing sidecars.
No more than MAX_REQUEST_BLOCKS
may be requested at a time.
BeaconBlockAndBlobSidecarByRoot
is primarily used to recover recent sidecars (e.g. when receiving a sidecar that did not arrive on the sidecar gossip topic).
The response MUST consist of zero or more response_chunk
.
Each successful response_chunk
MUST contain a single BlobSidecar
payload.
Clients MUST support requesting blocks and sidecars since minimum_request_epoch
, where minimum_request_epoch = max(finalized_epoch, current_epoch - MIN_EPOCHS_FOR_BLOBS_SIDECARS_REQUESTS, EIP4844_FORK_EPOCH)
. If any root in the request content references a block earlier than minimum_request_epoch
, peers SHOULD respond with error code 3: ResourceUnavailable
.
Clients MUST respond with at least one block and sidecar, if they have it.
Clients MAY limit the number of blocks and sidecars in the response.
Protocol ID: /eth2/beacon_chain/req/blobs_sidecars_by_range/1/
Request Content:
(
start_slot: Slot
count: uint64
)
Response Content:
class BlobSidecars(Container):
sidecars: List[BlobSidecar, MAX_BLOBS_PER_BLOCK] # TODO verify constant name
(
List[BlobSidecars, MAX_REQUEST_BLOBS_SIDECARS]
)