Skip to main content
netspecsEthereum networking

4.4.6.Payload chunking

Stage
Future
Validity
Future proposal; not yet reconstructed.
Sources
1 pinned source
Content
Pending reconstruction — no completeness claim is made.

Draft EIP-8101 proposes a breaking change to block propagation and Engine API validation. It splits an execution payload into transaction-aligned chunks and publishes each chunk's access list on a separate stream. Chunks exist for transfer and validation. The canonical execution chain still stores complete payloads.

The proposal has no target fork in the pinned sources. Current nodes do not use these topics, objects, or Engine API methods.

Commitments and objects

The beacon block carries an ExecutionPayloadHeader in place of the full payload. The header adds chunk_count. The block body also commits to:

chunk_headers_root: Root
chunk_access_lists_root: Root

chunk_headers_root is the SSZ root of the ordered execution chunk headers. chunk_access_lists_root is the SSZ root of the hashes of the RLP-encoded chunk access lists.

ExecutionChunkHeader:
  index: uint8
  chunk_access_list_hash: Root
  pre_chunk_tx_count: uint32
  pre_chunk_gas_used: uint64
  pre_chunk_blob_gas_used: uint64
  txs_root: Root
  gas_used: uint64
  blob_gas_used: uint64
  withdrawals_root: Root

ExecutionChunk contains one header, up to 65,536 transactions, and a withdrawal list. Only the last chunk may contain withdrawals.

A chunk access list uses the EIP-7928 block-access-list encoding, but limits the account, storage, balance, nonce, and code changes to one chunk. Chunk zero includes pre-execution system writes. The last chunk includes post-execution system operations.

The execution header commits to an access list with keccak256(RLP(chunk_access_list)). The consensus body uses an SSZ hash of the same RLP bytes for its Merkle proof. An implementation must check both commitments in their proper domain.

Bounds and construction rules

Item Draft value
CHUNK_GAS_LIMIT 2**24, or 16,777,216 gas
MAX_CHUNKS_PER_BLOCK 2**8, or 256
MAX_TRANSACTIONS_PER_CHUNK 2**16, or 65,536
CHUNK_INCLUSION_PROOF_DEPTH 13
MAX_CAL_SIZE 2**24 bytes, or 16 MiB

A producer assigns whole transactions to chunks. It does not split a transaction. Each chunk uses no more than CHUNK_GAS_LIMIT. The chunks use sequential indexes 0..N-1, and the block has no more than 256 chunks.

The layout must be minimal: the sum of the gas used by two adjacent chunks must exceed CHUNK_GAS_LIMIT. This rule prevents a producer from making many small chunks that it could have combined. Only the final chunk carries withdrawals.

Gossip objects

The execution_chunk topic carries:

ExecutionChunkMessage:
  chunk: ExecutionChunk
  inclusion_proof: Vector[Root, 13]
  signed_block_header: SignedBeaconBlockHeader

The chunk_access_list topic carries:

ChunkAccessListMessage:
  chunk_index: uint8
  chunk_access_list: ByteList[16 MiB]
  inclusion_proof: Vector[Root, 13]
  signed_block_header: SignedBeaconBlockHeader

The signed header authenticates the proposer and supplies the body root for the inclusion proof. A peer can therefore check a message before it has the full beacon block.

For a chunk, the receiver checks the proposer signature, index bound, gas bound, transaction root, and Merkle branch from the chunk header to body_root. For an access list, it checks the proposer signature, index, 16 MiB size bound, and Merkle branch from the access-list hash to body_root.

All consensus nodes would subscribe to both topics. The draft does not define Req/Resp recovery methods, topic sharding, retention, or peer-scoring parameters.

Three-phase validation

Access-list reception

After it validates an access-list message and obtains the matching beacon block, the consensus client sends the RLP bytes and chunk index to the execution client. The execution client caches them by execution block hash.

Chunk execution

Chunk N can execute only after access lists 0..N are present. The execution client starts from the parent state, applies the state changes from lists 0..N-1, checks the hash of list N against the chunk header, and executes the chunk's transactions against that reconstructed pre-state.

An implementation records the chunk header and result by beacon block root. It may execute independent chunks in parallel after their prerequisites arrive.

Block finalization

The block becomes execution-valid only after all indexes 0..chunk_count-1 are present and valid. Finalization checks:

  • no chunk index is missing;
  • each chunk execution succeeded;
  • the pre_chunk_* values form one continuous transaction, gas, and blob-gas sequence;
  • the final state root equals the payload header's state root; and
  • all remaining execution header fields are valid.

A validator does not attest until all chunks have passed and block finalization succeeds. Under the draft ePBS link, payload-timeliness votes only report receipt of the data. They do not prove execution validity.

Engine API sequence

The four proposed methods form one ordered transaction.

engine_newBlockHeaderV1(payloadHeader, beaconRoot, blobHashes, executionRequests) registers the block and replaces engine_newPayloadV5 for a chunked block. The consensus client calls it first.

engine_newChunkAccessListV1(blockHash, chunkIndex, chunkAccessList) validates and caches one RLP-encoded list.

engine_executeChunkV1(blockHash, chunk) checks and executes one chunk after all lists through that chunk index are present.

engine_finalizeBlockV1(blockHash) checks the complete chunk sequence and the resulting block state.

All four return PayloadStatusV1, but the allowed status depends on the method:

Status Meaning
ACCEPTED Header or access list accepted
VALID Chunk execution or block finalization succeeded
INSUFFICIENT_INFORMATION A chunk lacks a required access list
INVALID Input, execution, or final validation failed
SYNCING The parent state is not available

INSUFFICIENT_INFORMATION applies only to chunk execution. ACCEPTED applies only to header and access-list input. INVALID and SYNCING can apply to all four methods.

Failure and transition rules

The first invalid chunk or list makes the draft block invalid. A missing chunk prevents finalization. A missing access list prevents its chunk and all later dependent chunks from executing. A node can reconstruct a withheld access list by running the preceding execution in order, but the draft's streaming path then loses its latency benefit.

Activation would require one coordinated hard fork. New beacon body commitments, consensus gossip, payload construction, and all four Engine API methods must change together. Historical blocks keep their old form.

The pinned draft still leaves interoperability gaps:

  • it defines no target fork or transition configuration;
  • chunk_count is a uint8 while the stated maximum is 256, so the maximum count has no direct encoding;
  • it gives no recovery protocol, serving window, subnet plan, or detailed peer-scoring rules for chunks and access lists;
  • it does not give complete JSON-RPC wire schemas for the Engine API parameters and errors;
  • it does not resolve how data withholding maps to ePBS timeliness and fork choice; and
  • its security section says missing access lists permit a sequential fallback, while its three-phase flow requires each list before execution. A later revision must state the required fallback behavior.

These gaps make the page a description of a draft, not an active network contract.