#![cfg_attr(not(feature = "std"), no_std)]
#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(feature = "std")]
mod rstd {
pub use std::vec::Vec;
pub use std::cmp;
pub use std::collections::{BTreeMap, VecDeque};
}
#[cfg(not(feature = "std"))]
mod rstd {
pub use core::cmp;
pub use alloc::collections::{BTreeMap, VecDeque};
pub use alloc::vec::Vec;
}
use self::rstd::*;
pub use hash_db::Hasher;
pub trait TrieStream {
fn new() -> Self;
fn append_empty_data(&mut self);
fn begin_branch(
&mut self,
maybe_key: Option<&[u8]>,
maybe_value: Option<&[u8]>,
has_children: impl Iterator<Item = bool>,
);
fn append_empty_child(&mut self) {}
fn end_branch(&mut self, _value: Option<&[u8]>) {}
fn append_leaf(&mut self, key: &[u8], value: &[u8]);
fn append_extension(&mut self, key: &[u8]);
fn append_substream<H: Hasher>(&mut self, other: Self);
fn out(self) -> Vec<u8>;
}
fn shared_prefix_length<T: Eq>(first: &[T], second: &[T]) -> usize {
first.iter()
.zip(second.iter())
.position(|(f, s)| f != s)
.unwrap_or_else(|| cmp::min(first.len(), second.len()))
}
pub fn trie_root<H, S, I, A, B>(input: I) -> H::Out where
I: IntoIterator<Item = (A, B)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>,
H: Hasher,
S: TrieStream,
{
trie_root_inner::<H, S, I, A, B>(input, false)
}
fn trie_root_inner<H, S, I, A, B>(input: I, no_extension: bool) -> H::Out where
I: IntoIterator<Item = (A, B)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>,
H: Hasher,
S: TrieStream,
{
let input = input
.into_iter()
.collect::<BTreeMap<_, _>>();
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);
for k in input.keys() {
for &b in k.as_ref() {
nibbles.push(b >> 4);
nibbles.push(b & 0x0F);
}
lens.push(nibbles.len());
}
let input = input.into_iter().zip(lens.windows(2))
.map(|((_, v), w)| (&nibbles[w[0]..w[1]], v))
.collect::<Vec<_>>();
let mut stream = S::new();
build_trie::<H, S, _, _>(&input, 0, &mut stream, no_extension);
H::hash(&stream.out())
}
pub fn trie_root_no_extension<H, S, I, A, B>(input: I) -> H::Out where
I: IntoIterator<Item = (A, B)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>,
H: Hasher,
S: TrieStream,
{
trie_root_inner::<H, S, I, A, B>(input, true)
}
pub fn unhashed_trie<H, S, I, A, B>(input: I) -> Vec<u8> where
I: IntoIterator<Item = (A, B)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>,
H: Hasher,
S: TrieStream,
{
unhashed_trie_inner::<H, S, I, A, B>(input, false)
}
fn unhashed_trie_inner<H, S, I, A, B>(input: I, no_extension: bool) -> Vec<u8> where
I: IntoIterator<Item = (A, B)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>,
H: Hasher,
S: TrieStream,
{
let input = input
.into_iter()
.collect::<BTreeMap<_, _>>();
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);
for k in input.keys() {
for &b in k.as_ref() {
nibbles.push(b >> 4);
nibbles.push(b & 0x0F);
}
lens.push(nibbles.len());
}
let input = input.into_iter().zip(lens.windows(2))
.map(|((_, v), w)| (&nibbles[w[0]..w[1]], v))
.collect::<Vec<_>>();
let mut stream = S::new();
build_trie::<H, S, _, _>(&input, 0, &mut stream, no_extension);
stream.out()
}
pub fn unhashed_trie_no_extension<H, S, I, A, B>(input: I) -> Vec<u8> where
I: IntoIterator<Item = (A, B)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>,
H: Hasher,
S: TrieStream,
{
unhashed_trie_inner::<H, S, I, A, B>(input, true)
}
pub fn sec_trie_root<H, S, I, A, B>(input: I) -> H::Out where
I: IntoIterator<Item = (A, B)>,
A: AsRef<[u8]>,
B: AsRef<[u8]>,
H: Hasher,
H::Out: Ord,
S: TrieStream,
{
trie_root::<H, S, _, _, _>(input.into_iter().map(|(k, v)| (H::hash(k.as_ref()), v)))
}
fn build_trie<H, S, A, B>(input: &[(A, B)], cursor: usize, stream: &mut S, no_extension: bool) where
A: AsRef<[u8]>,
B: AsRef<[u8]>,
H: Hasher,
S: TrieStream,
{
match input.len() {
0 => stream.append_empty_data(),
1 => stream.append_leaf(&input[0].0.as_ref()[cursor..], &input[0].1.as_ref() ),
_ => {
let (key, value) = (&input[0].0.as_ref(), input[0].1.as_ref());
let shared_nibble_count = input.iter().skip(1).fold(key.len(), |acc, &(ref k, _)| {
cmp::min( shared_prefix_length(key, k.as_ref()), acc )
});
let (cursor, o_branch_slice) = if no_extension {
if shared_nibble_count > cursor {
(shared_nibble_count, Some(&key[cursor..shared_nibble_count]))
} else {
(cursor, Some(&key[0..0]))
}
} else if shared_nibble_count > cursor {
stream.append_extension(&key[cursor..shared_nibble_count]);
build_trie_trampoline::<H, _, _, _>(
input,
shared_nibble_count,
stream,
no_extension,
);
return;
} else { (cursor, None) };
let value = if cursor == key.len() { Some(value) } else { None };
let mut shared_nibble_counts = [0usize; 16];
{
let mut begin = match value { None => 0, _ => 1 };
for i in 0..16 {
shared_nibble_counts[i] = input[begin..].iter()
.take_while(|(k, _)| k.as_ref()[cursor] == i as u8)
.count();
begin += shared_nibble_counts[i];
}
}
stream.begin_branch(o_branch_slice, value, shared_nibble_counts.iter().map(|&n| n > 0));
let mut begin = match value { None => 0, _ => 1 };
for &count in &shared_nibble_counts {
if count > 0 {
build_trie_trampoline::<H, S, _, _>(
&input[begin..(begin + count)],
cursor + 1,
stream,
no_extension,
);
begin += count;
} else {
stream.append_empty_child();
}
}
stream.end_branch(value);
}
}
}
fn build_trie_trampoline<H, S, A, B>(
input: &[(A, B)],
cursor: usize,
stream: &mut S,
no_extension: bool,
) where
A: AsRef<[u8]>,
B: AsRef<[u8]>,
H: Hasher,
S: TrieStream,
{
let mut substream = S::new();
build_trie::<H, _, _, _>(input, cursor, &mut substream, no_extension);
stream.append_substream::<H>(substream);
}