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_countis auint8while 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.