Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ The implementation comes in two formats:

- Trie DB (`trie-db` crate) which can be combined with a backend database to provide
a persistent trie structure whose contents can be modified and whose root hash
recalculated efficiently.
is recalculated efficiently.
- Trie Hash (`trie-hash` crate) which provides a closed-form function that accepts a
sorted enumeration of keys and values (exactly the format provided by
`BTreeMap<(&[u8], &[u8])>`) and provides a root calculated entirely in-memory and
Expand All @@ -27,7 +27,7 @@ In addition to these, several support crates are provided:
- `memory-db` crate, contains `MemoryDB`, an implementation of a `HashDB` using only
in in-memory map.
- `hash256-std-hasher` crate, an implementation of a `std::hash::Hasher` for 32-byte
keys that have already been hashed. Useful for `MemoryDB`.
keys that have already been hashed. Useful to build the backing `HashMap` for `MemoryDB`.

There are also three crates used only for testing:

Expand Down
2 changes: 1 addition & 1 deletion test-support/reference-trie/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ impl TrieStream for ReferenceTrieStream {
value.encode_to(&mut self.buffer);
}
}

fn append_extension(&mut self, key: &[u8]) {
self.buffer.extend(fuse_nibbles_node(key, false));
}
Expand Down
43 changes: 22 additions & 21 deletions trie-root/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,27 @@ extern crate keccak_hasher;

pub use hash_db::Hasher;

/// TODO: DOCUMENT!!!!
/// Byte-stream oriented trait for constructing closed-form tries.
pub trait TrieStream {
/// Construct a new `TrieStream`
fn new() -> Self;
/// Append an Empty node
fn append_empty_data(&mut self);
/// Start a new Branch node, possibly with a value; takes a list indicating
/// which slots in the Branch node has further child nodes.
fn begin_branch(&mut self, maybe_value: Option<&[u8]>, has_children: impl Iterator<Item = bool>);
// Append an empty child node. Optional.
fn append_empty_child(&mut self) {}
/// Wrap up a Branch node portion of a `TrieStream` and append the value
/// stored on the Branch (if any).
fn end_branch(&mut self, _value: Option<&[u8]>) {}
/// Append a Leaf node
fn append_leaf(&mut self, key: &[u8], value: &[u8]);
/// Append an Extension node
fn append_extension(&mut self, key: &[u8]);
/// Append a Branch of Extension substream
fn append_substream<H: Hasher>(&mut self, other: Self);
/// Return the finished `TrieStream` as a vector of bytes.
fn out(self) -> Vec<u8>;
}

Expand Down Expand Up @@ -93,6 +104,7 @@ pub fn trie_root<H, S, I, A, B>(input: I) -> H::Out where
.into_iter()
.collect::<BTreeMap<_, _>>();

// convert to nibbles
let mut nibbles = Vec::with_capacity(input.keys().map(|k| k.as_ref().len()).sum::<usize>() * 2);
let mut lens = Vec::with_capacity(input.len() + 1);
lens.push(0);
Expand Down Expand Up @@ -143,7 +155,6 @@ pub fn unhashed_trie<H, S, I, A, B>(input: I) -> Vec<u8> where
.map(|((_, v), w)| (&nibbles[w[0]..w[1]], v))
.collect::<Vec<_>>();

// println!("as nibbles: {:#x?}", input);
let mut stream = S::new();
build_trie::<H, S, _, _>(&input, 0, &mut stream);
stream.out()
Expand Down Expand Up @@ -193,18 +204,11 @@ fn build_trie<H, S, A, B>(input: &[(A, B)], cursor: usize, stream: &mut S) where
{
match input.len() {
// No input, just append empty data.
0 => {
// println!("[build_trie] no input; appending empty, cursor={}, stream={:?}", cursor, stream.as_raw());
stream.append_empty_data()
},
0 => stream.append_empty_data(),
// Leaf node; append the remainder of the key and the value. Done.
1 => {
// println!("[build_trie] appending leaf, cursor={}, stream={:?}, partial key={:?}", cursor, stream.as_raw(), &input[0].0.as_ref()[cursor..]);
// stream.append_leaf::<H>(&input[0].0.as_ref()[cursor..], &input[0].1.as_ref() )
stream.append_leaf(&input[0].0.as_ref()[cursor..], &input[0].1.as_ref() )
},
// We have multiple items in the input. We need to figure out if we
// should add an extension node or a branch node.
1 => stream.append_leaf(&input[0].0.as_ref()[cursor..], &input[0].1.as_ref() ),
// We have multiple items in the input. Figure out if we should add an
// extension node or a branch node.
_ => {
let (key, value) = (&input[0].0.as_ref(), input[0].1.as_ref());
// Count the number of nibbles in the other elements that are
Expand All @@ -218,10 +222,8 @@ fn build_trie<H, S, A, B>(input: &[(A, B)], cursor: usize, stream: &mut S) where
// of the path then recursively append the remainder of all items
// who had this partial key.
if shared_nibble_count > cursor {
// println!("[build_trie] appending ext and recursing, cursor={}, stream={:?}, partial key={:?}", cursor, stream.as_raw(), &key[cursor..shared_nibble_count]);
stream.append_extension(&key[cursor..shared_nibble_count]);
build_trie_trampoline::<H, _, _, _>(input, shared_nibble_count, stream);
// println!("[build_trie] returning after recursing, cursor={}, stream={:?}, partial key={:?}", cursor, stream.as_raw(), &key[cursor..shared_nibble_count]);
return;
}

Expand All @@ -232,10 +234,13 @@ fn build_trie<H, S, A, B>(input: &[(A, B)], cursor: usize, stream: &mut S) where
// attached to it.
let value = if cursor == key.len() { Some(value) } else { None };

// We need to know how many keys each of the children account for.
// We need to know how many key nibbles each of the children account for.
let mut shared_nibble_counts = [0usize; 16];
{
// Children keys begin at either index 1 or 0, depending on whether we have a value.
// If the Branch node has a value then the first of the input keys
// is exactly the key for that value and we don't care about it
// when finding shared nibbles for our child nodes. (We know it's
// the first of the input keys, because the input is sorted)
let mut begin = match value { None => 0, _ => 1 };
for i in 0..16 {
shared_nibble_counts[i] = input[begin..].iter()
Expand All @@ -253,18 +258,14 @@ fn build_trie<H, S, A, B>(input: &[(A, B)], cursor: usize, stream: &mut S) where
let mut begin = match value { None => 0, _ => 1 };
for &count in &shared_nibble_counts {
if count > 0 {
// println!("[build_trie] branch slot {}; recursing with cursor={}, begin={}, shared nibbles={}, input={:?}", i, cursor, begin, shared_nibble_count, &input[begin..(begin + shared_nibble_count)]);
build_trie_trampoline::<H, S, _, _>(&input[begin..(begin + count)], cursor + 1, stream);
begin += count;
} else {
stream.append_empty_child();
}
}

// println!("[build_trie] branch slot 17; cursor={}, appending value {:?}", cursor, value);
stream.end_branch(value);

// println!("[build_trie] ending branch node, cursor={}, stream={:?}", cursor, stream.as_raw());
}
}
}
Expand Down