-
Notifications
You must be signed in to change notification settings - Fork 1.2k
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
feat(rpc): debug_executionWitness
#9249
Conversation
4189012
to
2c93be0
Compare
b0dbd43
to
d9f1ca1
Compare
.with_database(StateProviderDatabase::new(state)) | ||
.with_bundle_update() | ||
.build(); | ||
|
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.
reminder to self: Need 4788 call here
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.
wondering if we can eventually use the block executor traits here, as there will be more system contract calls and maintaining a copy of block execution logic in debug APIs seems brittle
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.
Agree. I also specifically need this for Optimism execution, so that would be ideal. Glad to circle back around to this before we merge, just have to get it working first.
38b2229
to
2027c7a
Compare
2027c7a
to
6184498
Compare
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.
This should prob be part of the Evm Executor as a execute_witnessed()
style operation? and then the RPC method calls that?
crates/rpc/rpc/src/debug.rs
Outdated
let account_proofs = db | ||
.cache |
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.
should be access list inspector instead
6184498
to
6c40fe6
Compare
6c40fe6
to
81526f9
Compare
81526f9
to
26e133c
Compare
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.
suggestions and nits
.with_database(StateProviderDatabase::new(state)) | ||
.with_bundle_update() | ||
.build(); | ||
|
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.
still need to call 4788 etc here right?
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.
good catch
47398b0
to
ccbfa3a
Compare
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.
lgtm
.with_bundle_update() | ||
.build(); | ||
|
||
pre_block_beacon_root_contract_call( |
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.
one more thing, this doesn't check if the target block is post merge
do we need to call any other systemcalls or just 4788?
Overview
Adds a new endpoint to the
debug
namespace for generating historical execution witnesses.Rationale
For ZK and Optimistic proving systems, generating execution witnesses for stateless execution can be tough. Before peter's recent cross-client validation proposal, there were fairly limited proposals for this feature pre-verkle. All existing options involve expensive-to-run nodes with large storage requirements, i.e.
gcmode=archive
+state.scheme=hash
geth.Hash scheme geth does the trick, but in an abusive way towards their
debug_dbGet
endpoint, which just-so-happens to key all RLP-encoded trie nodes by their hash (H(rlp(trie_node))
->rlp(trie_node)
).How does it work?
CacheDB
.AccountProof
is generated, utilizing theHistoricalStateProvider::proof
method.H(rlp(trie_node))
->rlp(trie_node)
.DoS concerns
Due to reth's database format only storing merkle diffs, this process can become very expensive for the same reason that state root generation in historical execution within reth can be very expensive. Each diff is layered, which means the further back we reach, the more expensive the operation becomes (approaching upper bound, potentially unable to even fit in memory due to the sheer volume of layers.)
Because of this, this endpoint has been placed in the
debug_*
namespace, which is not often exposed to the open internet by node operators. Exposing this endpoint can pose major DoS concerns for node operators as it stands.Future historical
eth_getProof
supportHistorical
eth_getProof
support was already possible inreth
before this PR, but was never implemented due to the above DoS concerns (per @rkrasiuk). This PR does not remove the requirement for being at tip to useeth_getProof
, but this could be supported in a future PR, by adding a sane default for allowedeth_getProof
depth, configurable via the CLI. A max chain depth foreth_getProof
would effectively cap the number of in-memory layers that must be applied to the trie.TODO
In order to complete this feature, we'll need to be able to also include branch sibling nodes that must be referenced in order to delete leaves in the MPT. This endpoint currently gives the entirety of the witness data required for execution, but not to re-produce the block header for the processed block. The crux of this is that we cannot know which nodes we need to reveal until we're performing the deletion, meaning we also have to compute the state root in this endpoint and collect them, as these nodes are not included within the account proofs we already generate.
To outline the problem, let's say we start with this small trie, where the root node is a branch containing 2 children (both leaf nodes):
If we want to delete the node in the
3
bucket, the branch node would be left with only one child - this is an invalid state. To complete the deletion, we must revealA
(which is hashed), and collapse the branch node intoA
.In order of operation:
3
withrlp(empty) = 0x80
H(node_at(A))
, and prepend the branch nibble (A
) to its path.