This EIP proposes that, for each block n
, the state_root
in block n
's ExecutionPayload
references the post-state of block n-1
. As a result, block n
no longer needs to compute & include or verify the post state root for block n
. This removes the expensive state root computation from the block-propagation critical path, reducing end-to-end latency for block production and potentially increasing throughput.
Currently, every Ethereum block includes two state_root
.
The consensus layer (CL) state_root
contained within the BeaconBlock
tracks CL state (e.g., validator entries and exits).
The execution layer (EL) state_root
contained within the ExecutionPayload
tracks the effect of transaction execution (e.g., account balances, code, etc.).
The EL state_root
must be computed by block builders (and verified by relays, validators, and light clients) in near-real-time. This computation accounts for a large fraction of block production and verification time, especially in an MEV-Boost environment. This overhead is also a challenge for efforts to enable real-time ZK proving of the chain.
By delaying the EL state_root
reference by one block, we can remove EL state_root
calculation overhead from the critical path of block production. Instead, clients can pipeline calculation of block n-1
's EL state_root
during the idle slot time before block n
.
This change will lower latency at the tip, allowing us to increase throughput and simplify the block production pipeline. It can also significantly accelerate the timeline of real-time ZK proving Ethereum.
ExecutionPayload
State Root Field
Before (in the current post-Merge design):
solidity
struct ExecutionPayload {
uint256 blockNumber;
uint256 timestamp;
bytes32 parentHash;
address feeRecipient;
bytes32 stateRoot; // references the post-state root of *this* block's transactions
}
After (conceptual):
solidity
struct ExecutionPayload {
uint256 blockNumber;
uint256 timestamp;
bytes32 parentHash;
address feeRecipient;
bytes32 stateRoot; // now references *this* block's pre-state i.e. the post-state root of block (n-1)
}
In other words, block n
’s ExecutionPayload.stateRoot
must now point to the execution-layer post-state of block n-1
, rather than referencing the new state after block n
’s own transactions.
Block Header Validation
Remove the rule requiring each block’s stateRoot
to match the post-state produced by the transactions in that same block:
Instead, require that payload_n.stateRoot == post_state(n-1)
:
python
def validate_execution_payload(payload_n, post_state_of_block_n_minus_1):
# Was:
# assert compute_state_root(transactions_of_block_n) == payload_n.stateRoot
#
# Now:
assert payload_n.stateRoot == post_state_of_block_n_minus_1
The actual new state root resulting from block n
will only appear in block n+1
.
Proactive Computation of Post-state Root:
To fully realize latency benefits, clients should compute the post-state root of block n-1
during the idle time of slot n
.
n-1
is received and processed, the client can generate (or finalize) its EL post-state root in the “gap” while waiting for block n
to arrive. n
arrives, the node can quickly verify that payload_n.stateRoot
matches the already-known post_state(n-1)
. n
arrives to compute the post-state root for n-1
, but this would negate much of the latency advantage. The client would again have to pause to compute the previous root before finalizing the current block’s verification. No changes are required in the CL validation process or block structure:
Upon the hard fork that activates this proposal (call this activation block F
):
F
will repeat the same EL state_root
as the preceding block F-1
. That is: ExecutionPayload(F).stateRoot = post_state(F-1)
F+1
will reference the post-state of block F
, continuing the new delayed root scheme from that point onward.Reduce Latency at the Tip
Proposers and builders no longer must compute and finalize the new state root within the same slot.
This speeds up block validation, as validators can sign after checking the execution of the block and that its pre-state root matches their pre-computed expectation (i.e., without needing to wait to calculate a new state root).
Increase Throughput
The time currently spent on same-slot state_root
computation can be repurposed.
This time may now be reallocated to increased L1 block capacity (higher gas targets) or quicker slot times with less risk of reorgs.
Simplify Timing for MEV-Boost and Builders
In a proposer-builder separation (PBS) model, block construction speed is an important competitive dimension for builders and relays.
Delaying the state root also helps participants in the block production pipeline. Builders can reallocate the time to building more efficient blocks, and relays do not have to worry about state root delay as a source of timing variance or competition.
Accelerate Real-time ZK Proving
Merkle roots are particularly challenging for ZK proving systems, because Keccak is not a ZK-friendly hash function.
This EIP is a consensus-breaking change and requires a coordinated hard fork on mainnet or any network that adopts it. Once activated, older clients that expect blocks to contain their own (execution layer) post-state root will be incompatible and fail to sync.
Light clients
Must accept that a block’s final state root is not published until the subsequent block, adding up to a slot’s worth of latency (e.g. 12 seconds).
Notably, many other blockchain networks already operate on a delayed state root and it has worked fine. One such network, Cosmos, is a multichain architecture based entirely on light-client interoperability with a delayed state root.
Reliant Contracts
We are not aware of any common contract types that assume the availability of same-block state roots.
Copyright and related rights waived via CC0.