chore(trie): fully reveal sparse tries prior to leaf updates/removals#17643
Merged
mediocregopher merged 37 commits intomainfrom Aug 22, 2025
Merged
chore(trie): fully reveal sparse tries prior to leaf updates/removals#17643mediocregopher merged 37 commits intomainfrom
mediocregopher merged 37 commits intomainfrom
Conversation
Fixes #17571 **Background** The Serial/ParallelSparseTrie's have their nodes revealed using the DecodedMultiProofs generated based on the previous database state and the changed leafset. Once revealed, the leaf updates/removals are applied to the sparse tries and root hashes are calculated. There are specific edge-cases during leaf adding/removal where a node which is outside the changeset is required to complete the operation. In these cases we were falling back to a singular database lookup to fill in the gap. By modifying the generation of the DecodedMultiProofs to include those extra required nodes we can simplify the sparse trie implementations significantly, as well as the surrounding engine code which supports these one-off lookups. **Changes** This primarily relies on a change to the ProofRetainer in alloy-trie, made here: alloy-rs/trie#109 These changes are enabled by a flag which the payload validator enables; other places where proofs are generated remain unnaffected. There is a further change here to the trie walker to not skip over branch nodes when they might be involved in a leaf removal. A change to support leaf addition is not required, because that case involves children of extension nodes, and we don't ever skip over extension nodes anyway. The sparse trie code to fallback to the db for missing nodes remains in place for now, but we emit a warning when it happens. This will let us track if there's any edge-cases we're missing. **Benchmarks - 2k blocks on main** No significant change ``` Timestamp: 2025-07-28 10:37:12 UTC Baseline: main Feature: origin/mediocregopher/17571-leaf-updates-removals Performance Changes: NewPayload Latency: -1.24% FCU Latency: -1.74% Total Latency: -1.26% Gas/Second: +1.27% Blocks/Second: +1.27% Baseline Summary: Blocks: 2000, Gas: 36118922440, Duration: 74.02s Avg NewPayload: 35.69ms, Avg FCU: 1.29ms, Avg Total: 36.99ms Started: 2025-07-28 10:48:20 UTC, Ended: 2025-07-28 10:56:39 UTC Feature Summary: Blocks: 2000, Gas: 36118922440, Duration: 73.08s Avg NewPayload: 35.25ms, Avg FCU: 1.27ms, Avg Total: 36.52ms Started: 2025-07-28 10:58:35 UTC, Ended: 2025-07-28 11:06:55 UTC ```
Member
Assuming there are no warnings from the benches? Are there any changes in the metrics (nodes fetched for ex) |
Member
Author
…1-leaf-updates-removals-debug
…1-leaf-updates-removals
mattsse
reviewed
Aug 21, 2025
| /// Generates storage merkle proofs. | ||
| #[derive(Debug)] | ||
| pub struct StorageProof<T, H> { | ||
| pub struct StorageProof<T, H, K = AddedRemovedKeys> { |
Collaborator
There was a problem hiding this comment.
ah I see, this way this works for both, proofretainer and addedremovedkeys
makes sense
Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
Member
|
needs docs fixes |
mediocregopher
added a commit
that referenced
this pull request
Aug 22, 2025
In #17643 we introduced tracking of removed keys within a block in order to fully reveal sparse tries prior to updating/removing leafs. This lets us never have to block root calculation to reveal blinded nodes in the sparse tries. This was implemented by assuming that all keys are added (as opposed to being only modified), which results in over-revealing the sparse tries with all extension node children. This isn't logically incorrect, but is a bit wasteful. This change implements proper tracking of added keys alongside tracking of removed keys. When a key is added we always generate its proof in `on_state_update`, just like key removal. Because we can now enforce that added keys have their proofs generated in `on_state_update` we no longer need to optimistically retain extra proofs in prewarms.
mediocregopher
added a commit
that referenced
this pull request
Aug 25, 2025
In #17643 we introduced tracking of removed keys within a block in order to fully reveal sparse tries prior to updating/removing leafs. This lets us never have to block root calculation to reveal blinded nodes in the sparse tries. This was implemented by assuming that all keys are added (as opposed to being only modified), which results in over-revealing the sparse tries with all extension node children. This isn't logically incorrect, but is a bit wasteful. This change implements proper tracking of added keys alongside tracking of removed keys. When a key is added we always generate its proof in `on_state_update`, just like key removal. Because we can now enforce that added keys have their proofs generated in `on_state_update` we no longer need to optimistically retain extra proofs in prewarms.
lwedge99
pushed a commit
to sentioxyz/reth
that referenced
this pull request
Sep 16, 2025
…paradigmxyz#17643) Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Fixes #17571
Background
The Serial/ParallelSparseTrie's have their nodes revealed using the DecodedMultiProofs generated based on the previous database state and the changed leafset. Once revealed, the leaf updates/removals are applied to the sparse tries and root hashes are calculated.
There are specific edge-cases during leaf adding/removal where a node which is outside the changeset is required to complete the operation. In these cases we were falling back to a singular database lookup to fill in the gap.
By modifying the generation of the DecodedMultiProofs to include those extra required nodes we can simplify the sparse trie implementations significantly, as well as the surrounding engine code which supports these one-off lookups.
Changes
This primarily relies on a change to the ProofRetainer in alloy-trie, made here:
alloy-rs/trie#109
These changes are enabled by a flag which the payload validator enables; other places where proofs are generated remain unnaffected.
There is a further change here to the trie walker to not skip over branch nodes when they might be involved in a leaf removal. A change to support leaf addition is not required, because that case involves children of extension nodes, and we don't ever skip over extension nodes anyway.
The sparse trie code to fallback to the db for missing nodes remains in place for now, but we emit a warning when it happens. This will let us track if there's any edge-cases we're missing.
Benchmarks - 2k blocks on main
No significant change