Skip to content

Conversation

@mediocregopher
Copy link
Collaborator

@mediocregopher mediocregopher commented Nov 24, 2025

Closes #19512

This PR gives the new proof_v2::ProofCalculator the ability to retain the ProofTrieNodes for all nodes in the trie which match the given proof targets. The legacy proof calculator retains proofs by checking each node against all targets, whereas V2 checks each node against only a single target. See the should_retain method for details on how this works.

To support proof retention the idea of "committing" a child is introduced. A child is "committed" to when there can be no further changes to it, such as an extension or a leaf being split to insert a new branch. When a child is committed it is converted to an RlpNode, checked to see if its proof should be retained, and pushed back onto the child stack as a ProofTrieBranchChild::RlpNode. This is done all as one step in order to best reuse buffers during RLP-encoding.

}
Self::Branch(branch_node) => Ok(TrieNode::Branch(branch_node)),
}
// TODO store trie masks on branch
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Will be done as part of #19513

@mediocregopher mediocregopher changed the title Mediocregopher/proof rewrite leaf only feat(trie): Proof V2: retain proof nodes which match targets Nov 24, 2025
Comment on lines +63 to +64
/// ever be modified, and therefore all children besides the last are expected to be
/// [`ProofTrieBranchChild::RlpNode`]s.
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Given this property, it might make more sense to split this into something like:

child_stack: Vec<RlpNode>
uncommitted_child: Option<ProofTrieBranchChild<VE::DeferredEncoder>>

I'm not sure that this would give us any performance gains or anything, but it might make the code more understandable and easier to validate as correct. Would be better done as a follow-up PR though.

Comment on lines -220 to -239
"Stack is missing necessary children"
);
let children = self.child_stack.drain(self.child_stack.len() - num_children..);

// We will be pushing the branch onto the child stack, which will require its parent
// extension's short key (if it has a parent extension). Calculate this short key from the
// `branch_path` prior to modifying the `branch_path`.
let short_key = trim_nibbles_prefix(
&self.branch_path,
self.branch_path.len() - branch.ext_len as usize,
"Stack is missing necessary children ({num_children:?})"
);

// Update the branch_path. If this branch is the only branch then only its extension needs
// to be trimmed, otherwise we also need to remove its nibble from its parent.
let new_path_len = self.branch_path.len() -
branch.ext_len as usize -
if self.branch_stack.is_empty() { 0 } else { 1 };

debug_assert!(self.branch_path.len() >= new_path_len);
self.branch_path = self.branch_path.slice_unchecked(0, new_path_len);
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This logic didn't change, it only got re-ordered in the method a bit. We cannot modify the branch_path until after commit_child has potentially been called on the popped branch, in the case that the branch has an extension node parent.

@mediocregopher mediocregopher marked this pull request as ready for review November 24, 2025 17:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Backlog

Development

Successfully merging this pull request may close these issues.

Proof Calc Rewrite: Leaf-only Implementation

2 participants