-
Notifications
You must be signed in to change notification settings - Fork 5.4k
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
Conversation
✅ All reviewers have approved. |
EIPS/eip-xxxx.md
Outdated
|
||
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`. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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
.
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so we still execute the block before attesting -- only stateroot is not required.
since the effects of EIP 4788 and 2935, withdrawals, block tips coinbase rewards will be only reflected in state root (lets say no txs uses them and hence won't be in reflected in receipts etc) the block execution can't be fully verified (and CL newpayloads VALID can turn into invalid later on causing issues/complications for CL forkchoice)
unless we have a root/commitment to those changes and hence a validator could vote on a bad/buggy block execution.
Ideally we we should have a root of entire statediff/witnesses as block property which will sort of help close out the execution issue (and could be much faster than stateroot compute which would require harddisk accesses which is what this EIP will actually optimize in my opinion)
EIPS/eip-xxxx.md
Outdated
- 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`. |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should be during the idle time of slot n-1
. Slots work like this @charlie-paradigm:
- 0-4s: block propagation
- 4-12s: attestation aggregation
Between 0-4s you'd still get a block, execute it and attest to it, you just wouldn't be required to compute a state root yet. The computation should then be done between 4-12s of the same slot, no? E.g. the proposer/builder of slot n would want to be done with this by the time it needs to propose, which is the beginning of slot n.
Correct me if I am wrong, but I think the confusion is that you are treating slot n as if it begins as soon as the block has been received/attested to? In which case, that's not the case. There's a whole 8s of mostly idle time in slot n-1, and that's where you'd want to be doing this computation
EIPS/eip-xxxx.md
Outdated
bytes32 parentHash; | ||
address feeRecipient; | ||
... | ||
bytes32 stateRoot; // now references the post-state root of block (n-1) |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for purposes of accepting EIP draft just add a <-- TODO benchmark -->
comment
EIPS/eip-xxxx.md
Outdated
# assert compute_state_root(transactions_of_block_n) == payload_n.stateRoot | ||
# | ||
# Now: | ||
assert payload_n.stateRoot == post_state_of_block_n_minus_1 |
There was a problem hiding this comment.
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.)
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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.
# assert compute_state_root(transactions_of_block_n) == payload_n.stateRoot | ||
# | ||
# Now: | ||
assert payload_n.stateRoot == post_state_of_block_n_minus_1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the current block execution validations also validates receipts, execution requests root, header has logbloom etc so many other fields which are the result of block execution and get validated so I am assuming that those validations stay in?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did not realize this until this comment, because I first assumed that this could mean that tx execution could happen after publishing the block. But this is not possible, since we still need receipt roots.
Are there any numbers how much the time is of calculating the state root? This is a simplification, but I would assume that most clients would execute txs and write state changes to a cache. Only at the end of running the txs this cache is flushed to disk in order to calculate the new state root. I would honestly have no idea what the ratio is between executing the transactions and flushing the new cache to disk / calculating the root and would love to see some numbers on this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yea agree with @jochem-brouwer we should see what is the benchmark delay for batched state root calculation
Eip-7862: Fix linter issues
The commit adc3c35 (as a parent of 8e28b3e) contains errors. |
Fix linter issues
|
||
## Motivation | ||
|
||
Currently, every Ethereum block includes two `state_root`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the wording of this statement incorrect, EL blocks have only one state root, and this is the state root of Ethereum's "world state" (MPT of accounts)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the EIP is talking about the full block as it references ExecutionPayload
|
||
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd love to see some numbers here, what is this large fraction? If splitting the time between receiving a block, executing the txs, and calculating the root, what would these numbers be?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
for purposes of draft EIP can we add a <-- TODO benchmark --> here?
|
||
3. **Reliant Contracts** | ||
|
||
- We are not aware of any common contract types that assume the availability of same-block state roots. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Contracts cannot read a block state root, so I'm not sure if this is relevant?
|
||
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`. | ||
|
||
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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
how can it accelerate real-time ZK proving?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We get more of the slot time to calculate it async, rather than a proof needing to be made after block building is complete (probably in <100ms)
@charlie-paradigm for purposes of merging this as a draft, I have added a few editing comments and corrections (ignore my other comments regarding the EIP working details) If you can address those editing comments we can merge this EIP draft |
Co-authored-by: g11tech <[email protected]>
Co-authored-by: g11tech <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All Reviewers Have Approved; Performing Automatic Merge...
This EIP implements a delayed state root. It is ready for draft status and discussion.