-
Notifications
You must be signed in to change notification settings - Fork 31
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
fix: create intermediate nodes when needed #60
Conversation
f3fb619
to
cc94266
Compare
// guard against accessing beyond the current key length | ||
if common_prefix_len >= current.len() { | ||
return; | ||
} |
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.
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
// 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) | ||
}; |
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.
same, what's the behavior being fixed here?
// 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); | ||
} | ||
} | ||
} |
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.
what's this for?
// only set tree mask bits for positions that exist in state mask | ||
my_state_mask & self.tree_masks[len] |
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.
self.tree_masks[len]
must always be a subset of self.groups[len]
. it's currently validated below, why is this needed?
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:?}" | |
); |
this PR introduces branch node retention that violates MPT structure |
Towards: paradigmxyz/reth#12129
0b060502
, the node at0b
has tree mask0000000001000000
(expects child at position 6), there is no node at0b06
but there is a node at0b0605
. These changes fix the creation of the missing intermediate node.