diff --git a/crates/storage/trie/encoding.rs b/crates/storage/trie/encoding.rs new file mode 100644 index 000000000..ff3dba7b6 --- /dev/null +++ b/crates/storage/trie/encoding.rs @@ -0,0 +1,47 @@ +/// Converts a slice of compact-encoded nibbles into a byte slice +/// If the nibble slice has odd-length (aka the last byte will be a half byte) returns true else false +pub fn compact_nibbles_to_bytes(compact: &[u8]) -> (Vec, bool) { + // Convert compact nibbles to nibbles + let nibbles = compact_to_hex(compact); + // Convert nibbles to bytes, accouning for odd number of bytes + let mut last_is_half = false; + let bytes = nibbles + .chunks(2) + .map(|chunk| match chunk.len() { + 1 => { + last_is_half = true; + chunk[0] << 4 + } + // 2 + _ => chunk[0] << 4 | chunk[1], + }) + .collect::>(); + (bytes, last_is_half) +} + +// Code taken from https://github.com/ethereum/go-ethereum/blob/a1093d98eb3260f2abf340903c2d968b2b891c11/trie/encoding.go#L82 +fn compact_to_hex(compact: &[u8]) -> Vec { + if compact.is_empty() { + return vec![]; + } + let mut base = keybytes_to_hex(compact); + // delete terminator flag + if base[0] < 2 { + base = base[..base.len() - 1].to_vec(); + } + // apply odd flag + let chop = 2 - (base[0] & 1) as usize; + base[chop..].to_vec() +} + +// Code taken from https://github.com/ethereum/go-ethereum/blob/a1093d98eb3260f2abf340903c2d968b2b891c11/trie/encoding.go#L96 +fn keybytes_to_hex(keybytes: &[u8]) -> Vec { + let l = keybytes.len() * 2 + 1; + let mut nibbles = vec![0; l]; + for (i, b) in keybytes.iter().enumerate() { + nibbles[i * 2] = b / 16; + nibbles[i * 2 + 1] = b % 16; + } + nibbles[l - 1] = 16; + nibbles +} diff --git a/crates/storage/trie/trie.rs b/crates/storage/trie/trie.rs index 675702130..da498f798 100644 --- a/crates/storage/trie/trie.rs +++ b/crates/storage/trie/trie.rs @@ -1,4 +1,5 @@ mod db; +mod encoding; mod error; mod nibble; mod node; @@ -12,6 +13,7 @@ mod test_utils; use std::borrow::Cow; +use encoding::compact_nibbles_to_bytes; use ethereum_rust_rlp::constants::RLP_NULL; use ethereum_types::H256; use node::Node; @@ -228,23 +230,21 @@ impl Trie { return Ok(node.encode_raw(partial_path.offset())); } match node { - Node::Branch(branch_node) => { - match partial_path.next().map(usize::from) { - Some(idx) if idx < 16 => { - let child_hash = &branch_node.choices[idx]; - if child_hash.is_valid() { - let child_node = self - .state - .get_node(child_hash.clone())? - .expect("inconsistent internal tree structure"); - self.get_node_inner(child_node, partial_path, last_byte_is_half) - } else { - Ok(vec![]) - } + Node::Branch(branch_node) => match partial_path.next().map(usize::from) { + Some(idx) if idx < 16 => { + let child_hash = &branch_node.choices[idx]; + if child_hash.is_valid() { + let child_node = self + .state + .get_node(child_hash.clone())? + .expect("inconsistent internal tree structure"); + self.get_node_inner(child_node, partial_path, last_byte_is_half) + } else { + Ok(vec![]) } - _ => Ok(vec![]), } - } + _ => Ok(vec![]), + }, Node::Extension(extension_node) => { if partial_path.skip_prefix(&extension_node.prefix) && extension_node.child.is_valid() @@ -285,54 +285,6 @@ impl Trie { } } -/// Converts a slice of compact-encoded nibbles into a byte slice -/// If the nibble slice has odd-length (aka the last byte will be a half byte) returns true else false -fn compact_nibbles_to_bytes(compact: &Vec) -> (Vec, bool) { - // Convert compact nibbles to nibbles - let nibbles = compact_to_hex(compact); - // Convert nibbles to bytes, accouning for odd number of bytes - let mut last_is_half = false; - let bytes = nibbles - .chunks(2) - .map(|chunk| match chunk.len() { - 1 => { - last_is_half = true; - chunk[0] << 4 - } - // 2 - _ => chunk[0] << 4 | chunk[1], - }) - .collect::>(); - (bytes, last_is_half) -} - -// Code taken from https://github.com/ethereum/go-ethereum/blob/a1093d98eb3260f2abf340903c2d968b2b891c11/trie/encoding.go#L82 -fn compact_to_hex(compact: &Vec) -> Vec { - if compact.is_empty() { - return vec![]; - } - let mut base = keybytes_to_hex(compact); - // delete terminator flag - if base[0] < 2 { - base = base[..base.len() - 1].to_vec(); - } - // apply odd flag - let chop = 2 - (base[0] & 1) as usize; - base[chop..].to_vec() -} - -// Code taken from https://github.com/ethereum/go-ethereum/blob/a1093d98eb3260f2abf340903c2d968b2b891c11/trie/encoding.go#L96 -fn keybytes_to_hex(keybytes: &Vec) -> Vec { - let l = keybytes.len() * 2 + 1; - let mut nibbles = vec![0; l]; - for (i, b) in keybytes.into_iter().enumerate() { - nibbles[i * 2] = b / 16; - nibbles[i * 2 + 1] = b % 16; - } - nibbles[l - 1] = 16; - nibbles -} - impl IntoIterator for Trie { type Item = Node;