diff --git a/bin/reth/src/debug_cmd/in_memory_merkle.rs b/bin/reth/src/debug_cmd/in_memory_merkle.rs index 223a104efabf..357da8817129 100644 --- a/bin/reth/src/debug_cmd/in_memory_merkle.rs +++ b/bin/reth/src/debug_cmd/in_memory_merkle.rs @@ -223,7 +223,7 @@ impl Command { (Some(in_mem), Some(incr)) => { pretty_assertions::assert_eq!(in_mem.0, incr.0, "Nibbles don't match"); if in_mem.1 != incr.1 && - matches!(in_mem.0, TrieKey::AccountNode(ref nibbles) if nibbles.inner.len() > self.skip_node_depth.unwrap_or_default()) + matches!(in_mem.0, TrieKey::AccountNode(ref nibbles) if nibbles.len() > self.skip_node_depth.unwrap_or_default()) { in_mem_mismatched.push(in_mem); incremental_mismatched.push(incr); diff --git a/bin/reth/src/debug_cmd/merkle.rs b/bin/reth/src/debug_cmd/merkle.rs index fd6a9c0c5109..3745efc9f761 100644 --- a/bin/reth/src/debug_cmd/merkle.rs +++ b/bin/reth/src/debug_cmd/merkle.rs @@ -311,7 +311,7 @@ impl Command { "Nibbles don't match" ); if incremental.1 != clean.1 && - clean.0.inner.len() > self.skip_node_depth.unwrap_or_default() + clean.0.len() > self.skip_node_depth.unwrap_or_default() { incremental_account_mismatched.push(incremental); clean_account_mismatched.push(clean); @@ -340,8 +340,7 @@ impl Command { match (incremental_storage_trie_iter.next(), clean_storage_trie_iter.next()) { (Some(incremental), Some(clean)) => { if incremental != clean && - clean.1.nibbles.inner.len() > - self.skip_node_depth.unwrap_or_default() + clean.1.nibbles.len() > self.skip_node_depth.unwrap_or_default() { first_mismatched_storage = Some((incremental, clean)); break diff --git a/crates/primitives/benches/nibbles.rs b/crates/primitives/benches/nibbles.rs index abe9801a34c1..3d839fd7a688 100644 --- a/crates/primitives/benches/nibbles.rs +++ b/crates/primitives/benches/nibbles.rs @@ -3,17 +3,12 @@ use reth_primitives::trie::Nibbles; /// Benchmarks the nibble unpacking. pub fn nibbles_benchmark(c: &mut Criterion) { - c.bench_function("Nibbles unpack", |b| { + let mut g = c.benchmark_group("nibbles"); + g.bench_function("unpack", |b| { let raw = (1..=32).collect::>(); - b.iter(|| { - Nibbles::unpack(&raw); - }) + b.iter(|| Nibbles::unpack(&raw)) }); } -criterion_group! { - name = benches; - config = Criterion::default(); - targets = nibbles_benchmark -} +criterion_group!(benches, nibbles_benchmark); criterion_main!(benches); diff --git a/crates/primitives/src/trie/hash_builder/mod.rs b/crates/primitives/src/trie/hash_builder/mod.rs index 3e4a7a7265b5..89559819ecbf 100644 --- a/crates/primitives/src/trie/hash_builder/mod.rs +++ b/crates/primitives/src/trie/hash_builder/mod.rs @@ -1,8 +1,9 @@ use super::{ - nodes::{rlp_hash, BranchNode, ExtensionNode, LeafNode}, + nodes::{word_rlp, BranchNode, ExtensionNode, LeafNode}, BranchNodeCompact, Nibbles, TrieMask, }; use crate::{constants::EMPTY_ROOT_HASH, keccak256, Bytes, B256}; +use itertools::Itertools; use std::{ collections::{BTreeMap, HashMap}, fmt::Debug, @@ -62,7 +63,7 @@ pub struct HashBuilder { impl From for HashBuilder { fn from(state: HashBuilderState) -> Self { Self { - key: Nibbles::from_hex(state.key), + key: Nibbles::new_unchecked(state.key), stack: state.stack, value: state.value, groups: state.groups, @@ -79,7 +80,7 @@ impl From for HashBuilder { impl From for HashBuilderState { fn from(state: HashBuilder) -> Self { Self { - key: state.key.hex_data.to_vec(), + key: state.key.to_vec(), stack: state.stack, value: state.value, groups: state.groups, @@ -155,7 +156,7 @@ impl HashBuilder { if !self.key.is_empty() { self.update(&key); } else if key.is_empty() { - self.stack.push(rlp_hash(value)); + self.stack.push(word_rlp(&value)); } self.set_key_value(key, value); self.stored_in_database = stored_in_database; @@ -166,7 +167,7 @@ impl HashBuilder { // Clears the internal state if !self.key.is_empty() { self.update(&Nibbles::default()); - self.key.hex_data.0.clear(); + self.key.clear(); self.value = HashBuilderValue::Bytes(vec![]); } self.current_root() @@ -209,7 +210,7 @@ impl HashBuilder { tracing::Level::TRACE, "loop", i, - current = crate::hex::encode(¤t.hex_data), + ?current, ?build_extensions ); let _enter = span.enter(); @@ -217,7 +218,7 @@ impl HashBuilder { let preceding_exists = !self.groups.is_empty(); let preceding_len: usize = self.groups.len().saturating_sub(1); - let common_prefix_len = succeeding.common_prefix_length(¤t); + let common_prefix_len = succeeding.common_prefix_length(current.as_slice()); let len = std::cmp::max(preceding_len, common_prefix_len); assert!(len < current.len()); @@ -241,7 +242,7 @@ impl HashBuilder { trace!( target: "trie::hash_builder", ?extra_digit, - groups = self.groups.iter().map(|x| format!("{x:?}")).collect::>().join(","), + groups = ?self.groups.iter().format(", "), ); // Adjust the tree masks for exporting to the DB @@ -256,7 +257,7 @@ impl HashBuilder { trace!(target: "trie::hash_builder", "skipping {} nibbles", len_from); // The key without the common prefix - let short_node_key = current.slice_from(len_from); + let short_node_key = current.slice(len_from..); trace!(target: "trie::hash_builder", ?short_node_key); // Concatenate the 2 nodes together @@ -276,7 +277,7 @@ impl HashBuilder { } HashBuilderValue::Hash(hash) => { trace!(target: "trie::hash_builder", ?hash, "pushing branch node hash"); - self.stack.push(rlp_hash(*hash)); + self.stack.push(word_rlp(hash)); if self.stored_in_database { self.tree_masks[current.len() - 1] |= @@ -302,7 +303,7 @@ impl HashBuilder { }, "extension node rlp"); self.rlp_buf.clear(); self.stack.push(extension_node.rlp(&mut self.rlp_buf)); - self.retain_proof_from_buf(¤t.slice(0, len_from)); + self.retain_proof_from_buf(¤t.slice(..len_from)); self.resize_masks(len_from); } @@ -353,7 +354,7 @@ impl HashBuilder { self.rlp_buf.clear(); let rlp = branch_node.rlp(state_mask, &mut self.rlp_buf); - self.retain_proof_from_buf(¤t.slice(0, len)); + self.retain_proof_from_buf(¤t.slice(..len)); // Clears the stack from the branch node elements let first_child_idx = self.stack.len() - state_mask.count_ones() as usize; @@ -403,7 +404,7 @@ impl HashBuilder { // Send it over to the provided channel which will handle it on the // other side of the HashBuilder trace!(target: "trie::hash_builder", node = ?n, "intermediate node"); - let common_prefix = current.slice(0, len); + let common_prefix = current.slice(..len); if let Some(nodes) = self.updated_branch_nodes.as_mut() { nodes.insert(common_prefix, n); } @@ -563,7 +564,7 @@ mod tests { let (_, updates) = hb.split(); - let update = updates.get(&Nibbles::from(hex!("01").as_slice())).unwrap(); + let update = updates.get(&Nibbles::new_unchecked(hex!("01"))).unwrap(); assert_eq!(update.state_mask, TrieMask::new(0b1111)); // 1st nibble: 0, 1, 2, 3 assert_eq!(update.tree_mask, TrieMask::new(0)); assert_eq!(update.hash_mask, TrieMask::new(6)); // in the 1st nibble, the ones with 1 and 2 are branches with `hashes` @@ -633,7 +634,7 @@ mod tests { let mut hb2 = HashBuilder::default(); // Insert the branch with the `0x6` shared prefix. - hb2.add_branch(Nibbles::from_hex(vec![0x6]), branch_node_hash, false); + hb2.add_branch(Nibbles::new_unchecked([0x6]), branch_node_hash, false); let expected = trie_root(raw_input.clone()); assert_eq!(hb.root(), expected); diff --git a/crates/primitives/src/trie/mask.rs b/crates/primitives/src/trie/mask.rs index 152be03c936d..16fdd69597b9 100644 --- a/crates/primitives/src/trie/mask.rs +++ b/crates/primitives/src/trie/mask.rs @@ -32,27 +32,32 @@ pub struct TrieMask(u16); impl TrieMask { /// Creates a new `TrieMask` from the given inner value. + #[inline] pub fn new(inner: u16) -> Self { Self(inner) } /// Creates a new `TrieMask` from the given nibble. + #[inline] pub fn from_nibble(nibble: u8) -> Self { Self(1u16 << nibble) } /// Returns `true` if the current `TrieMask` is a subset of `other`. - pub fn is_subset_of(&self, other: &Self) -> bool { - *self & *other == *self + #[inline] + pub fn is_subset_of(self, other: Self) -> bool { + self & other == self } /// Returns `true` if a given bit is set in a mask. - pub fn is_bit_set(&self, index: u8) -> bool { + #[inline] + pub fn is_bit_set(self, index: u8) -> bool { self.0 & (1u16 << index) != 0 } /// Returns `true` if the mask is empty. - pub fn is_empty(&self) -> bool { + #[inline] + pub fn is_empty(self) -> bool { self.0 == 0 } } diff --git a/crates/primitives/src/trie/mod.rs b/crates/primitives/src/trie/mod.rs index f388fc6d1329..b531d8fdac36 100644 --- a/crates/primitives/src/trie/mod.rs +++ b/crates/primitives/src/trie/mod.rs @@ -19,7 +19,7 @@ mod subnode; pub use self::{ mask::TrieMask, - nibbles::{Nibbles, StoredNibbles, StoredNibblesSubKey}, + nibbles::{Nibbles, StoredNibblesSubKey}, storage::StorageTrieEntry, subnode::StoredSubNode, }; diff --git a/crates/primitives/src/trie/nibbles.rs b/crates/primitives/src/trie/nibbles.rs index d3d862966df5..aa36f2955c69 100644 --- a/crates/primitives/src/trie/nibbles.rs +++ b/crates/primitives/src/trie/nibbles.rs @@ -3,28 +3,30 @@ use alloy_rlp::RlpEncodableWrapper; use derive_more::{Deref, From, Index}; use reth_codecs::{main_codec, Compact}; use serde::{Deserialize, Serialize}; +use std::{borrow::Borrow, ops::RangeBounds}; -/// The nibbles are the keys for the AccountsTrie and the subkeys for the StorageTrie. -#[main_codec] -#[derive(Debug, Default, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub struct StoredNibbles { - /// The inner nibble bytes - pub inner: Bytes, -} +/// The representation of nibbles of the merkle trie stored in the database. +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Hash, Deref)] +pub struct StoredNibblesSubKey(pub Nibbles); -impl From> for StoredNibbles { - fn from(inner: Vec) -> Self { - Self { inner: inner.into() } +impl From for StoredNibblesSubKey { + #[inline] + fn from(value: Nibbles) -> Self { + Self(value) } } -/// The representation of nibbles of the merkle trie stored in the database. -#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Hash, Deref)] -pub struct StoredNibblesSubKey(StoredNibbles); - impl From> for StoredNibblesSubKey { - fn from(inner: Vec) -> Self { - Self(StoredNibbles { inner: inner.into() }) + #[inline] + fn from(value: Vec) -> Self { + Self(Nibbles::new_unchecked(value)) + } +} + +impl From for Nibbles { + #[inline] + fn from(value: StoredNibblesSubKey) -> Self { + value.0 } } @@ -33,73 +35,122 @@ impl Compact for StoredNibblesSubKey { where B: bytes::BufMut + AsMut<[u8]>, { - assert!(self.inner.len() <= 64); - let mut padded = vec![0; 64]; - padded[..self.inner.len()].copy_from_slice(&self.inner[..]); - buf.put_slice(&padded); - buf.put_u8(self.inner.len() as u8); + assert!(self.0.len() <= 64); + + // right-pad with zeros + buf.put_slice(&self.0[..]); + static ZERO: &[u8; 64] = &[0; 64]; + buf.put_slice(&ZERO[self.0.len()..]); + + buf.put_u8(self.0.len() as u8); 64 + 1 } fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) { let len = buf[64] as usize; - let inner = Vec::from(&buf[..len]).into(); - (Self(StoredNibbles { inner }), &buf[65..]) + (Self(Nibbles::new_unchecked(buf[..len].to_vec())), &buf[65..]) } } /// Structure representing a sequence of nibbles. /// -/// A nibble is a 4-bit value, and this structure is used to store -/// the nibble sequence representing the keys in a Merkle Patricia Trie (MPT). -/// Using nibbles simplifies trie operations and enables consistent key -/// representation in the MPT. +/// A nibble is a 4-bit value, and this structure is used to store the nibble sequence representing +/// the keys in a Merkle Patricia Trie (MPT). +/// Using nibbles simplifies trie operations and enables consistent key representation in the MPT. /// -/// The `hex_data` field is a `Vec` that stores the nibbles, with each -/// `u8` value containing a single nibble. This means that each byte in -/// `hex_data` has its upper 4 bits set to zero and the lower 4 bits +/// The internal representation is a shared heap-allocated vector ([`Bytes`]) that stores one nibble +/// per byte. This means that each byte has its upper 4 bits set to zero and the lower 4 bits /// representing the nibble value. +#[main_codec] #[derive( - Default, Clone, Eq, PartialEq, RlpEncodableWrapper, PartialOrd, Ord, Hash, Index, From, Deref, + Clone, + Debug, + Default, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + RlpEncodableWrapper, + Index, + From, + Deref, )] -pub struct Nibbles { - /// The inner representation of the nibble sequence. - pub hex_data: Bytes, +pub struct Nibbles(Bytes); + +impl From> for Nibbles { + #[inline] + fn from(value: Vec) -> Self { + Self::new_unchecked(value) + } } -impl From<&[u8]> for Nibbles { - fn from(slice: &[u8]) -> Self { - Nibbles::from_hex(slice.to_vec()) +impl From for Vec { + #[inline] + fn from(value: Nibbles) -> Self { + value.0.into() } } -impl From<&[u8; N]> for Nibbles { - fn from(arr: &[u8; N]) -> Self { - Nibbles::from_hex(arr.to_vec()) +impl From for Bytes { + #[inline] + fn from(value: Nibbles) -> Self { + value.into_bytes() } } -impl std::fmt::Debug for Nibbles { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("Nibbles").field("hex_data", &crate::hex::encode(&self.hex_data)).finish() +impl PartialEq<[u8]> for Nibbles { + #[inline] + fn eq(&self, other: &[u8]) -> bool { + self.as_slice() == other + } +} + +impl PartialEq for [u8] { + #[inline] + fn eq(&self, other: &Nibbles) -> bool { + self == other.as_slice() + } +} + +impl PartialOrd<[u8]> for Nibbles { + #[inline] + fn partial_cmp(&self, other: &[u8]) -> Option { + self.as_slice().partial_cmp(other) + } +} + +impl PartialOrd for [u8] { + #[inline] + fn partial_cmp(&self, other: &Nibbles) -> Option { + self.partial_cmp(other.as_slice()) + } +} + +impl Borrow<[u8]> for Nibbles { + #[inline] + fn borrow(&self) -> &[u8] { + self.as_slice() } } impl Nibbles { - /// Creates a new [Nibbles] instance from bytes. - pub fn from_hex>(hex: T) -> Self { - Nibbles { hex_data: hex.into() } + /// Creates a new [`Nibbles`] instance from nibble bytes, without checking their validity. + #[inline] + pub fn new_unchecked>(nibbles: T) -> Self { + Self(nibbles.into()) } - /// Take a byte array (slice or vector) as input and convert it into a [Nibbles] struct - /// containing the nibbles (half-bytes or 4 bits) that make up the input byte data. + /// Converts a byte slice into a [`Nibbles`] instance containing the nibbles (half-bytes or 4 + /// bits) that make up the input byte data. pub fn unpack>(data: T) -> Self { - let mut vec = Vec::with_capacity(data.as_ref().len() * 2); - for byte in data.as_ref() { - vec.push(byte / 16); - vec.push(byte % 16); + let data = data.as_ref(); + let mut nibbles = Vec::with_capacity(data.len() * 2); + for &byte in data { + nibbles.push(byte >> 4); + nibbles.push(byte & 0x0f); } - Nibbles { hex_data: Bytes::from(vec) } + Self(nibbles.into()) } /// Packs the nibbles stored in the struct into a byte vector. @@ -109,22 +160,14 @@ impl Nibbles { /// If the number of nibbles is odd, the last nibble is shifted left by 4 bits and /// added to the packed byte vector. pub fn pack(&self) -> Vec { - let length = (self.len() + 1) / 2; - if length == 0 { - Vec::new() - } else { - self.iter() - .enumerate() - .filter_map(|(index, nibble)| { - if index % 2 == 0 { - let next_nibble = self.get(index + 1).unwrap_or(&0); - Some((*nibble << 4) + *next_nibble) - } else { - None - } - }) - .collect() + let packed_len = (self.len() + 1) / 2; + let mut v = Vec::with_capacity(packed_len); + for i in 0..packed_len { + let hi = *unsafe { self.get_unchecked(i * 2) }; + let lo = self.get(i * 2 + 1).copied().unwrap_or(0); + v.push((hi << 4) | lo); } + v } /// Encodes a given path leaf as a compact array of bytes, where each byte represents two @@ -155,19 +198,19 @@ impl Nibbles { /// # use reth_primitives::trie::Nibbles; /// /// // Extension node with an even path length: - /// let nibbles = Nibbles::from_hex(vec![0x0A, 0x0B, 0x0C, 0x0D]); + /// let nibbles = Nibbles::new_unchecked(&[0x0A, 0x0B, 0x0C, 0x0D]); /// assert_eq!(nibbles.encode_path_leaf(false), vec![0x00, 0xAB, 0xCD]); /// /// // Extension node with an odd path length: - /// let nibbles = Nibbles::from_hex(vec![0x0A, 0x0B, 0x0C]); + /// let nibbles = Nibbles::new_unchecked(&[0x0A, 0x0B, 0x0C]); /// assert_eq!(nibbles.encode_path_leaf(false), vec![0x1A, 0xBC]); /// /// // Leaf node with an even path length: - /// let nibbles = Nibbles::from_hex(vec![0x0A, 0x0B, 0x0C, 0x0D]); + /// let nibbles = Nibbles::new_unchecked(&[0x0A, 0x0B, 0x0C, 0x0D]); /// assert_eq!(nibbles.encode_path_leaf(true), vec![0x20, 0xAB, 0xCD]); /// /// // Leaf node with an odd path length: - /// let nibbles = Nibbles::from_hex(vec![0x0A, 0x0B, 0x0C]); + /// let nibbles = Nibbles::new_unchecked(&[0x0A, 0x0B, 0x0C]); /// assert_eq!(nibbles.encode_path_leaf(true), vec![0x3A, 0xBC]); /// ``` pub fn encode_path_leaf(&self, is_leaf: bool) -> Vec { @@ -192,14 +235,14 @@ impl Nibbles { } /// Increments the nibble sequence by one. - pub fn increment(&self) -> Option { - let mut incremented = self.hex_data.to_vec(); + pub fn increment(&self) -> Option { + let mut incremented = self.0.to_vec(); for nibble in incremented.iter_mut().rev() { - assert!(*nibble < 0x10); + debug_assert!(*nibble < 0x10); if *nibble < 0xf { *nibble += 1; - return Some(Nibbles::from_hex(incremented)) + return Some(Self::new_unchecked(incremented)) } else { *nibble = 0; } @@ -210,27 +253,37 @@ impl Nibbles { /// The last element of the hex vector is used to determine whether the nibble sequence /// represents a leaf or an extension node. If the last element is 0x10 (16), then it's a leaf. + #[inline] pub fn is_leaf(&self) -> bool { - self.hex_data[self.hex_data.len() - 1] == 16 + self.last() == Some(16) } /// Returns `true` if the current nibble sequence starts with the given prefix. - pub fn has_prefix(&self, other: &Self) -> bool { + #[inline] + pub fn has_prefix(&self, other: &[u8]) -> bool { self.starts_with(other) } /// Returns the nibble at the given index. + /// + /// # Panics + /// + /// Panics if the index is out of bounds. + #[inline] + #[track_caller] pub fn at(&self, i: usize) -> usize { - self.hex_data[i] as usize + self.0[i] as usize } /// Returns the last nibble of the current nibble sequence. + #[inline] pub fn last(&self) -> Option { - self.hex_data.last().copied() + self.0.last().copied() } /// Returns the length of the common prefix between the current nibble sequence and the given. - pub fn common_prefix_length(&self, other: &Nibbles) -> usize { + #[inline] + pub fn common_prefix_length(&self, other: &[u8]) -> usize { let len = std::cmp::min(self.len(), other.len()); for i in 0..len { if self[i] != other[i] { @@ -240,34 +293,67 @@ impl Nibbles { len } - /// Slice the current nibbles from the given start index to the end. - pub fn slice_from(&self, index: usize) -> Nibbles { - self.slice(index, self.hex_data.len()) + /// Returns a reference to the underlying [`Bytes`]. + #[inline] + pub fn as_bytes(&self) -> &Bytes { + &self.0 + } + + /// Returns the nibbles as a byte slice. + #[inline] + pub fn as_slice(&self) -> &[u8] { + &self.0 + } + + /// Returns the underlying [`Bytes`]. + #[inline] + pub fn into_bytes(self) -> Bytes { + self.0 } /// Slice the current nibbles within the provided index range. - pub fn slice(&self, start: usize, end: usize) -> Nibbles { - Nibbles::from_hex(self.hex_data[start..end].to_vec()) + #[inline] + pub fn slice(&self, range: impl RangeBounds) -> Self { + Self(self.0.slice(range)) } /// Join two nibbles together. - pub fn join(&self, b: &Nibbles) -> Nibbles { + #[inline] + pub fn join(&self, b: &Self) -> Self { let mut hex_data = Vec::with_capacity(self.len() + b.len()); hex_data.extend_from_slice(self); hex_data.extend_from_slice(b); - Nibbles::from_hex(hex_data) + Self::new_unchecked(hex_data) + } + + /// Pushes a nibble to the end of the current nibbles. + /// + /// **Note**: This method re-allocates on each call. + #[inline] + pub fn push(&mut self, nibble: u8) { + self.extend([nibble]); } /// Extend the current nibbles with another nibbles. + /// + /// **Note**: This method re-allocates on each call. + #[inline] pub fn extend(&mut self, b: impl AsRef<[u8]>) { - let mut bytes = self.hex_data.to_vec(); + let mut bytes = self.0.to_vec(); bytes.extend_from_slice(b.as_ref()); - self.hex_data = bytes.into(); + self.0 = bytes.into(); } - /// Truncate the current nibbles to the given length. + /// Truncates the current nibbles to the given length. + #[inline] pub fn truncate(&mut self, len: usize) { - self.hex_data.0.truncate(len) + self.0.truncate(len); + } + + /// Clears the current nibbles. + #[inline] + pub fn clear(&mut self) { + self.0.clear(); } } @@ -279,7 +365,7 @@ mod tests { #[test] fn hashed_regression() { - let nibbles = Nibbles::from_hex(hex!("05010406040a040203030f010805020b050c04070003070e0909070f010b0a0805020301070c0a0902040b0f000f0006040a04050f020b090701000a0a040b")); + let nibbles = Nibbles::new_unchecked(hex!("05010406040a040203030f010805020b050c04070003070e0909070f010b0a0805020301070c0a0902040b0f000f0006040a04050f020b090701000a0a040b")); let path = nibbles.encode_path_leaf(true); let expected = hex!("351464a4233f1852b5c47037e997f1ba852317ca924bf0f064a45f2b9710aa4b"); assert_eq!(path, expected); @@ -295,7 +381,7 @@ mod tests { (vec![0xa, 0xb, 0x2, 0x0], vec![0xab, 0x20]), (vec![0xa, 0xb, 0x2, 0x7], vec![0xab, 0x27]), ] { - let nibbles = Nibbles::from_hex(input); + let nibbles = Nibbles::new_unchecked(input); let encoded = nibbles.pack(); assert_eq!(encoded, expected); } diff --git a/crates/primitives/src/trie/nodes/branch.rs b/crates/primitives/src/trie/nodes/branch.rs index 2771adfa40c8..961050be3f8d 100644 --- a/crates/primitives/src/trie/nodes/branch.rs +++ b/crates/primitives/src/trie/nodes/branch.rs @@ -123,8 +123,8 @@ impl BranchNodeCompact { ) -> 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)); - assert!(hash_mask.is_subset_of(&state_mask)); + assert!(tree_mask.is_subset_of(state_mask)); + assert!(hash_mask.is_subset_of(state_mask)); assert_eq!(hash_mask.count_ones() as usize, hashes.len()); Self { state_mask, tree_mask, hash_mask, hashes, root_hash } } diff --git a/crates/primitives/src/trie/nodes/leaf.rs b/crates/primitives/src/trie/nodes/leaf.rs index 9fb016e1505a..684bf913d6ff 100644 --- a/crates/primitives/src/trie/nodes/leaf.rs +++ b/crates/primitives/src/trie/nodes/leaf.rs @@ -54,25 +54,22 @@ impl std::fmt::Debug for LeafNode<'_> { #[cfg(test)] mod tests { use super::*; - use crate::hex_literal::hex; + use crate::hex; // From manual regression test #[test] fn encode_leaf_node_nibble() { - let nibble = Nibbles { hex_data: hex!("0604060f").into() }; + let nibble = Nibbles::new_unchecked(hex!("0604060f")); let encoded = nibble.encode_path_leaf(true); - let expected = hex!("20646f").to_vec(); - assert_eq!(encoded, expected); + assert_eq!(encoded, hex!("20646f")); } #[test] fn rlp_leaf_node_roundtrip() { - let nibble = Nibbles { hex_data: hex!("0604060f").into() }; - let val = hex!("76657262").to_vec(); + let nibble = Nibbles::new_unchecked(hex!("0604060f")); + let val = hex!("76657262"); let leaf = LeafNode::new(&nibble, &val); let rlp = leaf.rlp(&mut vec![]); - - let expected = hex!("c98320646f8476657262").to_vec(); - assert_eq!(rlp, expected); + assert_eq!(rlp, hex!("c98320646f8476657262")); } } diff --git a/crates/primitives/src/trie/nodes/mod.rs b/crates/primitives/src/trie/nodes/mod.rs index 78c413a92516..98e7d494af7e 100644 --- a/crates/primitives/src/trie/nodes/mod.rs +++ b/crates/primitives/src/trie/nodes/mod.rs @@ -3,28 +3,30 @@ use alloy_rlp::EMPTY_STRING_CODE; use std::ops::Range; mod branch; +pub use branch::{BranchNode, BranchNodeCompact}; + mod extension; -mod leaf; +pub use extension::ExtensionNode; -pub use self::{ - branch::{BranchNode, BranchNodeCompact}, - extension::ExtensionNode, - leaf::LeafNode, -}; +mod leaf; +pub use leaf::LeafNode; /// The range of valid child indexes. pub const CHILD_INDEX_RANGE: Range = 0..16; /// Given an RLP encoded node, returns either RLP(node) or RLP(keccak(RLP(node))) +#[inline] fn rlp_node(rlp: &[u8]) -> Vec { if rlp.len() < B256::len_bytes() { rlp.to_vec() } else { - rlp_hash(keccak256(rlp)) + word_rlp(&keccak256(rlp)) } } -/// Optimization for quick encoding of a hash as RLP -pub fn rlp_hash(hash: B256) -> Vec { - [[EMPTY_STRING_CODE + B256::len_bytes() as u8].as_slice(), hash.0.as_slice()].concat() +/// Optimization for quick encoding of a 32-byte word as RLP. +// TODO: this could return [u8; 33] but Vec is needed everywhere this function is used +#[inline] +pub fn word_rlp(word: &B256) -> Vec { + [&[EMPTY_STRING_CODE + B256::len_bytes() as u8][..], &word[..]].concat() } diff --git a/crates/storage/db/src/tables/codecs/compact.rs b/crates/storage/db/src/tables/codecs/compact.rs index c420e3105360..b005cc961ee6 100644 --- a/crates/storage/db/src/tables/codecs/compact.rs +++ b/crates/storage/db/src/tables/codecs/compact.rs @@ -37,7 +37,7 @@ impl_compression_for_compact!( Receipt, TxType, StorageEntry, - StoredNibbles, + Nibbles, BranchNodeCompact, StoredNibblesSubKey, StorageTrieEntry, diff --git a/crates/storage/db/src/tables/mod.rs b/crates/storage/db/src/tables/mod.rs index 275271f7bc39..f8d4457ff658 100644 --- a/crates/storage/db/src/tables/mod.rs +++ b/crates/storage/db/src/tables/mod.rs @@ -36,7 +36,7 @@ use crate::{ }; use reth_primitives::{ stage::StageCheckpoint, - trie::{BranchNodeCompact, StorageTrieEntry, StoredNibbles, StoredNibblesSubKey}, + trie::{BranchNodeCompact, Nibbles, StorageTrieEntry, StoredNibblesSubKey}, Account, Address, BlockHash, BlockNumber, Bytecode, Header, IntegerList, PruneCheckpoint, PruneSegment, Receipt, StorageEntry, TransactionSignedNoHash, TxHash, TxNumber, B256, }; @@ -384,7 +384,7 @@ dupsort!( table!( /// Stores the current state's Merkle Patricia Tree. - ( AccountsTrie ) StoredNibbles | BranchNodeCompact + ( AccountsTrie ) Nibbles | BranchNodeCompact ); dupsort!( diff --git a/crates/storage/db/src/tables/models/mod.rs b/crates/storage/db/src/tables/models/mod.rs index 507151797d4b..3fe332a60bbd 100644 --- a/crates/storage/db/src/tables/models/mod.rs +++ b/crates/storage/db/src/tables/models/mod.rs @@ -5,7 +5,7 @@ use crate::{ }; use reth_codecs::Compact; use reth_primitives::{ - trie::{StoredNibbles, StoredNibblesSubKey}, + trie::{Nibbles, StoredNibblesSubKey}, Address, PruneSegment, B256, }; @@ -102,18 +102,18 @@ impl Decode for String { } } -impl Encode for StoredNibbles { +impl Encode for Nibbles { type Encoded = Vec; // Delegate to the Compact implementation fn encode(self) -> Self::Encoded { - let mut buf = Vec::with_capacity(self.inner.len()); + let mut buf = Vec::with_capacity(self.len()); self.to_compact(&mut buf); buf } } -impl Decode for StoredNibbles { +impl Decode for Nibbles { fn decode>(value: B) -> Result { let buf = value.as_ref(); Ok(Self::from_compact(buf, buf.len()).0) diff --git a/crates/transaction-pool/benches/truncate.rs b/crates/transaction-pool/benches/truncate.rs index e96ed753b3e2..ca25d731d699 100644 --- a/crates/transaction-pool/benches/truncate.rs +++ b/crates/transaction-pool/benches/truncate.rs @@ -35,8 +35,7 @@ fn create_transactions_for_sender( .unwrap() .current(); - let mut nonce = 0; - for tx in txs.iter_mut() { + for (nonce, tx) in txs.iter_mut().enumerate() { // reject pre-eip1559 tx types, if there is a legacy tx, replace it with an eip1559 tx if tx.is_legacy() || tx.is_eip2930() { *tx = MockTransaction::eip1559(); @@ -47,8 +46,7 @@ fn create_transactions_for_sender( } tx.set_sender(sender); - tx.set_nonce(nonce); - nonce += 1; + tx.set_nonce(nonce as u64); } txs diff --git a/crates/trie/benches/prefix_set.rs b/crates/trie/benches/prefix_set.rs index 95782fe890f1..c9e4dbbd699f 100644 --- a/crates/trie/benches/prefix_set.rs +++ b/crates/trie/benches/prefix_set.rs @@ -16,14 +16,13 @@ pub trait PrefixSetAbstraction: Default { fn contains(&mut self, key: Nibbles) -> bool; } -/// Abstractions used for benching impl PrefixSetAbstraction for PrefixSetMut { fn insert(&mut self, key: Nibbles) { - self.insert(key) + PrefixSetMut::insert(self, key) } fn contains(&mut self, key: Nibbles) -> bool { - PrefixSetMut::contains(self, key) + PrefixSetMut::contains(self, &key) } } @@ -95,12 +94,12 @@ fn generate_test_data(size: usize) -> (Vec, Vec, Vec) { let mut preload = vec(vec(any::(), 32), size).new_tree(&mut runner).unwrap().current(); preload.dedup(); preload.sort(); - let preload = preload.into_iter().map(|hash| Nibbles::from(&hash[..])).collect::>(); + let preload = preload.into_iter().map(Nibbles::new_unchecked).collect::>(); let mut input = vec(vec(any::(), 0..=32), size).new_tree(&mut runner).unwrap().current(); input.dedup(); input.sort(); - let input = input.into_iter().map(|bytes| Nibbles::from(&bytes[..])).collect::>(); + let input = input.into_iter().map(Nibbles::new_unchecked).collect::>(); let expected = input .iter() @@ -145,11 +144,11 @@ mod implementations { fn contains(&mut self, prefix: Nibbles) -> bool { let range = match self.last_checked.as_ref() { // presumably never hit - Some(last) if &prefix < last => (Bound::Unbounded, Bound::Excluded(last)), + Some(last) if prefix < *last => (Bound::Unbounded, Bound::Excluded(last)), Some(last) => (Bound::Included(last), Bound::Unbounded), None => (Bound::Unbounded, Bound::Unbounded), }; - for key in self.keys.range(range) { + for key in self.keys.range::(range) { if key.has_prefix(&prefix) { self.last_checked = Some(prefix); return true diff --git a/crates/trie/src/prefix_set/mod.rs b/crates/trie/src/prefix_set/mod.rs index 7fe8cb9c17d2..0c262759a3c1 100644 --- a/crates/trie/src/prefix_set/mod.rs +++ b/crates/trie/src/prefix_set/mod.rs @@ -22,13 +22,14 @@ pub use loader::{LoadedPrefixSets, PrefixSetLoader}; /// # Examples /// /// ``` +/// use reth_primitives::trie::Nibbles; /// use reth_trie::prefix_set::PrefixSetMut; /// /// let mut prefix_set = PrefixSetMut::default(); -/// prefix_set.insert(b"key1"); -/// prefix_set.insert(b"key2"); -/// -/// assert_eq!(prefix_set.contains(b"key"), true); +/// prefix_set.insert(Nibbles::new_unchecked(&[0xa, 0xb])); +/// prefix_set.insert(Nibbles::new_unchecked(&[0xa, 0xb, 0xc])); +/// assert!(prefix_set.contains(&[0xa, 0xb])); +/// assert!(prefix_set.contains(&[0xa, 0xb, 0xc])); /// ``` #[derive(Debug, Default, Clone)] pub struct PrefixSetMut { @@ -49,26 +50,24 @@ where impl PrefixSetMut { /// Returns `true` if any of the keys in the set has the given prefix or /// if the given prefix is a prefix of any key in the set. - pub fn contains>(&mut self, prefix: T) -> bool { + pub fn contains(&mut self, prefix: &[u8]) -> bool { if !self.sorted { self.keys.sort(); self.keys.dedup(); self.sorted = true; } - let prefix = prefix.into(); - - while self.index > 0 && self.keys[self.index] > prefix { + while self.index > 0 && self.keys[self.index] > *prefix { self.index -= 1; } for (idx, key) in self.keys[self.index..].iter().enumerate() { - if key.has_prefix(&prefix) { + if key.has_prefix(prefix) { self.index += idx; return true } - if key > &prefix { + if *key > *prefix { self.index += idx; return false } @@ -78,9 +77,9 @@ impl PrefixSetMut { } /// Inserts the given `nibbles` into the set. - pub fn insert>(&mut self, nibbles: T) { + pub fn insert(&mut self, nibbles: Nibbles) { self.sorted = false; - self.keys.push(nibbles.into()); + self.keys.push(nibbles); } /// Returns the number of elements in the set. @@ -159,10 +158,10 @@ mod tests { #[test] fn test_contains_with_multiple_inserts_and_duplicates() { let mut prefix_set = PrefixSetMut::default(); - prefix_set.insert(b"123"); - prefix_set.insert(b"124"); - prefix_set.insert(b"456"); - prefix_set.insert(b"123"); // Duplicate + prefix_set.insert(Nibbles::new_unchecked(b"123")); + prefix_set.insert(Nibbles::new_unchecked(b"124")); + prefix_set.insert(Nibbles::new_unchecked(b"456")); + prefix_set.insert(Nibbles::new_unchecked(b"123")); // Duplicate assert!(prefix_set.contains(b"12")); assert!(prefix_set.contains(b"45")); diff --git a/crates/trie/src/trie.rs b/crates/trie/src/trie.rs index 4fdc41a7dd66..d145c66348f8 100644 --- a/crates/trie/src/trie.rs +++ b/crates/trie/src/trie.rs @@ -937,7 +937,7 @@ mod tests { assert_eq!(account_updates.len(), 2); let (nibbles1a, node1a) = account_updates.first().unwrap(); - assert_eq!(nibbles1a.inner[..], [0xB]); + assert_eq!(nibbles1a[..], [0xB]); assert_eq!(node1a.state_mask, TrieMask::new(0b1011)); assert_eq!(node1a.tree_mask, TrieMask::new(0b0001)); assert_eq!(node1a.hash_mask, TrieMask::new(0b1001)); @@ -945,7 +945,7 @@ mod tests { assert_eq!(node1a.hashes.len(), 2); let (nibbles2a, node2a) = account_updates.last().unwrap(); - assert_eq!(nibbles2a.inner[..], [0xB, 0x0]); + assert_eq!(nibbles2a[..], [0xB, 0x0]); assert_eq!(node2a.state_mask, TrieMask::new(0b10001)); assert_eq!(node2a.tree_mask, TrieMask::new(0b00000)); assert_eq!(node2a.hash_mask, TrieMask::new(0b10000)); @@ -963,7 +963,7 @@ mod tests { assert_eq!(storage_updates.len(), 1); let (nibbles3, node3) = storage_updates.first().unwrap(); - assert!(nibbles3.inner.is_empty()); + assert!(nibbles3.is_empty()); assert_eq!(node3.state_mask, TrieMask::new(0b1010)); assert_eq!(node3.tree_mask, TrieMask::new(0b0000)); assert_eq!(node3.hash_mask, TrieMask::new(0b0010)); @@ -1004,7 +1004,7 @@ mod tests { assert_eq!(account_updates.len(), 2); let (nibbles1b, node1b) = account_updates.first().unwrap(); - assert_eq!(nibbles1b.inner[..], [0xB]); + assert_eq!(nibbles1b[..], [0xB]); assert_eq!(node1b.state_mask, TrieMask::new(0b1011)); assert_eq!(node1b.tree_mask, TrieMask::new(0b0001)); assert_eq!(node1b.hash_mask, TrieMask::new(0b1011)); @@ -1014,7 +1014,7 @@ mod tests { assert_eq!(node1a.hashes[1], node1b.hashes[2]); let (nibbles2b, node2b) = account_updates.last().unwrap(); - assert_eq!(nibbles2b.inner[..], [0xB, 0x0]); + assert_eq!(nibbles2b[..], [0xB, 0x0]); assert_eq!(node2a, node2b); tx.commit().unwrap(); let tx = factory.provider_rw().unwrap(); @@ -1057,7 +1057,7 @@ mod tests { assert_eq!(account_updates.len(), 1); let (nibbles1c, node1c) = account_updates.first().unwrap(); - assert_eq!(nibbles1c.inner[..], [0xB]); + assert_eq!(nibbles1c[..], [0xB]); assert_eq!(node1c.state_mask, TrieMask::new(0b1011)); assert_eq!(node1c.tree_mask, TrieMask::new(0b0000)); @@ -1114,7 +1114,7 @@ mod tests { assert_eq!(account_updates.len(), 1); let (nibbles1d, node1d) = account_updates.first().unwrap(); - assert_eq!(nibbles1d.inner[..], [0xB]); + assert_eq!(nibbles1d[..], [0xB]); assert_eq!(node1d.state_mask, TrieMask::new(0b1011)); assert_eq!(node1d.tree_mask, TrieMask::new(0b0000)); @@ -1143,7 +1143,7 @@ mod tests { .iter() .filter_map(|entry| match entry { (TrieKey::AccountNode(nibbles), TrieOp::Update(node)) => { - Some((nibbles.inner[..].into(), node.clone())) + Some((nibbles.clone(), node.clone())) } _ => None, }) @@ -1170,7 +1170,7 @@ mod tests { let mut account_updates = HashMap::new(); for item in walker { let (key, node) = item.unwrap(); - account_updates.insert(key.inner[..].into(), node); + account_updates.insert(key, node); } assert_trie_updates(&account_updates); @@ -1231,7 +1231,7 @@ mod tests { .iter() .filter_map(|entry| match entry { (TrieKey::StorageNode(_, nibbles), TrieOp::Update(node)) => { - Some((nibbles.inner[..].into(), node.clone())) + Some((nibbles.clone().into(), node.clone())) } _ => None, }) @@ -1296,11 +1296,11 @@ mod tests { fn assert_trie_updates(account_updates: &HashMap) { assert_eq!(account_updates.len(), 2); - let node = account_updates.get(&vec![0x3].as_slice().into()).unwrap(); + let node = account_updates.get(&[0x3][..]).unwrap(); let expected = BranchNodeCompact::new(0b0011, 0b0001, 0b0000, vec![], None); assert_eq!(node, &expected); - let node = account_updates.get(&vec![0x3, 0x0, 0xA, 0xF].as_slice().into()).unwrap(); + let node = account_updates.get(&[0x3, 0x0, 0xA, 0xF][..]).unwrap(); assert_eq!(node.state_mask, TrieMask::new(0b101100000)); assert_eq!(node.tree_mask, TrieMask::new(0b000000000)); assert_eq!(node.hash_mask, TrieMask::new(0b001000000)); diff --git a/crates/trie/src/trie_cursor/account_cursor.rs b/crates/trie/src/trie_cursor/account_cursor.rs index 0fe241760a06..b98be8bd2ba3 100644 --- a/crates/trie/src/trie_cursor/account_cursor.rs +++ b/crates/trie/src/trie_cursor/account_cursor.rs @@ -1,7 +1,7 @@ use super::TrieCursor; use crate::updates::TrieKey; use reth_db::{cursor::DbCursorRO, tables, DatabaseError}; -use reth_primitives::trie::{BranchNodeCompact, StoredNibbles}; +use reth_primitives::trie::{BranchNodeCompact, Nibbles}; /// A cursor over the account trie. #[derive(Debug)] @@ -18,20 +18,20 @@ impl TrieCursor for AccountTrieCursor where C: DbCursorRO, { - type Key = StoredNibbles; + type Key = Nibbles; fn seek_exact( &mut self, key: Self::Key, ) -> Result, BranchNodeCompact)>, DatabaseError> { - Ok(self.0.seek_exact(key)?.map(|value| (value.0.inner.to_vec(), value.1))) + Ok(self.0.seek_exact(key)?.map(|value| (value.0.to_vec(), value.1))) } fn seek( &mut self, key: Self::Key, ) -> Result, BranchNodeCompact)>, DatabaseError> { - Ok(self.0.seek(key)?.map(|value| (value.0.inner.to_vec(), value.1))) + Ok(self.0.seek(key)?.map(|value| (value.0.to_vec(), value.1))) } fn current(&mut self) -> Result, DatabaseError> { @@ -80,13 +80,13 @@ mod tests { } let db_data = cursor.walk_range(..).unwrap().collect::, _>>().unwrap(); - assert_eq!(db_data[0].0.inner.to_vec(), data[0]); - assert_eq!(db_data[1].0.inner.to_vec(), data[1]); - assert_eq!(db_data[2].0.inner.to_vec(), data[2]); - assert_eq!(db_data[3].0.inner.to_vec(), data[3]); + assert_eq!(db_data[0].0.to_vec(), data[0]); + assert_eq!(db_data[1].0.to_vec(), data[1]); + assert_eq!(db_data[2].0.to_vec(), data[2]); + assert_eq!(db_data[3].0.to_vec(), data[3]); assert_eq!( - cursor.seek(hex!("0303040f").to_vec().into()).unwrap().map(|(k, _)| k.inner.to_vec()), + cursor.seek(hex!("0303040f").to_vec().into()).unwrap().map(|(k, _)| k.to_vec()), Some(data[1].clone()) ); } diff --git a/crates/trie/src/trie_cursor/storage_cursor.rs b/crates/trie/src/trie_cursor/storage_cursor.rs index 19fe1b281914..04b82ecbe472 100644 --- a/crates/trie/src/trie_cursor/storage_cursor.rs +++ b/crates/trie/src/trie_cursor/storage_cursor.rs @@ -38,7 +38,7 @@ where .cursor .seek_by_key_subkey(self.hashed_address, key.clone())? .filter(|e| e.nibbles == key) - .map(|value| (value.nibbles.inner.to_vec(), value.node))) + .map(|value| (value.nibbles.to_vec(), value.node))) } fn seek( @@ -48,7 +48,7 @@ where Ok(self .cursor .seek_by_key_subkey(self.hashed_address, key)? - .map(|value| (value.nibbles.inner.to_vec(), value.node))) + .map(|value| (value.nibbles.to_vec(), value.node))) } fn current(&mut self) -> Result, DatabaseError> { diff --git a/crates/trie/src/trie_cursor/subnode.rs b/crates/trie/src/trie_cursor/subnode.rs index a0e30dd93790..d49ccfe7f5dc 100644 --- a/crates/trie/src/trie_cursor/subnode.rs +++ b/crates/trie/src/trie_cursor/subnode.rs @@ -39,14 +39,14 @@ impl From for CursorSubNode { Some(n) => n as i8, None => -1, }; - Self { key: Nibbles::from_hex(value.key), nibble, node: value.node } + Self { key: Nibbles::new_unchecked(value.key), nibble, node: value.node } } } impl From for StoredSubNode { fn from(value: CursorSubNode) -> Self { let nibble = if value.nibble >= 0 { Some(value.nibble as u8) } else { None }; - Self { key: value.key.hex_data.to_vec(), nibble, node: value.node } + Self { key: value.key.to_vec(), nibble, node: value.node } } } @@ -67,7 +67,7 @@ impl CursorSubNode { pub fn full_key(&self) -> Nibbles { let mut out = self.key.clone(); if self.nibble >= 0 { - out.extend([self.nibble as u8]); + out.push(self.nibble as u8); } out } diff --git a/crates/trie/src/updates.rs b/crates/trie/src/updates.rs index 11cfb82204a3..9a3da6c54268 100644 --- a/crates/trie/src/updates.rs +++ b/crates/trie/src/updates.rs @@ -5,7 +5,7 @@ use reth_db::{ transaction::{DbTx, DbTxMut}, }; use reth_primitives::{ - trie::{BranchNodeCompact, Nibbles, StorageTrieEntry, StoredNibbles, StoredNibblesSubKey}, + trie::{BranchNodeCompact, Nibbles, StorageTrieEntry, StoredNibblesSubKey}, B256, }; use std::collections::{hash_map::IntoIter, HashMap}; @@ -14,7 +14,7 @@ use std::collections::{hash_map::IntoIter, HashMap}; #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum TrieKey { /// A node in the account trie. - AccountNode(StoredNibbles), + AccountNode(Nibbles), /// A node in the storage trie. StorageNode(B256, StoredNibblesSubKey), /// Storage trie of an account. @@ -78,9 +78,11 @@ impl TrieUpdates { /// Extend the updates with account trie updates. pub fn extend_with_account_updates(&mut self, updates: HashMap) { - self.extend(updates.into_iter().map(|(nibbles, node)| { - (TrieKey::AccountNode(nibbles.hex_data.to_vec().into()), TrieOp::Update(node)) - })); + self.extend( + updates + .into_iter() + .map(|(nibbles, node)| (TrieKey::AccountNode(nibbles), TrieOp::Update(node))), + ); } /// Extend the updates with storage trie updates. @@ -90,10 +92,7 @@ impl TrieUpdates { updates: HashMap, ) { self.extend(updates.into_iter().map(|(nibbles, node)| { - ( - TrieKey::StorageNode(hashed_address, nibbles.hex_data.to_vec().into()), - TrieOp::Update(node), - ) + (TrieKey::StorageNode(hashed_address, nibbles.into()), TrieOp::Update(node)) })); } @@ -122,7 +121,7 @@ impl TrieUpdates { } } TrieOp::Update(node) => { - if !nibbles.inner.is_empty() { + if !nibbles.is_empty() { account_trie_cursor.upsert(nibbles, node)?; } } @@ -136,7 +135,7 @@ impl TrieUpdates { TrieOp::Update(..) => unreachable!("Cannot update full storage trie."), }, TrieKey::StorageNode(hashed_address, nibbles) => { - if !nibbles.inner.is_empty() { + if !nibbles.is_empty() { // Delete the old entry if it exists. if storage_trie_cursor .seek_by_key_subkey(hashed_address, nibbles.clone())? diff --git a/crates/trie/src/walker.rs b/crates/trie/src/walker.rs index 4ad38fe190cc..54e7fc7ec270 100644 --- a/crates/trie/src/walker.rs +++ b/crates/trie/src/walker.rs @@ -122,16 +122,16 @@ impl TrieWalker { fn node(&mut self, exact: bool) -> Result, DatabaseError> { let key = self.key().expect("key must exist"); let entry = if exact { - self.cursor.seek_exact(key.hex_data.to_vec().into())? + self.cursor.seek_exact(key.to_vec().into())? } else { - self.cursor.seek(key.hex_data.to_vec().into())? + self.cursor.seek(key.to_vec().into())? }; if let Some((_, node)) = &entry { assert!(!node.state_mask.is_empty()); } - Ok(entry.map(|(k, v)| (Nibbles::from_hex(k), v))) + Ok(entry.map(|(k, v)| (Nibbles::new_unchecked(k), v))) } /// Consumes the next node in the trie, updating the stack. @@ -313,7 +313,7 @@ mod tests { // We're traversing the path in lexigraphical order. for expected in expected { let got = walker.advance().unwrap(); - assert_eq!(got.unwrap(), Nibbles::from(&expected[..])); + assert_eq!(got.unwrap(), Nibbles::new_unchecked(expected.clone())); } // There should be 8 paths traversed in total from 3 branches. @@ -361,26 +361,26 @@ mod tests { // No changes let mut cursor = TrieWalker::new(&mut trie, Default::default()); - assert_eq!(cursor.key(), Some(Nibbles::from_hex(vec![]))); // root + assert_eq!(cursor.key(), Some(Nibbles::new_unchecked([]))); // root assert!(cursor.can_skip_current_node); // due to root_hash cursor.advance().unwrap(); // skips to the end of trie assert_eq!(cursor.key(), None); // We insert something that's not part of the existing trie/prefix. let mut changed = PrefixSetMut::default(); - changed.insert(&[0xF, 0x1]); + changed.insert(Nibbles::new_unchecked([0xF, 0x1])); let mut cursor = TrieWalker::new(&mut trie, changed.freeze()); // Root node - assert_eq!(cursor.key(), Some(Nibbles::from_hex(vec![]))); + assert_eq!(cursor.key(), Some(Nibbles::new_unchecked([]))); // 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(), Some(Nibbles::from_hex(vec![0x2]))); + assert_eq!(cursor.key(), Some(Nibbles::new_unchecked([0x2]))); cursor.advance().unwrap(); - assert_eq!(cursor.key(), Some(Nibbles::from_hex(vec![0x2, 0x1]))); + assert_eq!(cursor.key(), Some(Nibbles::new_unchecked([0x2, 0x1]))); cursor.advance().unwrap(); - assert_eq!(cursor.key(), Some(Nibbles::from_hex(vec![0x4]))); + assert_eq!(cursor.key(), Some(Nibbles::new_unchecked([0x4]))); cursor.advance().unwrap(); assert_eq!(cursor.key(), None); // the end of trie diff --git a/docs/design/database.md b/docs/design/database.md index 4c51b613e02b..42ec8ba56036 100644 --- a/docs/design/database.md +++ b/docs/design/database.md @@ -113,7 +113,7 @@ HashedStorage { U256 StorageValue } AccountsTrie { - StoredNibbles Nibbles "PK" + Nibbles "PK" BranchNodeCompact Node } StoragesTrie {