This proposal introduces a mechanism to decouple state root computation from block validation by deferring the execution layer's state root reference by one block. Each block's ExecutionPayload
contains the post-state root of the previous block rather than its own, enabling validators to attest to a block's validity without waiting for state root computation.
The primary advantage of this proposal is asynchronous state root computation. In the current Ethereum protocol, blocks must compute and include their own post-state root before validators can attest to them. This requirement creates a bottleneck for block production, as the expensive state root computation must complete within critical path.
By deferring the state root reference by one block, validators can attest to blocks based on transaction execution alone, without waiting for the state root calculation. This allows state root computation to be pipelined during idle slot time, potentially enabling higher block gas limits and accelerating the timeline for real-time zero-knowledge proving of Ethereum blocks.
The block header structure is modified to support delayed state root computation:
@dataclass
class Header:
# Existing fields
parent_hash: Hash32
ommers_hash: Hash32
coinbase: Address
# Delayed state root - references the post-state of block (n-1)
state_root: Root # Now points to parent block's post-state
# Existing fields
transactions_root: Root
receipt_root: Root
bloom: Bloom
difficulty: Uint
number: Uint
gas_limit: Uint
gas_used: Uint
timestamp: U256
extra_data: Bytes
prev_randao: Bytes32
nonce: Bytes8
base_fee_per_gas: Uint
withdrawals_root: Root
blob_gas_used: U64
excess_blob_gas: U64
parent_beacon_block_root: Root
The key change is:
state_root
: Now represents the post-state root of block n-1
instead of block n
A block header MUST include the delayed state_root
to be considered valid under this EIP. The state_root
MUST match the post-state root after applying the parent block's execution.
The blockchain object is extended to track the last computed state root:
@dataclass
class BlockChain:
blocks: List[Block]
state: State
chain_id: U64
last_computed_state_root: Root # Post-state root from the last executed block
This additional field is used to verify the delayed state root claimed in subsequent blocks. The last_computed_state_root
acts as a critical chain state reference that MUST be updated after each block execution to ensure proper state progression.
Header validation is modified to verify the delayed state root:
def validate_header(chain: BlockChain, header: Header) -> None:
if header.number < Uint(1):
raise InvalidBlock
parent_header = chain.blocks[-1].header
# Validate delayed state root matches the last computed state root
if header.state_root != chain.last_computed_state_root:
raise InvalidBlock
excess_blob_gas = calculate_excess_blob_gas(parent_header)
if header.excess_blob_gas != excess_blob_gas:
raise InvalidBlock
if header.gas_used > header.gas_limit:
raise InvalidBlock
...
The state transition function applies a block to the chain with delayed state root computation:
def state_transition(chain: BlockChain, block: Block) -> None:
validate_header(chain, block.header)
block_output = apply_body(
block_env=create_block_env(chain, block),
transactions=block.transactions,
withdrawals=block.withdrawals,
)
# Compute and store the state root for the current block
# This will be included in the next block as its state_root
chain.last_computed_state_root = compute_state_root(chain.state)
chain.blocks.append(block)
if len(chain.blocks) > 255:
chain.blocks = chain.blocks[-255:]
During block processing:
Upon activation at block F
:
def apply_fork_transition(chain: BlockChain) -> None:
"""
Initialize the chain for delayed state roots at fork activation.
"""
# At fork activation, initialize last_computed_state_root
# to the current state root (post-state of block F-1)
chain.last_computed_state_root = compute_state_root(chain.state)
The activation block F
MUST contain the post-state root of its parent block F-1
. This is achieved by initializing chain.last_computed_state_root
to the current state root before processing block F
. From block F+1
onwards, the normal delayed root scheme applies where each block contains the post-state of its parent.
The separation of state root computation from block validation removes the primary latency bottleneck in block production and validation. Proposers and builders no longer need to compute the state root within the same slot, enabling faster block building and validation.
This latency reduction is particularly important in the context of Proposer-Builder-Separation, where builders compete on construction speed. By removing state root computation from the critical path, builders can allocate more time to transaction ordering optimization.
The time currently spent on same-slot state root computation can be repurposed for:
Merkle root computation is particularly expensive for ZK proving systems due to the non-ZK-friendly nature of the Keccak hash function. Without delayed state roots, real-time SNARK proofs would require:
With delayed state roots, ZK proofs can be generated during the ~12 second window between blocks, making real-time proving feasible with current technology. This change is likely necessary for Ethereum's transition to ZK-based verification.
This EIP requires a hard fork and is not backwards compatible. Clients that do not implement this change will reject blocks with delayed state roots as invalid.
Light clients must adapt to the one-slot delay in state root availability:
n
become available only after block n+1
is producedDuring chain reorganizations:
Copyright and related rights waived via CC0.