use crate::util;
use alloc::{collections::BTreeMap, vec::Vec};
use core::ops::Bound;
mod nibble;
pub mod branch_search;
pub mod calculate_root;
pub mod minimize_proof;
pub mod prefix_proof;
pub mod proof_decode;
pub mod proof_encode;
pub mod trie_node;
pub mod trie_structure;
use alloc::collections::BTreeSet;
pub use nibble::{
BytesToNibbles, Nibble, NibbleFromU8Error, all_nibbles, bytes_to_nibbles,
nibbles_to_bytes_prefix_extend, nibbles_to_bytes_suffix_extend, nibbles_to_bytes_truncate,
};
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum TrieEntryVersion {
V0,
V1,
}
impl TryFrom<u8> for TrieEntryVersion {
type Error = ();
fn try_from(value: u8) -> Result<Self, Self::Error> {
match value {
0 => Ok(TrieEntryVersion::V0),
1 => Ok(TrieEntryVersion::V1),
_ => Err(()),
}
}
}
impl From<TrieEntryVersion> for u8 {
fn from(v: TrieEntryVersion) -> u8 {
match v {
TrieEntryVersion::V0 => 0,
TrieEntryVersion::V1 => 1,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum HashFunction {
Blake2,
Keccak256,
}
pub const EMPTY_BLAKE2_TRIE_MERKLE_VALUE: [u8; 32] = [
3, 23, 10, 46, 117, 151, 183, 183, 227, 216, 76, 5, 57, 29, 19, 154, 98, 177, 87, 231, 135,
134, 216, 192, 130, 242, 157, 207, 76, 17, 19, 20,
];
pub const EMPTY_KECCAK256_TRIE_MERKLE_VALUE: [u8; 32] = [
188, 54, 120, 158, 122, 30, 40, 20, 54, 70, 66, 41, 130, 143, 129, 125, 102, 18, 247, 180, 119,
214, 101, 145, 255, 150, 169, 224, 100, 188, 201, 138,
];
pub fn trie_root(
version: TrieEntryVersion,
hash_function: HashFunction,
unordered_entries: &[(impl AsRef<[u8]>, impl AsRef<[u8]>)],
) -> [u8; 32] {
let ordered_entries = unordered_entries
.iter()
.map(|(k, v)| (k.as_ref(), v.as_ref()))
.collect::<BTreeMap<_, _>>();
let mut calculation = calculate_root::root_merkle_value(hash_function);
loop {
match calculation {
calculate_root::RootMerkleValueCalculation::Finished { hash } => return hash,
calculate_root::RootMerkleValueCalculation::StorageValue(storage_value) => {
let val = ordered_entries.get(&storage_value.key().collect::<Vec<_>>()[..]);
calculation = storage_value.inject(val.map(|v| (v, version)));
}
calculate_root::RootMerkleValueCalculation::NextKey(next_key) => {
let key = next_key
.key_before()
.chain(next_key.or_equal().then_some(0))
.collect::<Vec<_>>();
let result = ordered_entries
.range(&key[..]..)
.next()
.filter(|(k, _)| {
let mut k = k.iter();
let mut p = next_key.prefix();
loop {
match (k.next(), p.next()) {
(Some(a), Some(b)) if *a == b => {}
(Some(_), Some(_)) => break false,
(Some(_), None) => break true,
(None, Some(_)) => break false,
(None, None) => break true,
}
}
})
.map(|(k, _)| *k);
calculation = next_key.inject_key(result.map(|s| s.iter().copied()));
}
}
}
}
pub fn ordered_root(
version: TrieEntryVersion,
hash_function: HashFunction,
entries: &[impl AsRef<[u8]>],
) -> [u8; 32] {
const USIZE_COMPACT_BYTES: usize = 1 + (usize::BITS as usize) / 8;
let trie_keys = (0..entries.len())
.map(|num| util::encode_scale_compact_usize(num).as_ref().to_vec())
.collect::<BTreeSet<_>>();
let mut calculation = calculate_root::root_merkle_value(hash_function);
loop {
match calculation {
calculate_root::RootMerkleValueCalculation::Finished { hash, .. } => {
return hash;
}
calculate_root::RootMerkleValueCalculation::NextKey(next_key) => {
let key_before = next_key.key_before().collect::<Vec<_>>();
let lower_bound = if next_key.or_equal() {
Bound::Included(key_before)
} else {
Bound::Excluded(key_before)
};
let k = trie_keys
.range((lower_bound, Bound::Unbounded))
.next()
.filter(|k| {
k.iter()
.copied()
.zip(next_key.prefix())
.all(|(a, b)| a == b)
});
calculation = next_key.inject_key(k.map(|k| k.iter().copied()));
}
calculate_root::RootMerkleValueCalculation::StorageValue(value_req) => {
let key = value_req
.key()
.collect::<arrayvec::ArrayVec<u8, USIZE_COMPACT_BYTES>>();
let value = match nom::Parser::parse(
&mut nom::combinator::all_consuming(
util::nom_scale_compact_usize::<nom::error::Error<&[u8]>>,
),
&key,
) {
Ok((_, key)) => entries.get(key).map(move |v| (v, version)),
Err(_) => None,
};
calculation = value_req.inject(value);
}
}
}
}
#[cfg(test)]
mod tests {
use super::{HashFunction, trie_node};
use core::iter;
#[test]
fn empty_trie_blake2() {
let calculated_through_function = *<&[u8; 32]>::try_from(
trie_node::calculate_merkle_value(
trie_node::Decoded {
children: [None::<&'static [u8]>; 16],
partial_key: iter::empty(),
storage_value: trie_node::StorageValue::None,
},
HashFunction::Blake2,
true,
)
.unwrap()
.as_ref(),
)
.unwrap();
let calculated_manually = blake2_rfc::blake2b::blake2b(32, &[], &[0x0]);
assert_eq!(calculated_through_function, calculated_manually.as_bytes());
assert_eq!(
calculated_through_function,
super::EMPTY_BLAKE2_TRIE_MERKLE_VALUE
);
}
#[test]
fn empty_trie_keccak256() {
let calculated_through_function = *<&[u8; 32]>::try_from(
trie_node::calculate_merkle_value(
trie_node::Decoded {
children: [None::<&'static [u8]>; 16],
partial_key: iter::empty(),
storage_value: trie_node::StorageValue::None,
},
HashFunction::Keccak256,
true,
)
.unwrap()
.as_ref(),
)
.unwrap();
let calculated_manually = <sha3::Keccak256 as sha3::Digest>::digest(&[0x0]);
assert_eq!(calculated_through_function, calculated_manually.as_ref());
assert_eq!(
calculated_through_function,
super::EMPTY_KECCAK256_TRIE_MERKLE_VALUE
);
}
#[test]
fn trie_root_example_v0_blake2() {
let obtained = super::trie_root(
super::TrieEntryVersion::V0,
super::HashFunction::Blake2,
&[(&b"foo"[..], &b"bar"[..]), (&b"foobar"[..], &b"baz"[..])],
);
assert_eq!(
obtained,
[
166, 24, 32, 181, 251, 169, 176, 26, 238, 16, 181, 187, 216, 74, 234, 128, 184, 35,
3, 24, 197, 232, 202, 20, 185, 164, 148, 12, 118, 224, 152, 21
]
);
}
#[test]
fn trie_root_example_v0_keccak() {
let obtained = super::trie_root(
super::TrieEntryVersion::V0,
super::HashFunction::Keccak256,
&[(&b"foo"[..], &b"bar"[..]), (&b"foobar"[..], &b"baz"[..])],
);
assert_eq!(
obtained,
[
109, 13, 46, 4, 44, 192, 37, 121, 213, 230, 248, 34, 108, 36, 86, 23, 164, 52, 162,
165, 248, 111, 236, 65, 142, 71, 118, 196, 44, 205, 139, 145
]
);
}
#[test]
fn trie_root_example_v1_blake2() {
let obtained = super::trie_root(
super::TrieEntryVersion::V1,
super::HashFunction::Blake2,
&[
(&b"bar"[..], &b"foo"[..]),
(&b"barfoo"[..], &b"hello"[..]),
(&b"anotheritem"[..], &b"anothervalue"[..]),
],
);
assert_eq!(
obtained,
[
68, 24, 7, 195, 69, 202, 122, 223, 136, 189, 33, 171, 27, 60, 186, 219, 21, 97,
106, 187, 137, 22, 126, 185, 254, 40, 93, 213, 206, 205, 4, 200
]
);
}
#[test]
fn trie_root_example_v1_keccak() {
let obtained = super::trie_root(
super::TrieEntryVersion::V1,
super::HashFunction::Keccak256,
&[
(&b"bar"[..], &b"foo"[..]),
(&b"barfoo"[..], &b"hello"[..]),
(&b"anotheritem"[..], &b"anothervalue"[..]),
],
);
assert_eq!(
obtained,
[
163, 182, 101, 58, 113, 93, 97, 19, 25, 39, 58, 170, 167, 225, 212, 187, 157, 3,
230, 21, 92, 129, 196, 38, 212, 190, 49, 103, 242, 0, 4, 65
]
);
}
}