fix: clear stale leaves and inner nodes in set_subtree#840
fix: clear stale leaves and inner nodes in set_subtree#840sashass1315 wants to merge 2 commits into0xMiden:nextfrom
set_subtree#840Conversation
| // Leaves 4 and 5 should be removed, leaves 0, 1, 7 should remain | ||
| assert_eq!(tree.num_leaves(), 3); | ||
| assert_eq!(tree.get_leaf(&LeafIndex::<3>::new(0).unwrap()), a); | ||
| assert_eq!(tree.get_leaf(&LeafIndex::<3>::new(1).unwrap()), b); |
There was a problem hiding this comment.
The new tests cover empty subtree insertion well, but don't verify behavior when inserting a non-empty subtree over existing data. This is the main scenario the stale data fix targets. Could we add a test that inserts a non-empty subtree at depth > 1 into a populated tree and verifies the root matches a fresh build?
| let node_value_offset = subtree_insertion_index * num_nodes_at_depth; | ||
|
|
||
| for node_value in node_value_offset..(node_value_offset + num_nodes_at_depth) { | ||
| if let Ok(node_index) = NodeIndex::new(node_depth, node_value) { |
There was a problem hiding this comment.
The if let Ok(node_index) = NodeIndex::new(node_depth, node_value) pattern here silently skips any indices that fail validation. Is this hiding an error condition?
Looking at the loop logic:
node_depthranges fromsubtree_root_insertion_depth + 1toDEPTHnum_nodes_at_depth = 2^depth_offsetwheredepth_offset = node_depth - subtree_root_insertion_depthnode_valueranges fromnode_value_offsettonode_value_offset + num_nodes_at_depth - 1
For a valid NodeIndex, position must be less than 2^depth. Here that means node_value < 2^(subtree_root_insertion_depth + depth_offset) which equals subtree_insertion_index * 2^depth_offset + 2^depth_offset = (subtree_insertion_index + 1) * num_nodes_at_depth.
Since subtree_insertion_index is validated at line 307 to be < 2^subtree_root_insertion_depth, the math should always work out. So if NodeIndex::new returns an error, it would indicate a bug in the calculation logic that should probably not be silently ignored.
Would it make sense to use expect() here instead, similar to line 357? Or is there a case where this can legitimately fail?
| NodeIndex::new(subtree_root_insertion_depth, subtree_insertion_index)?; | ||
|
|
||
| // add leaves | ||
| // remove existing leaves and inner nodes in the insertion region |
There was a problem hiding this comment.
The CI changelog check is failing. Could you add an entry for this PR under the ## 0.23.0 (TBD) section in CHANGELOG.md? Suggested entry:
- Fixed
SimpleSmt::set_subtreeto clear stale leaves and inner nodes in the insertion region.
What was wrong?
set_subtree()crypto/miden-crypto/src/merkle/smt/simple/mod.rs
Line 292 in bbf7493
leaves.is_empty() == (root == EMPTY_ROOT)crypto/miden-crypto/src/merkle/smt/simple/mod.rs
Lines 186 to 190 in bbf7493
num_leaves()crypto/miden-crypto/src/merkle/smt/simple/mod.rs
Lines 144 to 147 in bbf7493
is_empty()crypto/miden-crypto/src/merkle/smt/simple/mod.rs
Lines 186 to 190 in bbf7493
What changed?
Added cleanup logic to
set_subtree()that removes all leaves and inner nodes within the insertion region before adding the new subtree's data. Also added tests to verify the fix.