Skip to content

Commit d3d640d

Browse files
increment_and_strip_trailing_zeros
1 parent e25fdef commit d3d640d

File tree

1 file changed

+47
-3
lines changed
  • crates/trie/trie/src/proof_v2

1 file changed

+47
-3
lines changed

crates/trie/trie/src/proof_v2/mod.rs

Lines changed: 47 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -958,7 +958,7 @@ where
958958
// The just-popped branch is completely processed; we know there can be no more keys
959959
// with that prefix. Set the lower bound which can be returned from this method to
960960
// be the next possible prefix, if any.
961-
uncalculated_lower_bound = cached_path.increment();
961+
uncalculated_lower_bound = increment_and_strip_trailing_zeros(&cached_path);
962962

963963
continue
964964
}
@@ -1009,7 +1009,7 @@ where
10091009

10101010
// Update the `uncalculated_lower_bound` to indicate that the child whose bit
10111011
// was just set is completely processed.
1012-
uncalculated_lower_bound = child_path.increment();
1012+
uncalculated_lower_bound = increment_and_strip_trailing_zeros(&child_path);
10131013

10141014
// Push the current cached branch back onto the stack before looping.
10151015
self.cached_branch_stack.push((cached_path, cached_branch));
@@ -1053,7 +1053,7 @@ where
10531053
// There is no cached data for the sub-trie at this child, we must recalculate the
10541054
// sub-trie root (this child) using the leaves. Return the range of keys based on the
10551055
// child path.
1056-
let child_path_upper = child_path.increment();
1056+
let child_path_upper = increment_and_strip_trailing_zeros(&child_path);
10571057
trace!(
10581058
target: TRACE_TARGET,
10591059
lower=?child_path,
@@ -1352,6 +1352,26 @@ enum PopCachedBranchOutcome {
13521352
CalculateLeaves((Nibbles, Option<Nibbles>)),
13531353
}
13541354

1355+
/// Increments the nibbles and strips any trailing zeros.
1356+
///
1357+
/// This function wraps `Nibbles::increment` and when it returns a value with trailing zeros,
1358+
/// it strips those zeros using bit manipulation on the underlying U256.
1359+
fn increment_and_strip_trailing_zeros(nibbles: &Nibbles) -> Option<Nibbles> {
1360+
let mut result = nibbles.increment()?;
1361+
1362+
// If result is empty, just return it
1363+
if result.is_empty() {
1364+
return Some(result);
1365+
}
1366+
1367+
// Get access to the underlying U256 to detect trailing zeros
1368+
let uint_val = *result.as_mut_uint_unchecked();
1369+
let non_zero_prefix_len = 64 - (uint_val.trailing_zeros() / 4);
1370+
result.truncate(non_zero_prefix_len);
1371+
1372+
Some(result)
1373+
}
1374+
13551375
#[cfg(test)]
13561376
mod tests {
13571377
use super::*;
@@ -1650,4 +1670,28 @@ mod tests {
16501670
// Assert the proof
16511671
harness.assert_proof(targets).expect("Proof generation failed");
16521672
}
1673+
1674+
#[test]
1675+
fn test_increment_and_strip_trailing_zeros() {
1676+
let test_cases: Vec<(Nibbles, Option<Nibbles>)> = vec![
1677+
// Basic increment without trailing zeros
1678+
(Nibbles::from_nibbles([0x1, 0x2, 0x3]), Some(Nibbles::from_nibbles([0x1, 0x2, 0x4]))),
1679+
// Increment with trailing zeros - should be stripped
1680+
(Nibbles::from_nibbles([0x0, 0x0, 0xF]), Some(Nibbles::from_nibbles([0x0, 0x1]))),
1681+
(Nibbles::from_nibbles([0x0, 0xF, 0xF]), Some(Nibbles::from_nibbles([0x1]))),
1682+
// Overflow case
1683+
(Nibbles::from_nibbles([0xF, 0xF, 0xF]), None),
1684+
// Empty nibbles
1685+
(Nibbles::new(), None),
1686+
// Single nibble
1687+
(Nibbles::from_nibbles([0x5]), Some(Nibbles::from_nibbles([0x6]))),
1688+
// All Fs except last - results in trailing zeros after increment
1689+
(Nibbles::from_nibbles([0xE, 0xF, 0xF]), Some(Nibbles::from_nibbles([0xF]))),
1690+
];
1691+
1692+
for (input, expected) in test_cases {
1693+
let result = increment_and_strip_trailing_zeros(&input);
1694+
assert_eq!(result, expected, "Failed for input: {:?}", input);
1695+
}
1696+
}
16531697
}

0 commit comments

Comments
 (0)