This EIP defines a migration process of execution blocks to Simple Serialize (SSZ).
With EIP-6404 SSZ transactions, EIP-6466 SSZ receipts, and EIP-6465 SSZ withdrawals, all Merkle-Patricia Trie (MPT) besides the state trie are converted to SSZ. This enables the surrounding data structure, the execution block itself, to also convert to SSZ, achieving a unified block representation across both Consensus Layer and Execution Layer.
Normalized block hash: The Consensus Layer can compute the block hash autonomously, enabling it to process all consistency checks that currently require asynchronous communication with the Execution Layer (verify_and_notify_new_payload
). This allows early rejection of inconsistent blocks and dropping the requirement to wait for engine API interactions while syncing.
Optimized engine API: With all exchanged data supporting SSZ, the engine API can be changed from the textual JSON encoding to binary SSZ encoding, reducing exchanged data size by ~50% and significantly improving encoding/parsing efficiency.
Proving support: With SSZ, individual fields of the execution block header become provable without requiring full block headers to be present. With EIP-7495 SSZ ProgressiveContainer
, proofs are forward compatible as long as underlying semantics of individual fields are unchanged, reducing maintenance requirements for smart contracts and verifying client applications.
Cleanup opportunity: The conversion to SSZ allows dropping historical fields from the PoW era and the inefficient logs bloom mechanism.
The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "NOT RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119 and RFC 8174.
The different kinds of gas amounts are combined into a single structure, mirroring the EIP-6404 gas fees.
Name | SSZ equivalent |
---|---|
GasAmount |
uint64 |
class GasAmounts(ProgressiveContainer([active_fields=[1, 1]])):
regular: GasAmount
blob: GasAmount
requests_hash
is changed to ExecutionRequests.hash_tree_root()
using the same structure as in the Consensus Layer BeaconBlockBody
.
New execution block headers use a normalized SSZ representation.
class ExecutionBlockHeader(
ProgressiveContainer[active_fields=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
):
parent_hash: Root
miner: ExecutionAddress
state_root: Bytes32
transactions_root: Root # EIP-6404 transactions.hash_tree_root()
receipts_root: Root # EIP-6466 receipts.hash_tree_root()
number: uint64
gas_limits: GasAmounts
gas_used: GasAmounts
timestamp: uint64
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
mix_hash: Bytes32
base_fees_per_gas: BlobFeesPerGas
withdrawals_root: Root # EIP-6465 withdrawals.hash_tree_root()
excess_gas: GasAmounts
parent_beacon_block_root: Root
requests_hash: Bytes32 # EIP-6110 execution_requests.hash_tree_root()
system_logs_root: Root # EIP-7799 system_logs.hash_tree_root()
For new blocks, the execution block hash is changed to be based on hash_tree_root
in all contexts, including (1) the BLOCKHASH
opcode, (2) JSON-RPC API interactions (blockHash
field), (3) devp2p networking.
ExecutionPayload
changesUsages of ExecutionPayloadHeader
are replaced with ExecutionBlockHeader
.
Usages of ExecutionPayload
are updated to share hash_tree_root
with ExxecutionBlockHeader
. transactions_root
, withdrawals_root
and requests_root
are expanded to their full list contents.
class ExecutionPayload(
ProgressiveContainer[active_fields=[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]]
):
parent_hash: Root
miner: ExecutionAddress
state_root: Bytes32
transactions: ProgressiveList[Transaction]
receipts_root: Root
number: uint64
gas_limits: GasAmounts
gas_used: GasAmounts
timestamp: uint64
extra_data: ByteList[MAX_EXTRA_DATA_BYTES]
mix_hash: Bytes32
base_fees_per_gas: BlobFeesPerGas
withdrawals: ProgressiveList[Withdrawal]
excess_gas: GasAmounts
parent_beacon_block_root: Root
requests: ExecutionRequests
system_logs_root: Root
This transition completes the transition to SSZ for everything except the execution state trie.
Log
, the withdrawals mechanism and validator requests could be redefined to be based on logs (similar to deposits, originally, but without the delay), possibly removing the need for withdrawals_root
and requests_hash
.compute_requests_hash
.For client applications and smart contracts, it would streamline transaction history verification based on EIP-7792.
Engine API should be updated with (1) possible withdrawals/requests refactoring as above, (2) dropping the block_hash
field so that ExecutionPayload
is replaced with to ExecutionBlockHeader
, (3) binary encoding based on ForkDigest
-context (through HTTP header or interleaved, similar to beacon-API). This reduces encoding overhead and also simplifies sharing data structures in combined CL/EL in-process implementations.
This breaks compatibility of smart contracts that depend on the previous block header binary format, including for "generic" implementations that assume a common prefix and run the entire data through a linear keccak256 hash.
The SSZ block hash is based on SHA256 and shares the namespace with existing keccak256 based block hashes. As these hash algorithms are fundamentally different, no significant collision risk is expected.
Copyright and related rights waived via CC0.