Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add EIP: Delayed Execution Layer State Root #9241

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 136 additions & 0 deletions EIPS/eip-xxxx.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
---
eip: XXXX
title: "Delayed Execution Layer State Root"
description: "Delays the ExecutionPayload's state root reference by one block."
author: Charlie Noyes <[email protected]>, Dan Robinson <[email protected]>, Justin Drake <[email protected]>, Toni Wahrstätter <[email protected]>
discussions-to: https://ethereum-magicians.org/t/eip-XXXX/, https://ethresear.ch/t/proposal-delay-stateroot-reference-to-increase-throughput-and-reduce-latency/20490
status: Draft
type: Standards Track
category: Core
created: 2024-12-23
---

## Abstract

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 include or verify the newly computed state root for block `n`’s own transactions. 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.

## Motivation

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 of block `n`.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idle slot time of block n.

I think this is n-1. At n-1, the block arrives around the 4th second of the slot, you verify everything except the state root, and then you have 8 more seconds in n-1 to verify the state root

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think in this design the EL clients are calculating the state root of block n-1 while building block n at the same time, and this process occurs during the last 8 seconds of block n-1. Is this correct?

Copy link
Contributor

@g11tech g11tech Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yea either change it to n-1 or it should read:

Instead, clients can pipeline calculation of block n's EL state_root during the idle slot time of block n.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it might be clearer to specify post-state root, rather than the parameter.

"Instead, clients can pipeline calculation of block n-1's EL post-state root during the idle slot time of block n."

Would you guys be happy with this?

To clarify what happens is that:

When n-1 arrives, it contains the EL pre-state root of n-1.

While waiting for block n to arrive, the client can calculate the post-state root of n-1 (equivalently, pre-state of n).

When block n arrives, it can verify that it contains the correct post-state of n-1 (equivalently, pre-state of n).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so all we are delaying for the attesting/verifying validator is the stateroot calc? how significant is that as percentate of block building time?

we could infact delay the entire execution for the attesting/verifying validator (which means they can execute/verify bigger blocks on the commodity hardware while the specialized builders can build a gas chugging block

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think we can delay attesting unless we do eip7732


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 real-time ZK proving Ethereum.
charlie-paradigm marked this conversation as resolved.
Show resolved Hide resolved

## Specification

### Execution Layer Changes

1. **`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 the post-state root of block (n-1)
charlie-paradigm marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

@g11tech g11tech Jan 15, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i have another Q:

since the block builders will have the stateroot because they can't include a tx before executing a previous one because of previous txs affecting any prestate of the tx, so why should we not include the stateroot in it

since the logs/requests etc are all dependent on the correct execution. Ofcourse the attesters can still do delayed verification.

may we we just add a block pre-stateroot field and use that for running verifications because proofs of correct execution results against this block might require this block's post stateroot and will be easy and fast check for whenever the block gets executed before next block arrives

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

since the block builders will have the stateroot because they can't include a tx before executing a previous one because of previous txs affecting any prestate of the tx, so why should we not include the stateroot in it

They only need the state, not the state root.

Currently they'd need to compute the state root before completing the block building process. Now they don't need to compute it eagerly (they can do it async).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I get that, but having post stateroot in block is a good thing for creating proofs merkle and ZK against the current block header itself.

yes it would matter how hard it is to create a stateroot, my supposition is : its not really that expensive and doesn't add any real latency but then depends on how big the block is, but if its vialble we should include it

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I'm not sure I understand. Do you suggest to include both pre state root and post state root of the current block in its header?

having post stateroot in block is a good thing for creating proofs merkle and ZK against the current block header itself

Do you mean verifying blocks with a zk proof instead of re-executing them? That's not necessarily in conflict with this EIP, nodes can still receive the state root together with the proof (not as part of the header but on some other channel).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes I mean to specify both because the block builder will have the final execution results anyway when its done adding txs to the block.

for the proof, it needs to be anchored in post state root. Although receipts should have the entire execution traced but thats not true of system updates which are purely reflected in stateroot.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok now I understand that this EIP is trying to save post state root compute time even for builder. is that correct?

if so then as I asked in a previous comment how significant this time would be (so benchmarks against some typical blocks with 30m 60m... 100m 1g gas i guess) on a latest commondity hardware (which one would expect least of block builders)

I guess that would bring forward the proper justification of the EIP

...
}
```
- 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.

2. **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

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this mean that if a future protocol upgrade changes EVM behavior, then nodes that did not upgrade would fork off the network with 1 block delay? (Though I don't think this is an issue.)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess that is true only if the protocol change results in a mismatched state but doesn't change the execution flow of the transactions.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, so for instance adding a new tx type could result in a fork exactly at the upgrade block.

But adding a new opcode or precompile, or changing the gas schedule, could result in a fork one block later.

```
- The actual new state root resulting from block `n` will only appear in block `n+1`.

3. **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`.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

during the idle time of slot n.

Same. I think this would be n-1, not n

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think that I agree.

You could say "compute the pre-state root of n during the idle slot time of n"

and that might be clearer?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at this again and think what you have is fine. If we want to be clearer, we could rephrase it as the following:

"As a proposer/builder for n, assuming it receives a block for n-1 during slot n-1, to fill in the state_root field, they should compute the post-state root at n-1 during the idle time of n-1"

I agree with what you said here: #9241 (comment)

- Concretely, once block `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.
- By doing so, when block `n` arrives, the node can quickly verify that `payload_n.stateRoot` matches the already-known `post_state(n-1)`.
- Alternatively, a client could lazily wait until block `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.

### Consensus Layer

No changes are required in the CL validation process or block structure:
- The beacon block continues to wrap each ExecutionPayload as usual.
- The proposal only changes how the EL stateRoot field is populated and validated.
### Transition / Fork Activation

Upon the hard fork that activates this proposal (call this activation block `F`):

- **Block `F`** will **repeat** the same EL `state_root` as the preceding block `F-1`. That is:
```solidity
ExecutionPayload(F).stateRoot = post_state(F-1)
```
- **Block `F+1`** will reference the post-state of block `F`, continuing the new delayed root scheme from that point onward.

## Rationale

1. **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 propagation, as peers can quickly validate the rest of the block without waiting on the state root calculation.
charlie-paradigm marked this conversation as resolved.
Show resolved Hide resolved

2. **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.

3. **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.

4. **Accelerate Real-time ZK Proving**
- Merkle roots are particularly challenging for ZK proving systems, because Keccak is not a ZK-friendly hash function.
- Without a delayed state root, real-time SNARK proofs would share all of the latency issues with the existing real-time state root (but many times worse, as they take longer to calculate).
- Block proposers and builders would need to be able to prove the state root in <1s after deciding on their built blocks. This is not realistically possible.
- The latency would interact with the MEV pipeline in the same way that the current state root calculation latency does.
- With a delayed state root, the calculation of an accompanying ZK proof can also be delayed (pipelined). The network will instead have ~6 seconds to generate the proof, which is much more feasible.
- State root delay is likely a **necessary** change for real-time ZK proving.

## Backwards Compatibility

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.

## Security Considerations

1. **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).
- In practice, many light client protocols already tolerate slight delays in proof availability.
- 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.

2. **Reliant Contracts**
- We are not aware of any common contract types that assume the availability of same-block state roots.



## Copyright Waiver

Copyright and related rights waived via [CC0](../LICENSE.md).
Loading