From 0561675bb978e4023241a66806adaff4a951fd66 Mon Sep 17 00:00:00 2001 From: Thomas Coratger <60488569+tcoratger@users.noreply.github.com> Date: Tue, 13 Jun 2023 13:49:05 +0200 Subject: [PATCH] feat(trie): convert `vec` to `Bytes` in `Nibbles` (#3120) --- .../primitives/src/trie/hash_builder/mod.rs | 6 ++-- crates/primitives/src/trie/nibbles.rs | 29 +++++++++++++------ crates/primitives/src/trie/nodes/leaf.rs | 4 +-- crates/stages/src/stages/merkle.rs | 2 +- crates/trie/src/progress.rs | 2 +- crates/trie/src/trie.rs | 4 +-- crates/trie/src/trie_cursor/subnode.rs | 4 +-- crates/trie/src/updates.rs | 9 ++++-- crates/trie/src/walker.rs | 16 +++++----- 9 files changed, 46 insertions(+), 30 deletions(-) diff --git a/crates/primitives/src/trie/hash_builder/mod.rs b/crates/primitives/src/trie/hash_builder/mod.rs index 34b3b702fd..90c9210e0d 100644 --- a/crates/primitives/src/trie/hash_builder/mod.rs +++ b/crates/primitives/src/trie/hash_builder/mod.rs @@ -54,7 +54,7 @@ pub struct HashBuilder { impl From for HashBuilder { fn from(state: HashBuilderState) -> Self { Self { - key: Nibbles::from(state.key), + key: Nibbles::from_hex(state.key), stack: state.stack, value: state.value, groups: state.groups, @@ -70,7 +70,7 @@ impl From for HashBuilder { impl From for HashBuilderState { fn from(state: HashBuilder) -> Self { Self { - key: state.key.hex_data, + key: state.key.hex_data.to_vec(), stack: state.stack, value: state.value, groups: state.groups, @@ -153,7 +153,7 @@ impl HashBuilder { // Clears the internal state if !self.key.is_empty() { self.update(&Nibbles::default()); - self.key.clear(); + self.key.hex_data.0.clear(); self.value = HashBuilderValue::Bytes(vec![]); } self.current_root() diff --git a/crates/primitives/src/trie/nibbles.rs b/crates/primitives/src/trie/nibbles.rs index 9842b7f980..3bbf74a8b7 100644 --- a/crates/primitives/src/trie/nibbles.rs +++ b/crates/primitives/src/trie/nibbles.rs @@ -78,7 +78,7 @@ impl Compact for StoredNibblesSubKey { )] pub struct Nibbles { /// The inner representation of the nibble sequence. - pub hex_data: Vec, + pub hex_data: Bytes, } impl From<&[u8]> for Nibbles { @@ -102,13 +102,20 @@ impl std::fmt::Debug for Nibbles { impl Nibbles { /// Creates a new [Nibbles] instance from bytes. pub fn from_hex(hex: Vec) -> Self { - Nibbles { hex_data: hex } + Nibbles { hex_data: Bytes::from(hex) } } /// 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. pub fn unpack>(data: T) -> Self { - Nibbles { hex_data: data.as_ref().iter().flat_map(|item| [item / 16, item % 16]).collect() } + Nibbles { + hex_data: Bytes::from( + data.as_ref() + .iter() + .flat_map(|item| vec![item / 16, item % 16]) + .collect::>(), + ), + } } /// Packs the nibbles stored in the struct into a byte vector. @@ -202,13 +209,13 @@ impl Nibbles { /// Increments the nibble sequence by one. pub fn increment(&self) -> Option { - let mut incremented = self.hex_data.clone(); + let mut incremented = self.hex_data.to_vec(); for nibble in incremented.iter_mut().rev() { assert!(*nibble < 0x10); if *nibble < 0xf { *nibble += 1; - return Some(Nibbles::from(incremented)) + return Some(Nibbles::from_hex(incremented)) } else { *nibble = 0; } @@ -269,12 +276,16 @@ impl Nibbles { /// Extend the current nibbles with another nibbles. pub fn extend(&mut self, b: impl AsRef<[u8]>) { - self.hex_data.extend_from_slice(b.as_ref()); + // self.hex_data.extend_from_slice(b.as_ref()); + + let mut bytes = self.hex_data.to_vec(); + bytes.extend_from_slice(b.as_ref()); + self.hex_data = bytes.into(); } /// Truncate the current nibbles to the given length. pub fn truncate(&mut self, len: usize) { - self.hex_data.truncate(len) + self.hex_data.0.truncate(len) } } @@ -286,7 +297,7 @@ mod tests { #[test] fn hashed_regression() { let nibbles = hex::decode("05010406040a040203030f010805020b050c04070003070e0909070f010b0a0805020301070c0a0902040b0f000f0006040a04050f020b090701000a0a040b").unwrap(); - let nibbles = Nibbles::from(nibbles); + let nibbles = Nibbles::from_hex(nibbles); let path = nibbles.encode_path_leaf(true); let expected = hex::decode("351464a4233f1852b5c47037e997f1ba852317ca924bf0f064a45f2b9710aa4b") @@ -304,7 +315,7 @@ mod tests { (vec![0xa, 0xb, 0x2, 0x0], vec![0xab, 0x20]), (vec![0xa, 0xb, 0x2, 0x7], vec![0xab, 0x27]), ] { - let nibbles = Nibbles::from(input); + let nibbles = Nibbles::from_hex(input); let encoded = nibbles.pack(); assert_eq!(encoded, expected); } diff --git a/crates/primitives/src/trie/nodes/leaf.rs b/crates/primitives/src/trie/nodes/leaf.rs index cbf3ecd551..5ccbcfb0c3 100644 --- a/crates/primitives/src/trie/nodes/leaf.rs +++ b/crates/primitives/src/trie/nodes/leaf.rs @@ -59,7 +59,7 @@ mod tests { // From manual regression test #[test] fn encode_leaf_node_nibble() { - let nibble = Nibbles { hex_data: hex!("0604060f").to_vec() }; + let nibble = Nibbles { hex_data: hex!("0604060f").into() }; let encoded = nibble.encode_path_leaf(true); let expected = hex!("20646f").to_vec(); assert_eq!(encoded, expected); @@ -67,7 +67,7 @@ mod tests { #[test] fn rlp_leaf_node_roundtrip() { - let nibble = Nibbles { hex_data: hex!("0604060f").to_vec() }; + let nibble = Nibbles { hex_data: hex!("0604060f").into() }; let val = hex!("76657262").to_vec(); let leaf = LeafNode::new(&nibble, &val); let rlp = leaf.rlp(&mut vec![]); diff --git a/crates/stages/src/stages/merkle.rs b/crates/stages/src/stages/merkle.rs index 9201815789..bfb0344e43 100644 --- a/crates/stages/src/stages/merkle.rs +++ b/crates/stages/src/stages/merkle.rs @@ -214,7 +214,7 @@ impl Stage for MerkleStage { let checkpoint = MerkleCheckpoint::new( to_block, state.last_account_key, - state.last_walker_key.hex_data, + state.last_walker_key.hex_data.to_vec(), state.walker_stack.into_iter().map(StoredSubNode::from).collect(), state.hash_builder.into(), ); diff --git a/crates/trie/src/progress.rs b/crates/trie/src/progress.rs index 128fa3f50c..36b96643dc 100644 --- a/crates/trie/src/progress.rs +++ b/crates/trie/src/progress.rs @@ -34,7 +34,7 @@ impl From for IntermediateStateRootState { hash_builder: HashBuilder::from(value.state), walker_stack: value.walker_stack.into_iter().map(CursorSubNode::from).collect(), last_account_key: value.last_account_key, - last_walker_key: Nibbles::from(value.last_walker_key), + last_walker_key: Nibbles::from_hex(value.last_walker_key), } } } diff --git a/crates/trie/src/trie.rs b/crates/trie/src/trie.rs index 0c9b1b4537..1ad0baa6ea 100644 --- a/crates/trie/src/trie.rs +++ b/crates/trie/src/trie.rs @@ -1331,11 +1331,11 @@ mod tests { fn assert_trie_updates(account_updates: &HashMap) { assert_eq!(account_updates.len(), 2); - let node = account_updates.get(&vec![0x3].into()).unwrap(); + let node = account_updates.get(&vec![0x3].as_slice().into()).unwrap(); let expected = BranchNodeCompact::new(0b0011, 0b0001, 0b0000, vec![], None); assert_eq!(node, &expected); - let node = account_updates.get(&vec![0x3, 0x0, 0xA, 0xF].into()).unwrap(); + let node = account_updates.get(&vec![0x3, 0x0, 0xA, 0xF].as_slice().into()).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/subnode.rs b/crates/trie/src/trie_cursor/subnode.rs index 368af22865..fb82dc5333 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(value.key), nibble, node: value.node } + Self { key: Nibbles::from_hex(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, nibble, node: value.node } + Self { key: value.key.hex_data.to_vec(), nibble, node: value.node } } } diff --git a/crates/trie/src/updates.rs b/crates/trie/src/updates.rs index e3fe3e311d..49ab105f00 100644 --- a/crates/trie/src/updates.rs +++ b/crates/trie/src/updates.rs @@ -77,20 +77,25 @@ impl TrieUpdates { } /// Extend the updates with account trie updates. + #[allow(clippy::mutable_key_type)] pub fn extend_with_account_updates(&mut self, updates: HashMap) { self.extend(updates.into_iter().map(|(nibbles, node)| { - (TrieKey::AccountNode(nibbles.hex_data.into()), TrieOp::Update(node)) + (TrieKey::AccountNode(nibbles.hex_data.to_vec().into()), TrieOp::Update(node)) })); } /// Extend the updates with storage trie updates. + #[allow(clippy::mutable_key_type)] pub fn extend_with_storage_updates( &mut self, hashed_address: H256, updates: HashMap, ) { self.extend(updates.into_iter().map(|(nibbles, node)| { - (TrieKey::StorageNode(hashed_address, nibbles.hex_data.into()), TrieOp::Update(node)) + ( + TrieKey::StorageNode(hashed_address, nibbles.hex_data.to_vec().into()), + TrieOp::Update(node), + ) })); } diff --git a/crates/trie/src/walker.rs b/crates/trie/src/walker.rs index f91f25843b..284ad4f2b2 100644 --- a/crates/trie/src/walker.rs +++ b/crates/trie/src/walker.rs @@ -129,16 +129,16 @@ impl<'a, K: Key + From>, C: TrieCursor> TrieWalker<'a, K, C> { 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.into())? + self.cursor.seek_exact(key.hex_data.to_vec().into())? } else { - self.cursor.seek(key.hex_data.into())? + self.cursor.seek(key.hex_data.to_vec().into())? }; if let Some((_, node)) = &entry { assert!(!node.state_mask.is_empty()); } - Ok(entry.map(|(k, v)| (Nibbles::from(k), v))) + Ok(entry.map(|(k, v)| (Nibbles::from_hex(k), v))) } /// Consumes the next node in the trie, updating the stack. @@ -374,7 +374,7 @@ mod tests { // No changes let mut cursor = TrieWalker::new(&mut trie, Default::default()); - assert_eq!(cursor.key(), Some(Nibbles::from(vec![]))); // root + assert_eq!(cursor.key(), Some(Nibbles::from_hex(vec![]))); // 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); @@ -385,15 +385,15 @@ mod tests { let mut cursor = TrieWalker::new(&mut trie, changed); // Root node - assert_eq!(cursor.key(), Some(Nibbles::from(vec![]))); + assert_eq!(cursor.key(), Some(Nibbles::from_hex(vec![]))); // 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(vec![0x2]))); + assert_eq!(cursor.key(), Some(Nibbles::from_hex(vec![0x2]))); cursor.advance().unwrap(); - assert_eq!(cursor.key(), Some(Nibbles::from(vec![0x2, 0x1]))); + assert_eq!(cursor.key(), Some(Nibbles::from_hex(vec![0x2, 0x1]))); cursor.advance().unwrap(); - assert_eq!(cursor.key(), Some(Nibbles::from(vec![0x4]))); + assert_eq!(cursor.key(), Some(Nibbles::from_hex(vec![0x4]))); cursor.advance().unwrap(); assert_eq!(cursor.key(), None); // the end of trie