feat(trie): convert vec to Bytes in Nibbles (#3120)

This commit is contained in:
Thomas Coratger
2023-06-13 13:49:05 +02:00
committed by GitHub
parent e43455c2c3
commit 0561675bb9
9 changed files with 46 additions and 30 deletions

View File

@ -54,7 +54,7 @@ pub struct HashBuilder {
impl From<HashBuilderState> 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<HashBuilderState> for HashBuilder {
impl From<HashBuilder> 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()

View File

@ -78,7 +78,7 @@ impl Compact for StoredNibblesSubKey {
)]
pub struct Nibbles {
/// The inner representation of the nibble sequence.
pub hex_data: Vec<u8>,
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<u8>) -> 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<T: AsRef<[u8]>>(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::<Vec<u8>>(),
),
}
}
/// 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<Nibbles> {
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);
}

View File

@ -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![]);

View File

@ -214,7 +214,7 @@ impl<DB: Database> Stage<DB> 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(),
);

View File

@ -34,7 +34,7 @@ impl From<MerkleCheckpoint> 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),
}
}
}

View File

@ -1331,11 +1331,11 @@ mod tests {
fn assert_trie_updates(account_updates: &HashMap<Nibbles, BranchNodeCompact>) {
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));

View File

@ -39,14 +39,14 @@ impl From<StoredSubNode> 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<CursorSubNode> 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 }
}
}

View File

@ -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<Nibbles, BranchNodeCompact>) {
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<Nibbles, BranchNodeCompact>,
) {
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),
)
}));
}

View File

@ -129,16 +129,16 @@ impl<'a, K: Key + From<Vec<u8>>, C: TrieCursor<K>> TrieWalker<'a, K, C> {
fn node(&mut self, exact: bool) -> Result<Option<(Nibbles, BranchNodeCompact)>, 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