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

fix: create intermediate nodes when needed #60

Closed

Conversation

fgimenez
Copy link
Contributor

Towards: paradigmxyz/reth#12129

  • Fixed intermediate node creation: create nodes with the appropriate tree mask and state mask when the current path is more than 1 nibble longer than the current prefix. As the tests here showed test(trie-db): add checks for tree mask invariant paradigmxyz/reth#12080, we had issues with a path like 0b060502, the node at 0b has tree mask 0000000001000000 (expects child at position 6), there is no node at 0b06 but there is a node at 0b0605. These changes fix the creation of the missing intermediate node.
  • Added unit tests for new functionality, specifically for intermediate node creation with different setups and verification of tree mask is a subset of state mask
  • Added unit test to cover bug(trie): invalid trie masks paradigmxyz/reth#12129 with data from the case described above.

@fgimenez fgimenez force-pushed the fgimenez/fix-intermediate-node-creation branch from f3fb619 to cc94266 Compare October 28, 2024 18:09
Comment on lines +204 to +207
// guard against accessing beyond the current key length
if common_prefix_len >= current.len() {
return;
}
Copy link
Member

Choose a reason for hiding this comment

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

common_prefix_len > current.len() is just not possible here due to common_prefix_length call. that leaves us with common_prefix_len == current.len(), why the change of behavior to return early

Comment on lines +209 to +214
// calculate len ensuring we don't exceed current key boundaries
let len = if current.is_empty() {
0
} else {
cmp::min(cmp::max(preceding_len, common_prefix_len), current.len() - 1)
};
Copy link
Member

Choose a reason for hiding this comment

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

same, what's the behavior being fixed here?

Comment on lines +244 to +273
// handle intermediate nodes if needed, when current path is more
// than 1 nibble longer than common prefix
let needs_update = len + 1 < current.len() - 1;
if needs_update {
for intermediate_len in (len + 1)..current.len() {
let intermediate_path = current.slice(..intermediate_len);

if self
.updated_branch_nodes
.as_ref()
.map_or(true, |nodes| !nodes.contains_key(&intermediate_path))
{
let next_nibble = current[intermediate_len];
let state_mask = TrieMask::from_nibble(next_nibble);
let tree_mask =
if self.stored_in_database { state_mask } else { TrieMask::default() };

let node = BranchNodeCompact::new(
state_mask,
tree_mask,
TrieMask::default(),
Vec::new(),
None,
);

if let Some(ref mut nodes) = self.updated_branch_nodes {
nodes.insert(intermediate_path, node);
}
}
}
Copy link
Member

Choose a reason for hiding this comment

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

what's this for?

Comment on lines +418 to +419
// only set tree mask bits for positions that exist in state mask
my_state_mask & self.tree_masks[len]
Copy link
Member

Choose a reason for hiding this comment

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

self.tree_masks[len] must always be a subset of self.groups[len]. it's currently validated below, why is this needed?

trie/src/nodes/branch.rs

Lines 285 to 298 in cf984af

/// Creates a new [BranchNodeCompact] from the given parameters.
pub fn new(
state_mask: impl Into<TrieMask>,
tree_mask: impl Into<TrieMask>,
hash_mask: impl Into<TrieMask>,
hashes: Vec<B256>,
root_hash: Option<B256>,
) -> Self {
let (state_mask, tree_mask, hash_mask) =
(state_mask.into(), tree_mask.into(), hash_mask.into());
assert!(
tree_mask.is_subset_of(state_mask),
"state mask: {state_mask:?} tree mask: {tree_mask:?}"
);

@rkrasiuk
Copy link
Member

this PR introduces branch node retention that violates MPT structure

@rkrasiuk rkrasiuk closed this Oct 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants