diff --git a/Cargo.lock b/Cargo.lock index 1e212fe9b..149c10f3a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -349,9 +349,9 @@ dependencies = [ [[package]] name = "alloy-trie" -version = "0.2.1" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59974c3c7778ebbcd73356a430fd4608aaf0630b1fdb4f5337bfd70f40b66618" +checksum = "6b9e1498416f7e7f09af8061970e14936846b6271e153aa5ba539a22a7eb414d" dependencies = [ "alloy-primitives", "alloy-rlp", @@ -4660,9 +4660,9 @@ dependencies = [ [[package]] name = "nybbles" -version = "0.1.2" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836816c354fb2c09622b54545a6f98416147346b13cc7eba5f92fab6b3042c93" +checksum = "95f06be0417d97f81fe4e5c86d7d01b392655a9cac9c19a848aa033e18937b23" dependencies = [ "alloy-rlp", "arbitrary", diff --git a/Cargo.toml b/Cargo.toml index f16d79efc..ae5e293d2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -180,7 +180,7 @@ alloy-primitives = "0.6" alloy-dyn-abi = "0.6" alloy-sol-types = "0.6" alloy-rlp = "0.3" -alloy-trie = "0.2" +alloy-trie = "0.3" alloy-rpc-types = { git = "https://github.com/alloy-rs/alloy", rev = "76c70fb" } alloy-rpc-trace-types = { git = "https://github.com/alloy-rs/alloy", rev = "76c70fb" } alloy-rpc-engine-types = { git = "https://github.com/alloy-rs/alloy", rev = "76c70fb" } @@ -223,7 +223,7 @@ metrics = "0.21.1" # Needed for `metrics-macro` to resolve the crate using `::me hex-literal = "0.4" once_cell = "1.17" syn = "2.0" -nybbles = "0.1" +nybbles = "0.2.1" smallvec = "1.13" # proc-macros diff --git a/crates/primitives/Cargo.toml b/crates/primitives/Cargo.toml index 0442e0c38..b2d1a87b6 100644 --- a/crates/primitives/Cargo.toml +++ b/crates/primitives/Cargo.toml @@ -25,7 +25,7 @@ alloy-primitives = { workspace = true, features = ["rand", "rlp"] } alloy-rlp = { workspace = true, features = ["arrayvec"] } alloy-trie = { workspace = true, features = ["serde"] } ethers-core = { workspace = true, default-features = false, optional = true } -nybbles = { version = "0.1.2", features = ["serde", "rlp"] } +nybbles = { workspace = true, features = ["serde", "rlp"] } alloy-genesis.workspace = true alloy-eips.workspace = true # crypto @@ -125,7 +125,3 @@ harness = false name = "trie_root" required-features = ["arbitrary", "test-utils"] harness = false - -[[bench]] -name = "nibbles" -harness = false diff --git a/crates/primitives/benches/nibbles.rs b/crates/primitives/benches/nibbles.rs deleted file mode 100644 index e8e3f65f9..000000000 --- a/crates/primitives/benches/nibbles.rs +++ /dev/null @@ -1,65 +0,0 @@ -#![allow(missing_docs)] -use criterion::{criterion_group, criterion_main, Criterion}; -use proptest::{prelude::*, strategy::ValueTree}; -use reth_primitives::trie::Nibbles; -use std::{hint::black_box, time::Duration}; - -/// Benchmarks the nibble unpacking. -pub fn nibbles_benchmark(c: &mut Criterion) { - let mut g = c.benchmark_group("nibbles"); - g.warm_up_time(Duration::from_secs(1)); - g.noise_threshold(0.02); - - g.bench_function("unpack/32", |b| { - let bytes = get_bytes(32); - b.iter(|| Nibbles::unpack(black_box(&bytes[..]))) - }); - g.bench_function("unpack/256", |b| { - let bytes = get_bytes(256); - b.iter(|| Nibbles::unpack(black_box(&bytes[..]))) - }); - g.bench_function("unpack/2048", |b| { - let bytes = get_bytes(2048); - b.iter(|| Nibbles::unpack(black_box(&bytes[..]))) - }); - - g.bench_function("pack/32", |b| { - let nibbles = get_nibbles(32); - b.iter(|| black_box(&nibbles).pack()) - }); - g.bench_function("pack/256", |b| { - let nibbles = get_nibbles(256); - b.iter(|| black_box(&nibbles).pack()) - }); - g.bench_function("pack/2048", |b| { - let nibbles = get_nibbles(2048); - b.iter(|| black_box(&nibbles).pack()) - }); - - g.bench_function("encode_path_leaf/31", |b| { - let nibbles = get_nibbles(31); - b.iter(|| black_box(&nibbles).encode_path_leaf(false)) - }); - g.bench_function("encode_path_leaf/256", |b| { - let nibbles = get_nibbles(256); - b.iter(|| black_box(&nibbles).encode_path_leaf(false)) - }); - g.bench_function("encode_path_leaf/2048", |b| { - let nibbles = get_nibbles(2048); - b.iter(|| black_box(&nibbles).encode_path_leaf(false)) - }); -} - -fn get_nibbles(len: usize) -> Nibbles { - Nibbles::from_nibbles_unchecked(get_bytes(len)) -} - -fn get_bytes(len: usize) -> Vec { - proptest::collection::vec(proptest::arbitrary::any::(), len) - .new_tree(&mut Default::default()) - .unwrap() - .current() -} - -criterion_group!(benches, nibbles_benchmark); -criterion_main!(benches); diff --git a/crates/trie/benches/prefix_set.rs b/crates/trie/benches/prefix_set.rs index 89388f2e6..c45c1f2b2 100644 --- a/crates/trie/benches/prefix_set.rs +++ b/crates/trie/benches/prefix_set.rs @@ -92,15 +92,14 @@ fn generate_test_data(size: usize) -> (Vec, Vec, Vec) { let config = ProptestConfig { result_cache: basic_result_cache, ..Default::default() }; let mut runner = TestRunner::new(config); - let mut preload = vec(vec(any::(), 32), size).new_tree(&mut runner).unwrap().current(); + let vec_of_nibbles = |range| vec(any_with::(range), size); + let mut preload = vec_of_nibbles(32usize.into()).new_tree(&mut runner).unwrap().current(); preload.dedup(); preload.sort(); - let preload = preload.into_iter().map(Nibbles::from_nibbles_unchecked).collect::>(); - let mut input = vec(vec(any::(), 0..=32), size).new_tree(&mut runner).unwrap().current(); + let mut input = vec_of_nibbles((0..=32usize).into()).new_tree(&mut runner).unwrap().current(); input.dedup(); input.sort(); - let input = input.into_iter().map(Nibbles::from_nibbles_unchecked).collect::>(); let expected = input .iter() diff --git a/crates/trie/src/prefix_set/mod.rs b/crates/trie/src/prefix_set/mod.rs index 082335df0..948b75b2e 100644 --- a/crates/trie/src/prefix_set/mod.rs +++ b/crates/trie/src/prefix_set/mod.rs @@ -176,14 +176,14 @@ mod tests { #[test] fn test_contains_with_multiple_inserts_and_duplicates() { let mut prefix_set = PrefixSetMut::default(); - prefix_set.insert(Nibbles::from_nibbles_unchecked(b"123")); - prefix_set.insert(Nibbles::from_nibbles_unchecked(b"124")); - prefix_set.insert(Nibbles::from_nibbles_unchecked(b"456")); - prefix_set.insert(Nibbles::from_nibbles_unchecked(b"123")); // Duplicate + prefix_set.insert(Nibbles::from_nibbles([1, 2, 3])); + prefix_set.insert(Nibbles::from_nibbles([1, 2, 4])); + prefix_set.insert(Nibbles::from_nibbles([4, 5, 6])); + prefix_set.insert(Nibbles::from_nibbles([1, 2, 3])); // Duplicate - assert!(prefix_set.contains(b"12")); - assert!(prefix_set.contains(b"45")); - assert!(!prefix_set.contains(b"78")); + assert!(prefix_set.contains(&[1, 2])); + assert!(prefix_set.contains(&[4, 5])); + assert!(!prefix_set.contains(&[7, 8])); assert_eq!(prefix_set.len(), 3); // Length should be 3 (excluding duplicate) } } diff --git a/crates/trie/src/trie_cursor/database_cursors.rs b/crates/trie/src/trie_cursor/database_cursors.rs index c24b335c5..71b48c7b8 100644 --- a/crates/trie/src/trie_cursor/database_cursors.rs +++ b/crates/trie/src/trie_cursor/database_cursors.rs @@ -172,14 +172,11 @@ mod tests { let mut cursor = provider.tx_ref().cursor_dup_write::().unwrap(); let hashed_address = B256::random(); - let key = vec![0x2, 0x3]; + let key = StoredNibblesSubKey::from(vec![0x2, 0x3]); let value = BranchNodeCompact::new(1, 1, 1, vec![B256::random()], None); cursor - .upsert( - hashed_address, - StorageTrieEntry { nibbles: key.clone().into(), node: value.clone() }, - ) + .upsert(hashed_address, StorageTrieEntry { nibbles: key.clone(), node: value.clone() }) .unwrap(); let mut cursor = DatabaseStorageTrieCursor::new(cursor, hashed_address); diff --git a/crates/trie/src/trie_cursor/subnode.rs b/crates/trie/src/trie_cursor/subnode.rs index 6d8404af5..c3eca176a 100644 --- a/crates/trie/src/trie_cursor/subnode.rs +++ b/crates/trie/src/trie_cursor/subnode.rs @@ -68,11 +68,13 @@ impl CursorSubNode { } /// Returns the full key of the current node. + #[inline] pub fn full_key(&self) -> &Nibbles { &self.full_key } /// Returns `true` if the state flag is set for the current nibble. + #[inline] pub fn state_flag(&self) -> bool { self.node .as_ref() @@ -80,6 +82,7 @@ impl CursorSubNode { } /// Returns `true` if the tree flag is set for the current nibble. + #[inline] pub fn tree_flag(&self) -> bool { self.node .as_ref() diff --git a/crates/trie/src/walker.rs b/crates/trie/src/walker.rs index dc6a620e2..3710648fd 100644 --- a/crates/trie/src/walker.rs +++ b/crates/trie/src/walker.rs @@ -171,7 +171,7 @@ impl TrieWalker { // Check if the walker needs to backtrack to the previous level in the trie during its // traversal. - if subnode.nibble() >= 15 || (subnode.nibble() < 0 && !allow_root_to_child_nibble) { + if subnode.nibble() >= 0xf || (subnode.nibble() < 0 && !allow_root_to_child_nibble) { self.stack.pop(); self.move_to_next_sibling(false)?; return Ok(()) @@ -184,10 +184,13 @@ impl TrieWalker { } // Find the next sibling with state. - while subnode.nibble() < 16 { + loop { if subnode.state_flag() { return Ok(()) } + if subnode.nibble() == 0xf { + break + } subnode.inc_nibble(); } @@ -354,26 +357,26 @@ mod tests { // No changes let mut cursor = TrieWalker::new(&mut trie, Default::default()); - assert_eq!(cursor.key().cloned(), Some(Nibbles::from_nibbles_unchecked([]))); // root + assert_eq!(cursor.key().cloned(), Some(Nibbles::new())); // root assert!(cursor.can_skip_current_node); // due to root_hash cursor.advance().unwrap(); // skips to the end of trie assert_eq!(cursor.key().cloned(), None); // We insert something that's not part of the existing trie/prefix. let mut changed = PrefixSetMut::default(); - changed.insert(Nibbles::from_nibbles_unchecked([0xF, 0x1])); + changed.insert(Nibbles::from_nibbles([0xF, 0x1])); let mut cursor = TrieWalker::new(&mut trie, changed.freeze()); // Root node - assert_eq!(cursor.key().cloned(), Some(Nibbles::from_nibbles_unchecked([]))); + assert_eq!(cursor.key().cloned(), Some(Nibbles::new())); // Should not be able to skip state due to the changed values assert!(!cursor.can_skip_current_node); cursor.advance().unwrap(); - assert_eq!(cursor.key().cloned(), Some(Nibbles::from_nibbles_unchecked([0x2]))); + assert_eq!(cursor.key().cloned(), Some(Nibbles::from_nibbles([0x2]))); cursor.advance().unwrap(); - assert_eq!(cursor.key().cloned(), Some(Nibbles::from_nibbles_unchecked([0x2, 0x1]))); + assert_eq!(cursor.key().cloned(), Some(Nibbles::from_nibbles([0x2, 0x1]))); cursor.advance().unwrap(); - assert_eq!(cursor.key().cloned(), Some(Nibbles::from_nibbles_unchecked([0x4]))); + assert_eq!(cursor.key().cloned(), Some(Nibbles::from_nibbles([0x4]))); cursor.advance().unwrap(); assert_eq!(cursor.key().cloned(), None); // the end of trie