diff --git a/hashdb/Cargo.toml b/hashdb/Cargo.toml deleted file mode 100644 index 1ac6ef4..0000000 --- a/hashdb/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "hashdb" -version = "0.3.0" -authors = ["Parity Technologies "] -description = "trait for hash-keyed databases." -repository = "https://github.com/paritytech/parity-common" -license = "GPL-3.0" - -[dependencies] - -[features] -default = ["std"] -std = [] diff --git a/hashdb/README.md b/hashdb/README.md deleted file mode 100644 index 6af0246..0000000 --- a/hashdb/README.md +++ /dev/null @@ -1,7 +0,0 @@ -# HashDB -`HashDB` defines a common interface for databases of byte-slices keyed to their hash. It is generic over hash type through the `Hasher` trait. - -The `Hasher` trait can be used in a `no_std` context. - - -**This crate is deprecated in favor of ['hash-db'](https://crates.io/crates/hash-db)** diff --git a/hashdb/src/lib.rs b/hashdb/src/lib.rs deleted file mode 100644 index be96d68..0000000 --- a/hashdb/src/lib.rs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Database of byte-slices keyed to their hash. - -#![cfg_attr(not(feature = "std"), no_std)] - -#[cfg(feature = "std")] -extern crate core; - -#[cfg(feature = "std")] -#[cfg(feature = "std")] -use std::collections::HashMap; -use core::{fmt::Debug, hash::Hash}; - -/// Trait describing an object that can hash a slice of bytes. Used to abstract -/// other types over the hashing algorithm. Defines a single `hash` method and an -/// `Out` associated type with the necessary bounds. -pub trait Hasher: Sync + Send { - /// The output type of the `Hasher` - type Out: AsRef<[u8]> + AsMut<[u8]> + Default + Debug + PartialEq + Eq + Hash + Send + Sync + Clone + Copy; - /// What to use to build `HashMap`s with this `Hasher` - type StdHasher: Sync + Send + Default + core::hash::Hasher; - /// The length in bytes of the `Hasher` output - const LENGTH: usize; - - /// Compute the hash of the provided slice of bytes returning the `Out` type of the `Hasher` - fn hash(x: &[u8]) -> Self::Out; -} - -/// Trait modelling datastore keyed by a hash defined by the `Hasher`. -#[cfg(feature = "std")] -pub trait HashDB: Send + Sync + AsHashDB { - /// Get the keys in the database together with number of underlying references. - fn keys(&self) -> HashMap; - - /// Look up a given hash into the bytes that hash to it, returning None if the - /// hash is not known. - fn get(&self, key: &H::Out) -> Option; - - /// Check for the existance of a hash-key. - fn contains(&self, key: &H::Out) -> bool; - - /// Insert a datum item into the DB and return the datum's hash for a later lookup. Insertions - /// are counted and the equivalent number of `remove()`s must be performed before the data - /// is considered dead. - fn insert(&mut self, value: &[u8]) -> H::Out; - - /// Like `insert()`, except you provide the key and the data is all moved. - fn emplace(&mut self, key: H::Out, value: T); - - /// Remove a datum previously inserted. Insertions can be "owed" such that the same number of `insert()`s may - /// happen without the data being eventually being inserted into the DB. It can be "owed" more than once. - fn remove(&mut self, key: &H::Out); -} - -/// Upcast trait. -#[cfg(feature = "std")] -pub trait AsHashDB { - /// Perform upcast to HashDB for anything that derives from HashDB. - fn as_hashdb(&self) -> &HashDB; - /// Perform mutable upcast to HashDB for anything that derives from HashDB. - fn as_hashdb_mut(&mut self) -> &mut HashDB; -} - -// NOTE: There used to be a `impl AsHashDB for T` but that does not work with generics. See https://stackoverflow.com/questions/48432842/implementing-a-trait-for-reference-and-non-reference-types-causes-conflicting-im -// This means we need concrete impls of AsHashDB in several places, which somewhat defeats the point of the trait. -#[cfg(feature = "std")] -impl<'a, H: Hasher, T> AsHashDB for &'a mut HashDB { - fn as_hashdb(&self) -> &HashDB { &**self } - fn as_hashdb_mut(&mut self) -> &mut HashDB { &mut **self } -} diff --git a/memorydb/Cargo.toml b/memorydb/Cargo.toml deleted file mode 100644 index 91496c4..0000000 --- a/memorydb/Cargo.toml +++ /dev/null @@ -1,19 +0,0 @@ -[package] -name = "memorydb" -version = "0.3.0" -authors = ["Parity Technologies "] -description = "in-memory implementation of hashdb" -repository = "https://github.com/paritytech/parity-common" -license = "GPL-3.0" - -[dependencies] -heapsize = "0.4" -hashdb = { version = "0.3.0", path = "../hashdb" } -plain_hasher = { version = "0.2", path = "../plain_hasher", default-features = false } -rlp = { version = "0.3.0", path = "../rlp", default-features = false } - -[dev-dependencies] -tiny-keccak = "1.4.2" -ethereum-types = "0.4" -keccak-hasher = { version = "0.1", path = "../test-support/keccak-hasher" } -keccak-hash = { version = "0.1", path = "../keccak-hash" } diff --git a/memorydb/README.md b/memorydb/README.md deleted file mode 100644 index 38ac6fa..0000000 --- a/memorydb/README.md +++ /dev/null @@ -1,3 +0,0 @@ -MemoryDB is a reference counted memory-based [`HashDB`](https://github.com/paritytech/parity-common/tree/master/hashdb) implementation backed by a `HashMap`. - -**This crate is deprecated in favor of ['memory-db'](https://crates.io/crates/hash-db)** diff --git a/memorydb/benches/memdb.rs b/memorydb/benches/memdb.rs deleted file mode 100644 index 8bb8162..0000000 --- a/memorydb/benches/memdb.rs +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -#![feature(test)] - -extern crate hashdb; -extern crate memorydb; -extern crate keccak_hasher; -extern crate keccak_hash; -extern crate rlp; -extern crate test; - -use memorydb::MemoryDB; -use keccak_hasher::KeccakHasher; -use hashdb::{HashDB, Hasher}; -use keccak_hash::KECCAK_NULL_RLP; -use rlp::NULL_RLP; -use test::{Bencher, black_box}; - - -#[bench] -fn instantiation(b: &mut Bencher) { - b.iter(|| { - MemoryDB::>::new(); - }) -} - -#[bench] -fn compare_to_null_embedded_in_struct(b: &mut Bencher) { - struct X {a_hash: ::Out}; - let x = X {a_hash: KeccakHasher::hash(&NULL_RLP)}; - let key = KeccakHasher::hash(b"abc"); - - b.iter(|| { - black_box(key == x.a_hash); - }) -} - -#[bench] -fn compare_to_null_in_const(b: &mut Bencher) { - let key = KeccakHasher::hash(b"abc"); - - b.iter(|| { - black_box(key == KECCAK_NULL_RLP); - }) -} - -#[bench] -fn contains_with_non_null_key(b: &mut Bencher) { - let mut m = MemoryDB::>::new(); - let key = KeccakHasher::hash(b"abc"); - m.insert(b"abcefghijklmnopqrstuvxyz"); - b.iter(|| { - m.contains(&key); - }) -} - -#[bench] -fn contains_with_null_key(b: &mut Bencher) { - let mut m = MemoryDB::>::new(); - let null_key = KeccakHasher::hash(&NULL_RLP); - m.insert(b"abcefghijklmnopqrstuvxyz"); - b.iter(|| { - m.contains(&null_key); - }) -} diff --git a/memorydb/src/lib.rs b/memorydb/src/lib.rs deleted file mode 100644 index 4567857..0000000 --- a/memorydb/src/lib.rs +++ /dev/null @@ -1,397 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Reference-counted memory-based `HashDB` implementation. -extern crate hashdb; -extern crate heapsize; -extern crate rlp; -#[cfg(test)] extern crate keccak_hasher; -#[cfg(test)] extern crate tiny_keccak; -#[cfg(test)] extern crate ethereum_types; - -use hashdb::{HashDB, Hasher as KeyHasher, AsHashDB}; -use heapsize::HeapSizeOf; -use rlp::NULL_RLP; -use std::collections::hash_map::Entry; -use std::collections::HashMap; -use std::hash; -use std::mem; - -// Backing `HashMap` parametrized with a `Hasher` for the keys `Hasher::Out` and the `Hasher::StdHasher` -// as hash map builder. -type FastMap = HashMap<::Out, T, hash::BuildHasherDefault<::StdHasher>>; - -/// Reference-counted memory-based `HashDB` implementation. -/// -/// Use `new()` to create a new database. Insert items with `insert()`, remove items -/// with `remove()`, check for existence with `contains()` and lookup a hash to derive -/// the data with `get()`. Clear with `clear()` and purge the portions of the data -/// that have no references with `purge()`. -/// -/// # Example -/// ```rust -/// extern crate hashdb; -/// extern crate keccak_hasher; -/// extern crate memorydb; -/// -/// use hashdb::*; -/// use keccak_hasher::KeccakHasher; -/// use memorydb::*; -/// fn main() { -/// let mut m = MemoryDB::>::new(); -/// let d = "Hello world!".as_bytes(); -/// -/// let k = m.insert(d); -/// assert!(m.contains(&k)); -/// assert_eq!(m.get(&k).unwrap(), d); -/// -/// m.insert(d); -/// assert!(m.contains(&k)); -/// -/// m.remove(&k); -/// assert!(m.contains(&k)); -/// -/// m.remove(&k); -/// assert!(!m.contains(&k)); -/// -/// m.remove(&k); -/// assert!(!m.contains(&k)); -/// -/// m.insert(d); -/// assert!(!m.contains(&k)); - -/// m.insert(d); -/// assert!(m.contains(&k)); -/// assert_eq!(m.get(&k).unwrap(), d); -/// -/// m.remove(&k); -/// assert!(!m.contains(&k)); -/// } -/// ``` -#[derive(Clone, PartialEq)] -pub struct MemoryDB { - data: FastMap, - hashed_null_node: H::Out, - null_node_data: T, -} - -impl<'a, H, T> Default for MemoryDB -where - H: KeyHasher, - H::Out: HeapSizeOf, - T: From<&'a [u8]> + Clone -{ - fn default() -> Self { Self::new() } -} - -impl<'a, H, T> MemoryDB -where - H: KeyHasher, - H::Out: HeapSizeOf, - T: From<&'a [u8]> + Clone, -{ - /// Create a new instance of the memory DB. - pub fn new() -> Self { - MemoryDB::from_null_node(&NULL_RLP, NULL_RLP.as_ref().into()) - } -} - -impl MemoryDB -where - H: KeyHasher, - H::Out: HeapSizeOf, - T: Default, -{ - /// Remove an element and delete it from storage if reference count reaches zero. - /// If the value was purged, return the old value. - pub fn remove_and_purge(&mut self, key: &::Out) -> Option { - if key == &self.hashed_null_node { - return None; - } - match self.data.entry(key.clone()) { - Entry::Occupied(mut entry) => - if entry.get().1 == 1 { - Some(entry.remove().0) - } else { - entry.get_mut().1 -= 1; - None - }, - Entry::Vacant(entry) => { - entry.insert((T::default(), -1)); // FIXME: shouldn't it be purged? - None - } - } - } -} - -impl MemoryDB { - - /// Create a new `MemoryDB` from a given null key/data - pub fn from_null_node(null_key: &[u8], null_node_data: T) -> Self { - MemoryDB { - data: FastMap::::default(), - hashed_null_node: H::hash(null_key), - null_node_data, - } - } - - /// Clear all data from the database. - /// - /// # Examples - /// ```rust - /// extern crate hashdb; - /// extern crate keccak_hasher; - /// extern crate memorydb; - /// - /// use hashdb::*; - /// use keccak_hasher::KeccakHasher; - /// use memorydb::*; - /// - /// fn main() { - /// let mut m = MemoryDB::>::new(); - /// let hello_bytes = "Hello world!".as_bytes(); - /// let hash = m.insert(hello_bytes); - /// assert!(m.contains(&hash)); - /// m.clear(); - /// assert!(!m.contains(&hash)); - /// } - /// ``` - pub fn clear(&mut self) { - self.data.clear(); - } - - /// Purge all zero-referenced data from the database. - pub fn purge(&mut self) { - self.data.retain(|_, &mut (_, rc)| rc != 0); - } - - /// Return the internal map of hashes to data, clearing the current state. - pub fn drain(&mut self) -> FastMap { - mem::replace(&mut self.data, FastMap::::default()) - } - - /// Grab the raw information associated with a key. Returns None if the key - /// doesn't exist. - /// - /// Even when Some is returned, the data is only guaranteed to be useful - /// when the refs > 0. - pub fn raw(&self, key: &::Out) -> Option<(T, i32)> { - if key == &self.hashed_null_node { - return Some((self.null_node_data.clone(), 1)); - } - self.data.get(key).map(|(value, count)| (value.clone(), *count)) - } - - /// Consolidate all the entries of `other` into `self`. - pub fn consolidate(&mut self, mut other: Self) { - for (key, (value, rc)) in other.drain() { - match self.data.entry(key) { - Entry::Occupied(mut entry) => { - if entry.get().1 < 0 { - entry.get_mut().0 = value; - } - - entry.get_mut().1 += rc; - } - Entry::Vacant(entry) => { - entry.insert((value, rc)); - } - } - } - } -} - -impl MemoryDB -where - H: KeyHasher, - H::Out: HeapSizeOf, - T: HeapSizeOf, -{ - /// Returns the size of allocated heap memory - pub fn mem_used(&self) -> usize { - self.data.heap_size_of_children() - } -} - -impl HashDB for MemoryDB -where - H: KeyHasher, - T: Default + PartialEq + for<'a> From<&'a [u8]> + Send + Sync + Clone, -{ - fn keys(&self) -> HashMap { - self.data.iter() - .filter_map(|(k, v)| if v.1 != 0 { - Some((*k, v.1)) - } else { - None - }) - .collect() - } - - fn get(&self, key: &H::Out) -> Option { - if key == &self.hashed_null_node { - return Some(self.null_node_data.clone()); - } - - match self.data.get(key) { - Some(&(ref d, rc)) if rc > 0 => Some(d.clone()), - _ => None - } - } - - fn contains(&self, key: &H::Out) -> bool { - if key == &self.hashed_null_node { - return true; - } - - match self.data.get(key) { - Some(&(_, x)) if x > 0 => true, - _ => false - } - } - - fn emplace(&mut self, key:H::Out, value: T) { - if value == self.null_node_data { - return; - } - - match self.data.entry(key) { - Entry::Occupied(mut entry) => { - let &mut (ref mut old_value, ref mut rc) = entry.get_mut(); - if *rc <= 0 { - *old_value = value; - } - *rc += 1; - }, - Entry::Vacant(entry) => { - entry.insert((value, 1)); - }, - } - } - - fn insert(&mut self, value: &[u8]) -> H::Out { - if value == &NULL_RLP { - return self.hashed_null_node.clone(); - } - let key = H::hash(value); - match self.data.entry(key) { - Entry::Occupied(mut entry) => { - let &mut (ref mut old_value, ref mut rc) = entry.get_mut(); - if *rc <= 0 { - *old_value = value.into(); - } - *rc += 1; - }, - Entry::Vacant(entry) => { - entry.insert((value.into(), 1)); - }, - } - key - } - - fn remove(&mut self, key: &H::Out) { - if key == &self.hashed_null_node { - return; - } - - match self.data.entry(*key) { - Entry::Occupied(mut entry) => { - let &mut (_, ref mut rc) = entry.get_mut(); - *rc -= 1; - }, - Entry::Vacant(entry) => { - entry.insert((T::default(), -1)); - }, - } - } - -} - -impl AsHashDB for MemoryDB -where - H: KeyHasher, - T: Default + PartialEq + for<'a> From<&'a[u8]> + Send + Sync + Clone, -{ - fn as_hashdb(&self) -> &HashDB { self } - fn as_hashdb_mut(&mut self) -> &mut HashDB { self } -} - -#[cfg(test)] -mod tests { - use super::*; - use tiny_keccak::Keccak; - use ethereum_types::H256; - use keccak_hasher::KeccakHasher; - - #[test] - fn memorydb_remove_and_purge() { - let hello_bytes = b"Hello world!"; - let mut hello_key = [0;32]; - Keccak::keccak256(hello_bytes, &mut hello_key); - let hello_key = H256(hello_key); - - let mut m = MemoryDB::>::new(); - m.remove(&hello_key); - assert_eq!(m.raw(&hello_key).unwrap().1, -1); - m.purge(); - assert_eq!(m.raw(&hello_key).unwrap().1, -1); - m.insert(hello_bytes); - assert_eq!(m.raw(&hello_key).unwrap().1, 0); - m.purge(); - assert_eq!(m.raw(&hello_key), None); - - let mut m = MemoryDB::>::new(); - assert!(m.remove_and_purge(&hello_key).is_none()); - assert_eq!(m.raw(&hello_key).unwrap().1, -1); - m.insert(hello_bytes); - m.insert(hello_bytes); - assert_eq!(m.raw(&hello_key).unwrap().1, 1); - assert_eq!(&*m.remove_and_purge(&hello_key).unwrap(), hello_bytes); - assert_eq!(m.raw(&hello_key), None); - assert!(m.remove_and_purge(&hello_key).is_none()); - } - - #[test] - fn consolidate() { - let mut main = MemoryDB::>::new(); - let mut other = MemoryDB::>::new(); - let remove_key = other.insert(b"doggo"); - main.remove(&remove_key); - - let insert_key = other.insert(b"arf"); - main.emplace(insert_key, "arf".as_bytes().to_vec()); - - let negative_remove_key = other.insert(b"negative"); - other.remove(&negative_remove_key); // ref cnt: 0 - other.remove(&negative_remove_key); // ref cnt: -1 - main.remove(&negative_remove_key); // ref cnt: -1 - - main.consolidate(other); - - let overlay = main.drain(); - - assert_eq!(overlay.get(&remove_key).unwrap(), &("doggo".as_bytes().to_vec(), 0)); - assert_eq!(overlay.get(&insert_key).unwrap(), &("arf".as_bytes().to_vec(), 2)); - assert_eq!(overlay.get(&negative_remove_key).unwrap(), &("negative".as_bytes().to_vec(), -2)); - } - - #[test] - fn default_works() { - let mut db = MemoryDB::>::default(); - let hashed_null_node = KeccakHasher::hash(&NULL_RLP); - assert_eq!(db.insert(&NULL_RLP), hashed_null_node); - } -} diff --git a/patricia_trie/Cargo.toml b/patricia_trie/Cargo.toml deleted file mode 100644 index c92ab30..0000000 --- a/patricia_trie/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -name = "patricia-trie" -version = "0.3.0" -authors = ["Parity Technologies "] -description = "Merkle-Patricia Trie generic over key hasher and node encoding, deprecated please use trie-db crate" -repository = "https://github.com/paritytech/parity-common" -license = "GPL-3.0" - -[dependencies] -elastic-array = "0.10" -log = "0.3" -rand = "0.4" -hashdb = { version = "0.3.0", path = "../hashdb" } -parity-bytes = { version = "0.1", path = "../parity-bytes" } - -[dev-dependencies] -env_logger = "0.5" -ethereum-types = "0.4" -keccak-hash = { version = "0.1", path = "../keccak-hash" } -memorydb = { version = "0.3.0", path = "../memorydb", default-features = false } -rlp = { version = "0.3.0", path = "../rlp", default-features = false } -trie-standardmap = { version = "0.1", path = "../trie-standardmap", default-features = false } -triehash = { version = "0.3.0", path = "../triehash", default-features = false } -parity-bytes = { version = "0.1.0", path = "../parity-bytes" } -patricia-trie-ethereum = { version = "0.1", path = "../test-support/patricia-trie-ethereum" } -keccak-hasher = { version = "0.1", path = "../test-support/keccak-hasher" } diff --git a/patricia_trie/benches/trie.rs b/patricia_trie/benches/trie.rs deleted file mode 100644 index fcdcad9..0000000 --- a/patricia_trie/benches/trie.rs +++ /dev/null @@ -1,214 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -#![feature(test)] - -extern crate test; -extern crate parity_bytes; -extern crate ethereum_types; -extern crate memorydb; -extern crate patricia_trie as trie; -extern crate patricia_trie_ethereum as ethtrie; -extern crate keccak_hasher; -extern crate keccak_hash; -extern crate trie_standardmap; -extern crate hashdb; - -use parity_bytes::Bytes; -use ethereum_types::H256; -use keccak_hash::keccak; -use memorydb::MemoryDB; -use test::{Bencher, black_box}; -use trie::{DBValue, TrieMut, Trie}; -use trie_standardmap::{Alphabet, ValueMode, StandardMap}; -use keccak_hasher::KeccakHasher; -use ethtrie::{TrieDB, TrieDBMut}; - -fn random_word(alphabet: &[u8], min_count: usize, diff_count: usize, seed: &mut H256) -> Vec { - assert!(min_count + diff_count <= 32); - *seed = keccak(&seed); - let r = min_count + (seed[31] as usize % (diff_count + 1)); - let mut ret: Vec = Vec::with_capacity(r); - for i in 0..r { - ret.push(alphabet[seed[i] as usize % alphabet.len()]); - } - ret -} - -fn random_bytes(min_count: usize, diff_count: usize, seed: &mut H256) -> Vec { - assert!(min_count + diff_count <= 32); - *seed = keccak(&seed); - let r = min_count + (seed[31] as usize % (diff_count + 1)); - seed[0..r].to_vec() -} - -fn random_value(seed: &mut H256) -> Bytes { - *seed = keccak(&seed); - match seed[0] % 2 { - 1 => vec![seed[31];1], - _ => seed.to_vec(), - } -} - -#[bench] -fn trie_insertions_32_mir_1k(b: &mut Bencher) { - let st = StandardMap { - alphabet: Alphabet::All, - min_key: 32, - journal_key: 0, - value_mode: ValueMode::Mirror, - count: 1000, - }; - let d = st.make(); - b.iter(&mut ||{ - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - }); -} -#[bench] -fn trie_iter(b: &mut Bencher) { - let st = StandardMap { - alphabet: Alphabet::All, - min_key: 32, - journal_key: 0, - value_mode: ValueMode::Mirror, - count: 1000, - }; - let d = st.make(); - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - } - - b.iter(&mut ||{ - let t = TrieDB::new(&memdb, &root).unwrap(); - for n in t.iter().unwrap() { - black_box(n).unwrap(); - } - }); -} - -#[bench] -fn trie_insertions_32_ran_1k(b: &mut Bencher) { - let st = StandardMap { - alphabet: Alphabet::All, - min_key: 32, - journal_key: 0, - value_mode: ValueMode::Random, - count: 1000, - }; - let d = st.make(); - let mut r = H256::new(); - b.iter(&mut ||{ - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - r = t.root().clone(); - }); -} - -#[bench] -fn trie_insertions_six_high(b: &mut Bencher) { - let mut d: Vec<(Bytes, Bytes)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_bytes(6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - - b.iter(||{ - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - }) -} - -#[bench] -fn trie_insertions_six_mid(b: &mut Bencher) { - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - let mut d: Vec<(Bytes, Bytes)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - b.iter(||{ - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - }) -} - -#[bench] -fn trie_insertions_random_mid(b: &mut Bencher) { - let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; - let mut d: Vec<(Bytes, Bytes)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 1, 5, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - - b.iter(||{ - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - }) -} - -#[bench] -fn trie_insertions_six_low(b: &mut Bencher) { - let alphabet = b"abcdef"; - let mut d: Vec<(Bytes, Bytes)> = Vec::new(); - let mut seed = H256::new(); - for _ in 0..1000 { - let k = random_word(alphabet, 6, 0, &mut seed); - let v = random_value(&mut seed); - d.push((k, v)) - } - - b.iter(||{ - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for i in d.iter() { - t.insert(&i.0, &i.1).unwrap(); - } - }) -} diff --git a/patricia_trie/src/fatdb.rs b/patricia_trie/src/fatdb.rs deleted file mode 100644 index 0d7ae1e..0000000 --- a/patricia_trie/src/fatdb.rs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use hashdb::{HashDB, Hasher}; -use super::{Result, DBValue, TrieDB, Trie, TrieDBIterator, TrieItem, TrieIterator, Query}; -use node_codec::NodeCodec; - -/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. -/// Additionaly it stores inserted hash-key mappings for later retrieval. -/// -/// Use it as a `Trie` or `TrieMut` trait object. -pub struct FatDB<'db, H, C> -where - H: Hasher + 'db, - C: NodeCodec -{ - raw: TrieDB<'db, H, C>, -} - -impl<'db, H, C> FatDB<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - /// Create a new trie with the backing database `db` and empty `root` - /// Initialise to the state entailed by the genesis block. - /// This guarantees the trie is built correctly. - pub fn new(db: &'db HashDB, root: &'db H::Out) -> Result { - Ok(FatDB { raw: TrieDB::new(db, root)? }) - } - - /// Get the backing database. - pub fn db(&self) -> &HashDB { self.raw.db() } -} - -impl<'db, H, C> Trie for FatDB<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - fn root(&self) -> &H::Out { self.raw.root() } - - fn contains(&self, key: &[u8]) -> Result { - self.raw.contains(H::hash(key).as_ref()) - } - - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> Result, H::Out, C::Error> - where 'a: 'key - { - self.raw.get_with(H::hash(key).as_ref(), query) - } - - fn iter<'a>(&'a self) -> Result> + 'a>, ::Out, C::Error> { - FatDBIterator::::new(&self.raw).map(|iter| Box::new(iter) as Box<_>) - } -} - -/// Itarator over inserted pairs of key values. -pub struct FatDBIterator<'db, H, C> -where - H: Hasher + 'db, - C: NodeCodec + 'db -{ - trie_iterator: TrieDBIterator<'db, H, C>, - trie: &'db TrieDB<'db, H, C>, -} - -impl<'db, H, C> FatDBIterator<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - /// Creates new iterator. - pub fn new(trie: &'db TrieDB) -> Result { - Ok(FatDBIterator { - trie_iterator: TrieDBIterator::new(trie)?, - trie: trie, - }) - } -} - -impl<'db, H, C> TrieIterator for FatDBIterator<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - fn seek(&mut self, key: &[u8]) -> Result<(), H::Out, C::Error> { - let hashed_key = H::hash(key); - self.trie_iterator.seek(hashed_key.as_ref()) - } -} - -impl<'db, H, C> Iterator for FatDBIterator<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - type Item = TrieItem<'db, H::Out, C::Error>; - - fn next(&mut self) -> Option { - self.trie_iterator.next() - .map(|res| { - res.map(|(hash, value)| { - let aux_hash = H::hash(&hash); - (self.trie.db().get(&aux_hash).expect("Missing fatdb hash").into_vec(), value) - }) - }) - } -} - -#[cfg(test)] -mod test { - use memorydb::MemoryDB; - use DBValue; - use keccak_hasher::KeccakHasher; - use ethtrie::trie::{Trie, TrieMut}; - use ethtrie::{FatDB, FatDBMut}; - use ethereum_types::H256; - - #[test] - fn fatdb_to_trie() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - { - let mut t = FatDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - } - let t = FatDB::new(&memdb, &root).unwrap(); - assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); - assert_eq!( - t.iter().unwrap().map(Result::unwrap).collect::>(), - vec![(vec![0x01u8, 0x23], DBValue::from_slice(&[0x01u8, 0x23] as &[u8]))]); - } -} diff --git a/patricia_trie/src/fatdbmut.rs b/patricia_trie/src/fatdbmut.rs deleted file mode 100644 index 3f12b71..0000000 --- a/patricia_trie/src/fatdbmut.rs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use hashdb::{HashDB, Hasher}; -use super::{Result, DBValue, TrieDBMut, TrieMut}; -use node_codec::NodeCodec; - -/// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. -/// Additionaly it stores inserted hash-key mappings for later retrieval. -/// -/// Use it as a `Trie` or `TrieMut` trait object. -pub struct FatDBMut<'db, H, C> -where - H: Hasher + 'db, - C: NodeCodec -{ - raw: TrieDBMut<'db, H, C>, -} - -impl<'db, H, C> FatDBMut<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - /// Create a new trie with the backing database `db` and empty `root` - /// Initialise to the state entailed by the genesis block. - /// This guarantees the trie is built correctly. - pub fn new(db: &'db mut HashDB, root: &'db mut H::Out) -> Self { - FatDBMut { raw: TrieDBMut::new(db, root) } - } - - /// Create a new trie with the backing database `db` and `root`. - /// - /// Returns an error if root does not exist. - pub fn from_existing(db: &'db mut HashDB, root: &'db mut H::Out) -> Result { - Ok(FatDBMut { raw: TrieDBMut::from_existing(db, root)? }) - } - - /// Get the backing database. - pub fn db(&self) -> &HashDB { - self.raw.db() - } - - /// Get the backing database. - pub fn db_mut(&mut self) -> &mut HashDB { - self.raw.db_mut() - } -} - -impl<'db, H, C> TrieMut for FatDBMut<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - fn root(&mut self) -> &H::Out { self.raw.root() } - - fn is_empty(&self) -> bool { self.raw.is_empty() } - - fn contains(&self, key: &[u8]) -> Result { - self.raw.contains(H::hash(key).as_ref()) - } - - fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result, H::Out, C::Error> - where 'a: 'key - { - self.raw.get(H::hash(key).as_ref()) - } - - fn insert(&mut self, key: &[u8], value: &[u8]) -> Result, H::Out, C::Error> { - let hash = H::hash(key); - let out = self.raw.insert(hash.as_ref(), value)?; - let db = self.raw.db_mut(); - - // insert if it doesn't exist. - if out.is_none() { - let aux_hash = H::hash(hash.as_ref()); - db.emplace(aux_hash, DBValue::from_slice(key)); - } - Ok(out) - } - - fn remove(&mut self, key: &[u8]) -> Result, H::Out, C::Error> { - let hash = H::hash(key); - let out = self.raw.remove(hash.as_ref())?; - - // remove if it already exists. - if out.is_some() { - let aux_hash = H::hash(hash.as_ref()); - self.raw.db_mut().remove(&aux_hash); - } - - Ok(out) - } -} - -#[cfg(test)] -mod test { - use DBValue; - use memorydb::MemoryDB; - use ethtrie::trie::{Trie, TrieMut}; - use ethtrie::{TrieDB, FatDBMut}; - use keccak_hasher::KeccakHasher; - use keccak; - use ethereum_types::H256; - - #[test] - fn fatdbmut_to_trie() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - { - let mut t = FatDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - } - let t = TrieDB::new(&memdb, &root).unwrap(); - assert_eq!(t.get(&keccak::keccak(&[0x01u8, 0x23])), Ok(Some(DBValue::from_slice(&[0x01u8, 0x23])))); - } - - #[test] - fn fatdbmut_insert_remove_key_mapping() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let key = [0x01u8, 0x23]; - let val = [0x01u8, 0x24]; - let key_hash = keccak::keccak(&key); - let aux_hash = keccak::keccak(&key_hash); - let mut t = FatDBMut::new(&mut memdb, &mut root); - t.insert(&key, &val).unwrap(); - assert_eq!(t.get(&key), Ok(Some(DBValue::from_slice(&val)))); - assert_eq!(t.db().get(&aux_hash), Some(DBValue::from_slice(&key))); - t.remove(&key).unwrap(); - assert_eq!(t.db().get(&aux_hash), None); - } -} diff --git a/patricia_trie/src/lib.rs b/patricia_trie/src/lib.rs deleted file mode 100644 index 6a14fe1..0000000 --- a/patricia_trie/src/lib.rs +++ /dev/null @@ -1,334 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Trie interface and implementation. -extern crate elastic_array; -extern crate parity_bytes as bytes; // TODO: name changed; update upstream when `parity-common` is available -extern crate hashdb; -extern crate rand; -#[macro_use] -extern crate log; - -#[cfg(test)] -extern crate env_logger; -#[cfg(test)] -extern crate ethereum_types; -#[cfg(test)] -extern crate trie_standardmap as standardmap; -#[cfg(test)] -extern crate patricia_trie_ethereum as ethtrie; -#[cfg(test)] -extern crate memorydb; -#[cfg(test)] -extern crate rlp; -#[cfg(test)] -extern crate keccak_hash as keccak; -#[cfg(test)] -extern crate keccak_hasher; -#[cfg(test)] -extern crate triehash; - -use std::{fmt, error}; -use hashdb::{HashDB, Hasher}; -use std::marker::PhantomData; - -pub mod node; -pub mod triedb; -pub mod triedbmut; -pub mod sectriedb; -pub mod sectriedbmut; -pub mod recorder; - -mod fatdb; -mod fatdbmut; -mod lookup; -mod nibblevec; -mod nibbleslice; -mod node_codec; - -pub use self::triedb::{TrieDB, TrieDBIterator}; -pub use self::triedbmut::{TrieDBMut, ChildReference}; -pub use self::sectriedbmut::SecTrieDBMut; -pub use self::sectriedb::SecTrieDB; -pub use self::fatdb::{FatDB, FatDBIterator}; -pub use self::fatdbmut::FatDBMut; -pub use self::recorder::Recorder; -pub use self::lookup::Lookup; -pub use self::nibbleslice::NibbleSlice; -pub use node_codec::NodeCodec; - -pub type DBValue = elastic_array::ElasticArray128; - -/// Trie Errors. -/// -/// These borrow the data within them to avoid excessive copying on every -/// trie operation. -#[derive(Debug, PartialEq, Eq, Clone)] -pub enum TrieError { - /// Attempted to create a trie with a state root not in the DB. - InvalidStateRoot(T), - /// Trie item not found in the database, - IncompleteDatabase(T), - /// Corrupt Trie item - DecoderError(T, E), -} - -impl fmt::Display for TrieError where T: std::fmt::Debug, E: std::fmt::Debug { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - match *self { - TrieError::InvalidStateRoot(ref root) => write!(f, "Invalid state root: {:?}", root), - TrieError::IncompleteDatabase(ref missing) => write!(f, "Database missing expected key: {:?}", missing), - TrieError::DecoderError(ref hash, ref decoder_err) => { - write!(f, "Decoding failed for hash {:?}; err: {:?}", hash, decoder_err) - } - } - } -} - -impl error::Error for TrieError where T: std::fmt::Debug, E: std::error::Error { - fn description(&self) -> &str { - match *self { - TrieError::InvalidStateRoot(_) => "Invalid state root", - TrieError::IncompleteDatabase(_) => "Incomplete database", - TrieError::DecoderError(_, ref err) => err.description(), - } - } -} - -/// Trie result type. Boxed to avoid copying around extra space for the `Hasher`s `Out` on successful queries. -pub type Result = ::std::result::Result>>; - - -/// Trie-Item type used for iterators over trie data. -pub type TrieItem<'a, U, E> = Result<(Vec, DBValue), U, E>; - -/// Description of what kind of query will be made to the trie. -/// -/// This is implemented for any &mut recorder (where the query will return -/// a DBValue), any function taking raw bytes (where no recording will be made), -/// or any tuple of (&mut Recorder, FnOnce(&[u8])) -pub trait Query { - /// Output item. - type Item; - - /// Decode a byte-slice into the desired item. - fn decode(self, data: &[u8]) -> Self::Item; - - /// Record that a node has been passed through. - fn record(&mut self, _hash: &H::Out, _data: &[u8], _depth: u32) {} -} - -impl<'a, H: Hasher> Query for &'a mut Recorder { - type Item = DBValue; - fn decode(self, value: &[u8]) -> DBValue { DBValue::from_slice(value) } - fn record(&mut self, hash: &H::Out, data: &[u8], depth: u32) { - (&mut **self).record(hash, data, depth); - } -} - -impl Query for F where F: for<'a> FnOnce(&'a [u8]) -> T { - type Item = T; - fn decode(self, value: &[u8]) -> T { (self)(value) } -} - -impl<'a, F, T, H: Hasher> Query for (&'a mut Recorder, F) where F: FnOnce(&[u8]) -> T { - type Item = T; - fn decode(self, value: &[u8]) -> T { (self.1)(value) } - fn record(&mut self, hash: &H::Out, data: &[u8], depth: u32) { - self.0.record(hash, data, depth) - } -} - -/// A key-value datastore implemented as a database-backed modified Merkle tree. -pub trait Trie> { - /// Return the root of the trie. - fn root(&self) -> &H::Out; - - /// Is the trie empty? - fn is_empty(&self) -> bool { *self.root() == C::HASHED_NULL_NODE } - - /// Does the trie contain a given key? - fn contains(&self, key: &[u8]) -> Result { - self.get(key).map(|x|x.is_some() ) - } - - /// What is the value of the given key in this trie? - fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result, H::Out, C::Error> where 'a: 'key { - self.get_with(key, DBValue::from_slice) - } - - /// Search for the key with the given query parameter. See the docs of the `Query` - /// trait for more details. - fn get_with<'a, 'key, Q: Query>( - &'a self, - key: &'key [u8], - query: Q - ) -> Result, H::Out, C::Error> where 'a: 'key; - - /// Returns a depth-first iterator over the elements of trie. - fn iter<'a>(&'a self) -> Result> + 'a>, H::Out, C::Error>; -} - -/// A key-value datastore implemented as a database-backed modified Merkle tree. -pub trait TrieMut> { - /// Return the root of the trie. - fn root(&mut self) -> &H::Out; - - /// Is the trie empty? - fn is_empty(&self) -> bool; - - /// Does the trie contain a given key? - fn contains(&self, key: &[u8]) -> Result { - self.get(key).map(|x| x.is_some()) - } - - /// What is the value of the given key in this trie? - fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result, H::Out, C::Error> where 'a: 'key; - - /// Insert a `key`/`value` pair into the trie. An empty value is equivalent to removing - /// `key` from the trie. Returns the old value associated with this key, if it existed. - fn insert(&mut self, key: &[u8], value: &[u8]) -> Result, H::Out, C::Error>; - - /// Remove a `key` from the trie. Equivalent to making it equal to the empty - /// value. Returns the old value associated with this key, if it existed. - fn remove(&mut self, key: &[u8]) -> Result, H::Out, C::Error>; -} - -/// A trie iterator that also supports random access (`seek()`). -pub trait TrieIterator>: Iterator { - /// Position the iterator on the first element with key >= `key` - fn seek(&mut self, key: &[u8]) -> Result<(), H::Out, >::Error>; -} - -/// Trie types -#[derive(Debug, PartialEq, Clone)] -pub enum TrieSpec { - /// Generic trie. - Generic, - /// Secure trie. - Secure, - /// Secure trie with fat database. - Fat, -} - -impl Default for TrieSpec { - fn default() -> TrieSpec { - TrieSpec::Secure - } -} - -/// Trie factory. -#[derive(Default, Clone)] -pub struct TrieFactory> { - spec: TrieSpec, - mark_hash: PhantomData, - mark_codec: PhantomData, -} - -/// All different kinds of tries. -/// This is used to prevent a heap allocation for every created trie. -pub enum TrieKinds<'db, H: Hasher + 'db, C: NodeCodec> { - /// A generic trie db. - Generic(TrieDB<'db, H, C>), - /// A secure trie db. - Secure(SecTrieDB<'db, H, C>), - /// A fat trie db. - Fat(FatDB<'db, H, C>), -} - -// wrapper macro for making the match easier to deal with. -macro_rules! wrapper { - ($me: ident, $f_name: ident, $($param: ident),*) => { - match *$me { - TrieKinds::Generic(ref t) => t.$f_name($($param),*), - TrieKinds::Secure(ref t) => t.$f_name($($param),*), - TrieKinds::Fat(ref t) => t.$f_name($($param),*), - } - } -} - -impl<'db, H: Hasher, C: NodeCodec> Trie for TrieKinds<'db, H, C> { - fn root(&self) -> &H::Out { - wrapper!(self, root,) - } - - fn is_empty(&self) -> bool { - wrapper!(self, is_empty,) - } - - fn contains(&self, key: &[u8]) -> Result { - wrapper!(self, contains, key) - } - - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> Result, H::Out, C::Error> - where 'a: 'key - { - wrapper!(self, get_with, key, query) - } - - fn iter<'a>(&'a self) -> Result> + 'a>, H::Out, C::Error> { - wrapper!(self, iter,) - } -} - -impl<'db, H, C> TrieFactory -where - H: Hasher, - C: NodeCodec + 'db -{ - /// Creates new factory. - pub fn new(spec: TrieSpec) -> Self { - TrieFactory { spec, mark_hash: PhantomData, mark_codec: PhantomData } - } - - /// Create new immutable instance of Trie. - pub fn readonly( - &self, - db: &'db HashDB, - root: &'db H::Out - ) -> Result, H::Out, >::Error> { - match self.spec { - TrieSpec::Generic => Ok(TrieKinds::Generic(TrieDB::new(db, root)?)), - TrieSpec::Secure => Ok(TrieKinds::Secure(SecTrieDB::new(db, root)?)), - TrieSpec::Fat => Ok(TrieKinds::Fat(FatDB::new(db, root)?)), - } - } - - /// Create new mutable instance of Trie. - pub fn create(&self, db: &'db mut HashDB, root: &'db mut H::Out) -> Box + 'db> { - match self.spec { - TrieSpec::Generic => Box::new(TrieDBMut::<_, C>::new(db, root)), - TrieSpec::Secure => Box::new(SecTrieDBMut::<_, C>::new(db, root)), - TrieSpec::Fat => Box::new(FatDBMut::<_, C>::new(db, root)), - } - } - - /// Create new mutable instance of trie and check for errors. - pub fn from_existing( - &self, - db: &'db mut HashDB, - root: &'db mut H::Out - ) -> Result + 'db>, H::Out, >::Error> { - match self.spec { - TrieSpec::Generic => Ok(Box::new(TrieDBMut::<_, C>::from_existing(db, root)?)), - TrieSpec::Secure => Ok(Box::new(SecTrieDBMut::<_, C>::from_existing(db, root)?)), - TrieSpec::Fat => Ok(Box::new(FatDBMut::<_, C>::from_existing(db, root)?)), - } - } - - /// Returns true iff the trie DB is a fat DB (allows enumeration of keys). - pub fn is_fat(&self) -> bool { self.spec == TrieSpec::Fat } -} diff --git a/patricia_trie/src/lookup.rs b/patricia_trie/src/lookup.rs deleted file mode 100644 index 630585e..0000000 --- a/patricia_trie/src/lookup.rs +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Trie lookup via HashDB. - -use hashdb::{HashDB, Hasher}; -use nibbleslice::NibbleSlice; -use node::Node; -use node_codec::NodeCodec; -use super::{DBValue, Result, TrieError, Query}; -use std::marker::PhantomData; - -/// Trie lookup helper object. -pub struct Lookup<'a, H: Hasher + 'a, C: NodeCodec, Q: Query> { - /// database to query from. - pub db: &'a HashDB, - /// Query object to record nodes and transform data. - pub query: Q, - /// Hash to start at - pub hash: H::Out, - pub marker: PhantomData, // TODO: probably not needed when all is said and done? When Query is made generic? -} - -impl<'a, H, C, Q> Lookup<'a, H, C, Q> -where - H: Hasher + 'a, - C: NodeCodec + 'a, - Q: Query, -{ - /// Look up the given key. If the value is found, it will be passed to the given - /// function to decode or copy. - pub fn look_up(mut self, mut key: NibbleSlice) -> Result, H::Out, C::Error> { - let mut hash = self.hash; - - // this loop iterates through non-inline nodes. - for depth in 0.. { - let node_data = match self.db.get(&hash) { - Some(value) => value, - None => return Err(Box::new(match depth { - 0 => TrieError::InvalidStateRoot(hash), - _ => TrieError::IncompleteDatabase(hash), - })), - }; - - self.query.record(&hash, &node_data, depth); - - // this loop iterates through all inline children (usually max 1) - // without incrementing the depth. - let mut node_data = &node_data[..]; - loop { - let decoded = match C::decode(node_data) { - Ok(node) => node, - Err(e) => { - return Err(Box::new(TrieError::DecoderError(hash, e))) - } - }; - match decoded { - Node::Leaf(slice, value) => { - return Ok(match slice == key { - true => Some(self.query.decode(value)), - false => None, - }) - } - Node::Extension(slice, item) => { - if key.starts_with(&slice) { - node_data = item; - key = key.mid(slice.len()); - } else { - return Ok(None) - } - } - Node::Branch(children, value) => match key.is_empty() { - true => return Ok(value.map(move |val| self.query.decode(val))), - false => { - node_data = children[key.at(0) as usize]; - key = key.mid(1); - } - }, - _ => return Ok(None), - } - - // check if new node data is inline or hash. - if let Some(h) = C::try_decode_hash(&node_data) { - hash = h; - break - } - } - } - Ok(None) - } -} diff --git a/patricia_trie/src/nibbleslice.rs b/patricia_trie/src/nibbleslice.rs deleted file mode 100644 index 7f0e581..0000000 --- a/patricia_trie/src/nibbleslice.rs +++ /dev/null @@ -1,328 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Nibble-orientated view onto byte-slice, allowing nibble-precision offsets. - -use std::cmp::*; -use std::fmt; -use elastic_array::ElasticArray36; - -/// Nibble-orientated view onto byte-slice, allowing nibble-precision offsets. -/// -/// This is an immutable struct. No operations actually change it. -/// -/// # Example -/// ```snippet -/// use patricia_trie::nibbleslice::NibbleSlice; -/// fn main() { -/// let d1 = &[0x01u8, 0x23, 0x45]; -/// let d2 = &[0x34u8, 0x50, 0x12]; -/// let d3 = &[0x00u8, 0x12]; -/// let n1 = NibbleSlice::new(d1); // 0,1,2,3,4,5 -/// let n2 = NibbleSlice::new(d2); // 3,4,5,0,1,2 -/// let n3 = NibbleSlice::new_offset(d3, 1); // 0,1,2 -/// assert!(n1 > n3); // 0,1,2,... > 0,1,2 -/// assert!(n1 < n2); // 0,... < 3,... -/// assert!(n2.mid(3) == n3); // 0,1,2 == 0,1,2 -/// assert!(n1.starts_with(&n3)); -/// assert_eq!(n1.common_prefix(&n3), 3); -/// assert_eq!(n2.mid(3).common_prefix(&n1), 3); -/// } -/// ``` -#[derive(Copy, Clone, Eq, Ord)] -pub struct NibbleSlice<'a> { - data: &'a [u8], - offset: usize, - data_encode_suffix: &'a [u8], - offset_encode_suffix: usize, -} - -/// Iterator type for a nibble slice. -pub struct NibbleSliceIterator<'a> { - p: &'a NibbleSlice<'a>, - i: usize, -} - -impl<'a> Iterator for NibbleSliceIterator<'a> { - type Item = u8; - fn next(&mut self) -> Option { - self.i += 1; - match self.i <= self.p.len() { - true => Some(self.p.at(self.i - 1)), - false => None, - } - } -} - -impl<'a> NibbleSlice<'a> { - /// Create a new nibble slice with the given byte-slice. - pub fn new(data: &'a [u8]) -> Self { NibbleSlice::new_offset(data, 0) } - - /// Create a new nibble slice with the given byte-slice with a nibble offset. - pub fn new_offset(data: &'a [u8], offset: usize) -> Self { - NibbleSlice { - data, - offset, - data_encode_suffix: &b""[..], - offset_encode_suffix: 0 - } - } - - /// Create a composed nibble slice; one followed by the other. - pub fn new_composed(a: &NibbleSlice<'a>, b: &NibbleSlice<'a>) -> Self { - NibbleSlice { - data: a.data, - offset: a.offset, - data_encode_suffix: b.data, - offset_encode_suffix: b.offset - } - } - - /// Get an iterator for the series of nibbles. - pub fn iter(&'a self) -> NibbleSliceIterator<'a> { - NibbleSliceIterator { p: self, i: 0 } - } - - /// Create a new nibble slice from the given HPE encoded data (e.g. output of `encoded()`). - pub fn from_encoded(data: &'a [u8]) -> (NibbleSlice, bool) { - (Self::new_offset(data, if data[0] & 16 == 16 {1} else {2}), data[0] & 32 == 32) - } - - /// Is this an empty slice? - pub fn is_empty(&self) -> bool { self.len() == 0 } - - /// Get the length (in nibbles, naturally) of this slice. - #[inline] - pub fn len(&self) -> usize { (self.data.len() + self.data_encode_suffix.len()) * 2 - self.offset - self.offset_encode_suffix } - - /// Get the nibble at position `i`. - #[inline(always)] - pub fn at(&self, i: usize) -> u8 { - let l = self.data.len() * 2 - self.offset; - if i < l { - if (self.offset + i) & 1 == 1 { - self.data[(self.offset + i) / 2] & 15u8 - } - else { - self.data[(self.offset + i) / 2] >> 4 - } - } - else { - let i = i - l; - if (self.offset_encode_suffix + i) & 1 == 1 { - self.data_encode_suffix[(self.offset_encode_suffix + i) / 2] & 15u8 - } - else { - self.data_encode_suffix[(self.offset_encode_suffix + i) / 2] >> 4 - } - } - } - - /// Return object which represents a view on to this slice (further) offset by `i` nibbles. - pub fn mid(&self, i: usize) -> NibbleSlice<'a> { - NibbleSlice { - data: self.data, - offset: self.offset + i, - data_encode_suffix: &b""[..], - offset_encode_suffix: 0 - } - } - - /// Do we start with the same nibbles as the whole of `them`? - pub fn starts_with(&self, them: &Self) -> bool { self.common_prefix(them) == them.len() } - - /// How many of the same nibbles at the beginning do we match with `them`? - pub fn common_prefix(&self, them: &Self) -> usize { - let s = min(self.len(), them.len()); - let mut i = 0usize; - while i < s { - if self.at(i) != them.at(i) { break; } - i += 1; - } - i - } - - /// Encode while nibble slice in prefixed hex notation, noting whether it `is_leaf`. - #[inline] - pub fn encoded(&self, is_leaf: bool) -> ElasticArray36 { - let l = self.len(); - let mut r = ElasticArray36::new(); - let mut i = l % 2; - r.push(if i == 1 {0x10 + self.at(0)} else {0} + if is_leaf {0x20} else {0}); - while i < l { - r.push(self.at(i) * 16 + self.at(i + 1)); - i += 2; - } - r - } - - /// Encode only the leftmost `n` bytes of the nibble slice in prefixed hex notation, - /// noting whether it `is_leaf`. - pub fn encoded_leftmost(&self, n: usize, is_leaf: bool) -> ElasticArray36 { - let l = min(self.len(), n); - let mut r = ElasticArray36::new(); - let mut i = l % 2; - r.push(if i == 1 {0x10 + self.at(0)} else {0} + if is_leaf {0x20} else {0}); - while i < l { - r.push(self.at(i) * 16 + self.at(i + 1)); - i += 2; - } - r - } -} - -impl<'a> PartialEq for NibbleSlice<'a> { - fn eq(&self, them: &Self) -> bool { - self.len() == them.len() && self.starts_with(them) - } -} - -impl<'a> PartialOrd for NibbleSlice<'a> { - fn partial_cmp(&self, them: &Self) -> Option { - let s = min(self.len(), them.len()); - let mut i = 0usize; - while i < s { - match self.at(i).partial_cmp(&them.at(i)).unwrap() { - Ordering::Less => return Some(Ordering::Less), - Ordering::Greater => return Some(Ordering::Greater), - _ => i += 1, - } - } - self.len().partial_cmp(&them.len()) - } -} - -impl<'a> fmt::Debug for NibbleSlice<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for i in 0..self.len() { - match i { - 0 => write!(f, "{:01x}", self.at(i))?, - _ => write!(f, "'{:01x}", self.at(i))?, - } - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::NibbleSlice; - use elastic_array::ElasticArray36; - static D: &'static [u8;3] = &[0x01u8, 0x23, 0x45]; - - #[test] - fn basics() { - let n = NibbleSlice::new(D); - assert_eq!(n.len(), 6); - assert!(!n.is_empty()); - - let n = NibbleSlice::new_offset(D, 6); - assert!(n.is_empty()); - - let n = NibbleSlice::new_offset(D, 3); - assert_eq!(n.len(), 3); - for i in 0..3 { - assert_eq!(n.at(i), i as u8 + 3); - } - } - - #[test] - fn iterator() { - let n = NibbleSlice::new(D); - let mut nibbles: Vec = vec![]; - nibbles.extend(n.iter()); - assert_eq!(nibbles, (0u8..6).collect::>()) - } - - #[test] - fn mid() { - let n = NibbleSlice::new(D); - let m = n.mid(2); - for i in 0..4 { - assert_eq!(m.at(i), i as u8 + 2); - } - let m = n.mid(3); - for i in 0..3 { - assert_eq!(m.at(i), i as u8 + 3); - } - } - - #[test] - fn encoded() { - let n = NibbleSlice::new(D); - assert_eq!(n.encoded(false), ElasticArray36::from_slice(&[0x00, 0x01, 0x23, 0x45])); - assert_eq!(n.encoded(true), ElasticArray36::from_slice(&[0x20, 0x01, 0x23, 0x45])); - assert_eq!(n.mid(1).encoded(false), ElasticArray36::from_slice(&[0x11, 0x23, 0x45])); - assert_eq!(n.mid(1).encoded(true), ElasticArray36::from_slice(&[0x31, 0x23, 0x45])); - } - - #[test] - fn from_encoded() { - let n = NibbleSlice::new(D); - assert_eq!((n, false), NibbleSlice::from_encoded(&[0x00, 0x01, 0x23, 0x45])); - assert_eq!((n, true), NibbleSlice::from_encoded(&[0x20, 0x01, 0x23, 0x45])); - assert_eq!((n.mid(1), false), NibbleSlice::from_encoded(&[0x11, 0x23, 0x45])); - assert_eq!((n.mid(1), true), NibbleSlice::from_encoded(&[0x31, 0x23, 0x45])); - } - - #[test] - fn find_length_of_common_prefix() { - let n = NibbleSlice::new(D); - - let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45, 0x67]; - let m = NibbleSlice::new(other); - - assert_eq!(n.common_prefix(&m), 4); - assert_eq!(m.common_prefix(&n), 4); - assert_eq!(n.mid(1).common_prefix(&m.mid(1)), 3); - assert_eq!(n.mid(1).common_prefix(&m.mid(2)), 0); - assert_eq!(n.common_prefix(&m.mid(4)), 6); - assert!(!n.starts_with(&m.mid(4))); - assert!(m.mid(4).starts_with(&n)); - } - - #[test] - fn compare_sizes() { - let other = &[0x01u8, 0x23, 0x01, 0x23, 0x45]; - let n = NibbleSlice::new(D); - let m = NibbleSlice::new(other); - - assert!(n != m); - assert!(n > m); - assert!(m < n); - - assert!(n == m.mid(4)); - assert!(n >= m.mid(4)); - assert!(n <= m.mid(4)); - } - - #[test] - fn common_prefix_for_concatenated_slices() { - let first = NibbleSlice::new(&[0x01u8, 0x23, 0x45]); // 0'1'2'3'4'5' - let first_ext = NibbleSlice::new(&[0x22u8, 0x44, 0x55]); // 2'2'4'4'5'5 - let concat = NibbleSlice::new_composed(&first, &first_ext); - assert!(concat.len() == first.len() + first_ext.len()); - - // 0'1'2'3'4'5'2'2'9'9'5'5' - let second = NibbleSlice::new(&[0x01u8, 0x23, 0x45, 0x22, 0x99, 0x55]); - - let common_prefix_length = first.common_prefix(&second); - assert_eq!(common_prefix_length, 6); - - let common_prefix_length = concat.common_prefix(&second); - assert_eq!(common_prefix_length, 8); - } -} diff --git a/patricia_trie/src/nibblevec.rs b/patricia_trie/src/nibblevec.rs deleted file mode 100644 index 3fe8c9f..0000000 --- a/patricia_trie/src/nibblevec.rs +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! An owning, nibble-oriented byte vector. -use elastic_array::ElasticArray36; -use nibbleslice::NibbleSlice; - -/// Owning, nibble-oriented byte vector. Counterpart to `NibbleSlice`. -#[derive(Clone, PartialEq, Eq, Debug)] -pub struct NibbleVec { - inner: ElasticArray36, - len: usize, -} - -impl Default for NibbleVec { - fn default() -> Self { - NibbleVec::new() - } -} - -impl NibbleVec { - /// Make a new `NibbleVec` - pub fn new() -> Self { - NibbleVec { - inner: ElasticArray36::new(), - len: 0 - } - } - - /// Length of the `NibbleVec` - #[inline(always)] - pub fn len(&self) -> usize { self.len } - - /// Retrurns true if `NibbleVec` has zero length - pub fn is_empty(&self) -> bool { self.len == 0 } - - /// Try to get the nibble at the given offset. - #[inline] - pub fn at(&self, idx: usize) -> u8 { - if idx % 2 == 0 { - self.inner[idx / 2] >> 4 - } else { - self.inner[idx / 2] & 0x0F - } - } - - /// Push a nibble onto the `NibbleVec`. Ignores the high 4 bits. - pub fn push(&mut self, nibble: u8) { - let nibble = nibble & 0x0F; - - if self.len % 2 == 0 { - self.inner.push(nibble << 4); - } else { - *self.inner.last_mut().expect("len != 0 since len % 2 != 0; inner has a last element; qed") |= nibble; - } - - self.len += 1; - } - - /// Try to pop a nibble off the `NibbleVec`. Fails if len == 0. - pub fn pop(&mut self) -> Option { - if self.is_empty() { - return None; - } - - let byte = self.inner.pop().expect("len != 0; inner has last elem; qed"); - let nibble = if self.len % 2 == 0 { - self.inner.push(byte & 0xF0); - byte & 0x0F - } else { - byte >> 4 - }; - - self.len -= 1; - Some(nibble) - } - - /// Try to treat this `NibbleVec` as a `NibbleSlice`. Works only if len is even. - pub fn as_nibbleslice(&self) -> Option { - if self.len % 2 == 0 { - Some(NibbleSlice::new(self.inner())) - } else { - None - } - } - - /// Get the underlying byte slice. - pub fn inner(&self) -> &[u8] { - &self.inner[..] - } -} - -impl<'a> From> for NibbleVec { - fn from(s: NibbleSlice<'a>) -> Self { - let mut v = NibbleVec::new(); - for i in 0..s.len() { - v.push(s.at(i)); - } - v - } -} - -#[cfg(test)] -mod tests { - use super::NibbleVec; - - #[test] - fn push_pop() { - let mut v = NibbleVec::new(); - - for i in 0..16 { - v.push(i); - assert_eq!(v.len() - 1, i as usize); - assert_eq!(v.at(i as usize), i); - } - - for i in (0..16).rev() { - assert_eq!(v.pop(), Some(i)); - assert_eq!(v.len(), i as usize); - } - } - - #[test] - fn nibbleslice_conv() { - let mut v = NibbleVec::new(); - for i in 0..10 { - v.push(i); - } - - let v2: NibbleVec = v.as_nibbleslice().unwrap().into(); - assert_eq!(v, v2); - } -} diff --git a/patricia_trie/src/node.rs b/patricia_trie/src/node.rs deleted file mode 100644 index 81307bf..0000000 --- a/patricia_trie/src/node.rs +++ /dev/null @@ -1,106 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use elastic_array::ElasticArray36; -use nibbleslice::NibbleSlice; -use nibblevec::NibbleVec; -use super::DBValue; - -/// Partial node key type. -pub type NodeKey = ElasticArray36; - -/// Type of node in the trie and essential information thereof. -#[derive(Eq, PartialEq, Debug, Clone)] -pub enum Node<'a> { - /// Null trie node; could be an empty root or an empty branch entry. - Empty, - /// Leaf node; has key slice and value. Value may not be empty. - Leaf(NibbleSlice<'a>, &'a [u8]), - /// Extension node; has key slice and node data. Data may not be null. - Extension(NibbleSlice<'a>, &'a [u8]), - /// Branch node; has array of 16 child nodes (each possibly null) and an optional immediate node data. - Branch([&'a [u8]; 16], Option<&'a [u8]>), -} - -/// A Sparse (non mutable) owned vector struct to hold branch keys and value -#[derive(Eq, PartialEq, Debug, Clone)] -pub struct Branch { - data: Vec, - ubounds: [usize; 18], - has_value: bool, -} - -impl Branch { - fn new(a: [&[u8]; 16], value: Option<&[u8]>) -> Self { - let mut data = Vec::with_capacity(a.iter().map(|inner| inner.len()).sum()); - let mut ubounds = [0; 18]; - for (inner, ub) in a.iter().zip(ubounds.iter_mut().skip(1)) { - data.extend_from_slice(inner); - *ub = data.len(); - } - if let Some(value) = value { - data.extend(value); - ubounds[17] = data.len(); - } - Branch { data, ubounds, has_value: value.is_some() } - } - - /// Get the node value, if any - pub fn get_value(&self) -> Option<&[u8]> { - if self.has_value { - Some(&self.data[self.ubounds[16]..self.ubounds[17]]) - } else { - None - } - } - - /// Test if the node has a value - pub fn has_value(&self) -> bool { - self.has_value - } -} - -impl ::std::ops::Index for Branch { - type Output = [u8]; - fn index(&self, index: usize) -> &[u8] { - assert!(index < 16); - &self.data[self.ubounds[index]..self.ubounds[index + 1]] - } -} - -/// An owning node type. Useful for trie iterators. -#[derive(Debug, PartialEq, Eq)] -pub enum OwnedNode { - /// Empty trie node. - Empty, - /// Leaf node: partial key and value. - Leaf(NibbleVec, DBValue), - /// Extension node: partial key and child node. - Extension(NibbleVec, DBValue), - /// Branch node: 16 children and an optional value. - Branch(Branch), -} - -impl<'a> From> for OwnedNode { - fn from(node: Node<'a>) -> Self { - match node { - Node::Empty => OwnedNode::Empty, - Node::Leaf(k, v) => OwnedNode::Leaf(k.into(), DBValue::from_slice(v)), - Node::Extension(k, child) => OwnedNode::Extension(k.into(), DBValue::from_slice(child)), - Node::Branch(c, val) => OwnedNode::Branch(Branch::new(c, val)), - } - } -} diff --git a/patricia_trie/src/node_codec.rs b/patricia_trie/src/node_codec.rs deleted file mode 100644 index f91d38b..0000000 --- a/patricia_trie/src/node_codec.rs +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Generic trait for trie node encoding/decoding. Takes a `hashdb::Hasher` -//! to parametrize the hashes used in the codec. - -use hashdb::Hasher; -use node::Node; -use ChildReference; - -use elastic_array::{ElasticArray128}; - -/// Trait for trie node encoding/decoding -pub trait NodeCodec: Sized { - /// Encoding error type - type Error: ::std::error::Error; - - /// Null node type - const HASHED_NULL_NODE: H::Out; - - /// Decode bytes to a `Node`. Returns `Self::E` on failure. - fn decode(data: &[u8]) -> Result; - - /// Decode bytes to the `Hasher`s output type. Returns `None` on failure. - fn try_decode_hash(data: &[u8]) -> Option; - - /// Check if the provided bytes correspond to the codecs "empty" node. - fn is_empty_node(data: &[u8]) -> bool; - - /// Returns an empty node - fn empty_node() -> Vec; - - /// Returns an encoded leaft node - fn leaf_node(partial: &[u8], value: &[u8]) -> Vec; - - /// Returns an encoded extension node - fn ext_node(partial: &[u8], child_ref: ChildReference) -> Vec; - - /// Returns an encoded branch node. Takes an iterator yielding `ChildReference` and an optional value - fn branch_node(children: I, value: Option>) -> Vec - where I: IntoIterator>>; -} diff --git a/patricia_trie/src/recorder.rs b/patricia_trie/src/recorder.rs deleted file mode 100644 index 6d6d81c..0000000 --- a/patricia_trie/src/recorder.rs +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Trie query recorder. - -use bytes::Bytes; - -/// A record of a visited node. -#[derive(PartialEq, Eq, Debug, Clone)] -pub struct Record { - /// The depth of this node. - pub depth: u32, - - /// The raw data of the node. - pub data: Bytes, - - /// The hash of the data. - pub hash: HO, -} - -/// Records trie nodes as they pass it. -#[derive(Debug)] -pub struct Recorder { - nodes: Vec>, - min_depth: u32, -} - -impl Default for Recorder { - fn default() -> Self { - Recorder::new() - } -} - -impl Recorder { - /// Create a new `Recorder` which records all given nodes. - #[inline] - pub fn new() -> Self { - Recorder::with_depth(0) - } - - /// Create a `Recorder` which only records nodes beyond a given depth. - pub fn with_depth(depth: u32) -> Self { - Recorder { - nodes: Vec::new(), - min_depth: depth, - } - } - - /// Record a visited node, given its hash, data, and depth. - pub fn record(&mut self, hash: &HO, data: &[u8], depth: u32) { - if depth >= self.min_depth { - self.nodes.push(Record { - depth: depth, - data: data.into(), - hash: *hash, - }) - } - } - - /// Drain all visited records. - pub fn drain(&mut self) -> Vec> { - ::std::mem::replace(&mut self.nodes, Vec::new()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use keccak::keccak; - use keccak_hasher::KeccakHasher; - use ethereum_types::H256; - - #[test] - fn basic_recorder() { - let mut basic = Recorder::::new(); - - let node1 = vec![1, 2, 3, 4]; - let node2 = vec![4, 5, 6, 7, 8, 9, 10]; - - let (hash1, hash2) = (keccak(&node1), keccak(&node2)); - basic.record(&hash1, &node1, 0); - basic.record(&hash2, &node2, 456); - - let record1 = Record { - data: node1, - hash: hash1, - depth: 0, - }; - - let record2 = Record { - data: node2, - hash: hash2, - depth: 456, - }; - - - assert_eq!(basic.drain(), vec![record1, record2]); - } - - #[test] - fn basic_recorder_min_depth() { - let mut basic = Recorder::::with_depth(400); - - let node1 = vec![1, 2, 3, 4]; - let node2 = vec![4, 5, 6, 7, 8, 9, 10]; - - let hash1 = keccak(&node1); - let hash2 = keccak(&node2); - basic.record(&hash1, &node1, 0); - basic.record(&hash2, &node2, 456); - - let records = basic.drain(); - - assert_eq!(records.len(), 1); - - assert_eq!(records[0].clone(), Record { - data: node2, - hash: hash2, - depth: 456, - }); - } - - #[test] - fn trie_record() { - use ethtrie::trie::{Trie, TrieMut, Recorder}; - use memorydb::MemoryDB; - use ethtrie::{TrieDB, TrieDBMut}; - use DBValue; - - let mut db = MemoryDB::::new(); - - let mut root = H256::default(); - - { - let mut x = TrieDBMut::new(&mut db, &mut root); - - x.insert(b"dog", b"cat").unwrap(); - x.insert(b"lunch", b"time").unwrap(); - x.insert(b"notdog", b"notcat").unwrap(); - x.insert(b"hotdog", b"hotcat").unwrap(); - x.insert(b"letter", b"confusion").unwrap(); - x.insert(b"insert", b"remove").unwrap(); - x.insert(b"pirate", b"aargh!").unwrap(); - x.insert(b"yo ho ho", b"and a bottle of rum").unwrap(); - } - - let trie = TrieDB::new(&db, &root).unwrap(); - let mut recorder = Recorder::::new(); - - trie.get_with(b"pirate", &mut recorder).unwrap().unwrap(); - - let nodes: Vec<_> = recorder.drain().into_iter().map(|r| r.data).collect(); - assert_eq!(nodes, vec![ - vec![ - 248, 81, 128, 128, 128, 128, 128, 128, 160, 50, 19, 71, 57, 213, 63, 125, 149, - 92, 119, 88, 96, 80, 126, 59, 11, 160, 142, 98, 229, 237, 200, 231, 224, 79, 118, - 215, 93, 144, 246, 179, 176, 160, 118, 211, 171, 199, 172, 136, 136, 240, 221, 59, - 110, 82, 86, 54, 23, 95, 48, 108, 71, 125, 59, 51, 253, 210, 18, 116, 79, 0, 236, - 102, 142, 48, 128, 128, 128, 128, 128, 128, 128, 128, 128 - ], - vec![ - 248, 60, 206, 134, 32, 105, 114, 97, 116, 101, 134, 97, 97, 114, 103, 104, 33, - 128, 128, 128, 128, 128, 128, 128, 128, 221, 136, 32, 111, 32, 104, 111, 32, 104, - 111, 147, 97, 110, 100, 32, 97, 32, 98, 111, 116, 116, 108, 101, 32, 111, 102, - 32, 114, 117, 109, 128, 128, 128, 128, 128, 128, 128 - ] - ]); - - trie.get_with(b"letter", &mut recorder).unwrap().unwrap(); - - let nodes: Vec<_> = recorder.drain().into_iter().map(|r| r.data).collect(); - assert_eq!(nodes, vec![ - vec![ - 248, 81, 128, 128, 128, 128, 128, 128, 160, 50, 19, 71, 57, 213, 63, 125, 149, - 92, 119, 88, 96, 80, 126, 59, 11, 160, 142, 98, 229, 237, 200, 231, 224, 79, 118, - 215, 93, 144, 246, 179, 176, 160, 118, 211, 171, 199, 172, 136, 136, 240, 221, - 59, 110, 82, 86, 54, 23, 95, 48, 108, 71, 125, 59, 51, 253, 210, 18, 116, 79, - 0, 236, 102, 142, 48, 128, 128, 128, 128, 128, 128, 128, 128, 128 - ], - vec![ - 248, 99, 128, 128, 128, 128, 200, 131, 32, 111, 103, 131, 99, 97, 116, 128, 128, - 128, 206, 134, 32, 111, 116, 100, 111, 103, 134, 104, 111, 116, 99, 97, 116, 206, - 134, 32, 110, 115, 101, 114, 116, 134, 114, 101, 109, 111, 118, 101, 128, 128, - 160, 202, 250, 252, 153, 229, 63, 255, 13, 100, 197, 80, 120, 190, 186, 92, 5, - 255, 135, 245, 205, 180, 213, 161, 8, 47, 107, 13, 105, 218, 1, 9, 5, 128, - 206, 134, 32, 111, 116, 100, 111, 103, 134, 110, 111, 116, 99, 97, 116, 128, 128 - ], - vec![ - 235, 128, 128, 128, 128, 128, 128, 208, 133, 53, 116, 116, 101, 114, 137, 99, - 111, 110, 102, 117, 115, 105, 111, 110, 202, 132, 53, 110, 99, 104, 132, 116, - 105, 109, 101, 128, 128, 128, 128, 128, 128, 128, 128, 128 - ] - ]); - } -} diff --git a/patricia_trie/src/sectriedb.rs b/patricia_trie/src/sectriedb.rs deleted file mode 100644 index c4a2e82..0000000 --- a/patricia_trie/src/sectriedb.rs +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use hashdb::{HashDB, Hasher}; -use super::triedb::TrieDB; -use super::{Result, DBValue, Trie, TrieItem, TrieIterator, Query}; -use node_codec::NodeCodec; - -/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. -/// -/// Use it as a `Trie` trait object. You can use `raw()` to get the backing `TrieDB` object. -pub struct SecTrieDB<'db, H, C> -where - H: Hasher + 'db, - C: NodeCodec -{ - raw: TrieDB<'db, H, C> -} - -impl<'db, H, C> SecTrieDB<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - /// Create a new trie with the backing database `db` and empty `root` - /// - /// Initialise to the state entailed by the genesis block. - /// This guarantees the trie is built correctly. - /// Returns an error if root does not exist. - pub fn new(db: &'db HashDB, root: &'db H::Out) -> Result { - Ok(SecTrieDB { raw: TrieDB::new(db, root)? }) - } - - /// Get a reference to the underlying raw `TrieDB` struct. - pub fn raw(&self) -> &TrieDB { - &self.raw - } - - /// Get a mutable reference to the underlying raw `TrieDB` struct. - pub fn raw_mut(&mut self) -> &mut TrieDB<'db, H, C> { - &mut self.raw - } -} - -impl<'db, H, C> Trie for SecTrieDB<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - fn root(&self) -> &H::Out { self.raw.root() } - - fn contains(&self, key: &[u8]) -> Result { - self.raw.contains(H::hash(key).as_ref()) - } - - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> Result, H::Out, C::Error> - where 'a: 'key - { - self.raw.get_with(H::hash(key).as_ref(), query) - } - - fn iter<'a>(&'a self) -> Result> + 'a>, H::Out, C::Error> { - TrieDB::iter(&self.raw) - } -} - -#[cfg(test)] -mod test { - use memorydb::MemoryDB; - use keccak; - use keccak_hasher::KeccakHasher; - use ethtrie::{TrieDBMut, SecTrieDB, trie::{Trie, TrieMut}}; - use ethereum_types::H256; - use DBValue; - - #[test] - fn trie_to_sectrie() { - let mut db = MemoryDB::::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut db, &mut root); - t.insert(&keccak::keccak(&[0x01u8, 0x23]), &[0x01u8, 0x23]).unwrap(); - } - let t = SecTrieDB::new(&db, &root).unwrap(); - assert_eq!(t.get(&[0x01u8, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); - } -} diff --git a/patricia_trie/src/sectriedbmut.rs b/patricia_trie/src/sectriedbmut.rs deleted file mode 100644 index e5cc351..0000000 --- a/patricia_trie/src/sectriedbmut.rs +++ /dev/null @@ -1,110 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use hashdb::{HashDB, Hasher}; -use super::{Result, DBValue, TrieMut, TrieDBMut}; -use node_codec::NodeCodec; - -/// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database. -/// -/// Use it as a `Trie` or `TrieMut` trait object. You can use `raw()` to get the backing `TrieDBMut` object. -pub struct SecTrieDBMut<'db, H, C> -where - H: Hasher + 'db, - C: NodeCodec -{ - raw: TrieDBMut<'db, H, C> -} - -impl<'db, H, C> SecTrieDBMut<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - /// Create a new trie with the backing database `db` and empty `root` - /// Initialise to the state entailed by the genesis block. - /// This guarantees the trie is built correctly. - pub fn new(db: &'db mut HashDB, root: &'db mut H::Out) -> Self { - SecTrieDBMut { raw: TrieDBMut::new(db, root) } - } - - /// Create a new trie with the backing database `db` and `root`. - /// - /// Returns an error if root does not exist. - pub fn from_existing(db: &'db mut HashDB, root: &'db mut H::Out) -> Result { - Ok(SecTrieDBMut { raw: TrieDBMut::from_existing(db, root)? }) - } - - /// Get the backing database. - pub fn db(&self) -> &HashDB { self.raw.db() } - - /// Get the backing database. - pub fn db_mut(&mut self) -> &mut HashDB { self.raw.db_mut() } -} - -impl<'db, H, C> TrieMut for SecTrieDBMut<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - fn root(&mut self) -> &H::Out { - self.raw.root() - } - - fn is_empty(&self) -> bool { - self.raw.is_empty() - } - - fn contains(&self, key: &[u8]) -> Result { - self.raw.contains(&H::hash(key).as_ref()) - } - - fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Result, H::Out, C::Error> - where 'a: 'key - { - self.raw.get(&H::hash(key).as_ref()) - } - - fn insert(&mut self, key: &[u8], value: &[u8]) -> Result, H::Out, C::Error> { - self.raw.insert(&H::hash(key).as_ref(), value) - } - - fn remove(&mut self, key: &[u8]) -> Result, H::Out, C::Error> { - self.raw.remove(&H::hash(key).as_ref()) - } -} - -#[cfg(test)] -mod test { - use memorydb::MemoryDB; - use keccak; - use keccak_hasher::KeccakHasher; - use ethtrie::{TrieDB, SecTrieDBMut, trie::{Trie, TrieMut}}; - use ethereum_types::H256; - use DBValue; - - #[test] - fn sectrie_to_trie() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - { - let mut t = SecTrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - } - let t = TrieDB::new(&memdb, &root).unwrap(); - assert_eq!(t.get(&keccak::keccak(&[0x01u8, 0x23])).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); - } -} diff --git a/patricia_trie/src/triedb.rs b/patricia_trie/src/triedb.rs deleted file mode 100644 index a2d53a4..0000000 --- a/patricia_trie/src/triedb.rs +++ /dev/null @@ -1,637 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -use std::fmt; -use hashdb::*; -use nibbleslice::NibbleSlice; -use super::node::{Node, OwnedNode}; -use node_codec::NodeCodec; -use super::lookup::Lookup; -use super::{Result, DBValue, Trie, TrieItem, TrieError, TrieIterator, Query}; -use bytes::Bytes; -use std::marker::PhantomData; -use std::borrow::Cow; - -/// A `Trie` implementation using a generic `HashDB` backing database, a `Hasher` -/// implementation to generate keys and a `NodeCodec` implementation to encode/decode -/// the nodes. -/// -/// Use it as a `Trie` trait object. You can use `db()` to get the backing database object. -/// Use `get` and `contains` to query values associated with keys in the trie. -/// -/// # Example -/// ``` -/// extern crate patricia_trie as trie; -/// extern crate patricia_trie_ethereum as ethtrie; -/// extern crate hashdb; -/// extern crate keccak_hasher; -/// extern crate memorydb; -/// extern crate ethereum_types; -/// -/// use trie::*; -/// use hashdb::*; -/// use keccak_hasher::KeccakHasher; -/// use memorydb::*; -/// use ethereum_types::H256; -/// use ethtrie::{TrieDB, TrieDBMut}; -/// -/// -/// fn main() { -/// let mut memdb = MemoryDB::::new(); -/// let mut root = H256::new(); -/// TrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar").unwrap(); -/// let t = TrieDB::new(&memdb, &root).unwrap(); -/// assert!(t.contains(b"foo").unwrap()); -/// assert_eq!(t.get(b"foo").unwrap().unwrap(), DBValue::from_slice(b"bar")); -/// } -/// ``` -pub struct TrieDB<'db, H, C> -where - H: Hasher + 'db, - C: NodeCodec -{ - db: &'db HashDB, - root: &'db H::Out, - /// The number of hashes performed so far in operations on this trie. - hash_count: usize, - codec_marker: PhantomData, -} - -impl<'db, H, C> TrieDB<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - /// Create a new trie with the backing database `db` and `root` - /// Returns an error if `root` does not exist - pub fn new(db: &'db HashDB, root: &'db H::Out) -> Result { - if !db.contains(root) { - Err(Box::new(TrieError::InvalidStateRoot(*root))) - } else { - Ok(TrieDB {db, root, hash_count: 0, codec_marker: PhantomData}) - } - } - - /// Get the backing database. - pub fn db(&'db self) -> &'db HashDB { self.db } - - /// Get the data of the root node. - fn root_data(&self) -> Result { - self.db - .get(self.root) - .ok_or_else(|| Box::new(TrieError::InvalidStateRoot(*self.root))) - } - - /// Given some node-describing data `node`, return the actual node RLP. - /// This could be a simple identity operation in the case that the node is sufficiently small, but - /// may require a database lookup. - fn get_raw_or_lookup(&'db self, node: &[u8]) -> Result, H::Out, C::Error> { - match C::try_decode_hash(node) { - Some(key) => { - self.db - .get(&key) - .map(|v| Cow::Owned(v)) - .ok_or_else(|| Box::new(TrieError::IncompleteDatabase(key))) - } - None => Ok(Cow::Owned(DBValue::from_slice(node))) - } - } -} - -impl<'db, H, C> Trie for TrieDB<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - fn root(&self) -> &H::Out { self.root } - - fn get_with<'a, 'key, Q: Query>(&'a self, key: &'key [u8], query: Q) -> Result, H::Out, C::Error> - where 'a: 'key - { - Lookup { - db: self.db, - query: query, - hash: self.root.clone(), - marker: PhantomData::, - }.look_up(NibbleSlice::new(key)) - } - - fn iter<'a>(&'a self) -> Result> + 'a>, H::Out, C::Error> { - TrieDBIterator::new(self).map(|iter| Box::new(iter) as Box<_>) - } -} - -// This is for pretty debug output only -struct TrieAwareDebugNode<'db, 'a, H, C> -where - H: Hasher + 'db, - C: NodeCodec + 'db -{ - trie: &'db TrieDB<'db, H, C>, - key: &'a[u8] -} - -impl<'db, 'a, H, C> fmt::Debug for TrieAwareDebugNode<'db, 'a, H, C> -where - H: Hasher, - C: NodeCodec -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Ok(node) = self.trie.get_raw_or_lookup(self.key) { - match C::decode(&node) { - Ok(Node::Leaf(slice, value)) => f.debug_struct("Node::Leaf") - .field("slice", &slice) - .field("value", &value) - .finish(), - Ok(Node::Extension(ref slice, ref item)) => f.debug_struct("Node::Extension") - .field("slice", &slice) - .field("item", &TrieAwareDebugNode{trie: self.trie, key: item}) - .finish(), - Ok(Node::Branch(ref nodes, ref value)) => { - let nodes: Vec> = nodes.into_iter().map(|n| TrieAwareDebugNode{trie: self.trie, key: n} ).collect(); - f.debug_struct("Node::Branch") - .field("nodes", &nodes) - .field("value", &value) - .finish() - }, - Ok(Node::Empty) => f.debug_struct("Node::Empty").finish(), - - Err(e) => f.debug_struct("BROKEN_NODE") - .field("key", &self.key) - .field("error", &format!("ERROR decoding node branch Rlp: {}", e)) - .finish() - } - } else { - f.debug_struct("BROKEN_NODE") - .field("key", &self.key) - .field("error", &"Not found") - .finish() - } - } -} - -impl<'db, H, C> fmt::Debug for TrieDB<'db, H, C> -where - H: Hasher, - C: NodeCodec -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let root_rlp = self.db.get(self.root).expect("Trie root not found!"); - f.debug_struct("TrieDB") - .field("hash_count", &self.hash_count) - .field("root", &TrieAwareDebugNode { - trie: self, - key: &root_rlp - }) - .finish() - } -} - -#[derive(Clone, Eq, PartialEq)] -enum Status { - Entering, - At, - AtChild(usize), - Exiting, -} - -#[derive(Eq, PartialEq)] -struct Crumb { - node: OwnedNode, - status: Status, -} - -impl Crumb { - /// Move on to next status in the node's sequence. - fn increment(&mut self) { - self.status = match (&self.status, &self.node) { - (_, &OwnedNode::Empty) => Status::Exiting, - (&Status::Entering, _) => Status::At, - (&Status::At, &OwnedNode::Branch(_)) => Status::AtChild(0), - (&Status::AtChild(x), &OwnedNode::Branch(_)) if x < 15 => Status::AtChild(x + 1), - _ => Status::Exiting, - } - } -} - -/// Iterator for going through all values in the trie. -pub struct TrieDBIterator<'a, H: Hasher + 'a, C: NodeCodec + 'a> { - db: &'a TrieDB<'a, H, C>, - trail: Vec, - key_nibbles: Bytes, -} - -impl<'a, H: Hasher, C: NodeCodec> TrieDBIterator<'a, H, C> { - /// Create a new iterator. - pub fn new(db: &'a TrieDB) -> Result, H::Out, C::Error> { - let mut r = TrieDBIterator { db, trail: Vec::with_capacity(8), key_nibbles: Vec::with_capacity(64) }; - db.root_data().and_then(|root| r.descend(&root))?; - Ok(r) - } - - fn seek<'key>(&mut self, node_data: &DBValue, mut key: NibbleSlice<'key>) -> Result<(), H::Out, C::Error> { - let mut node_data = Cow::Borrowed(node_data); - loop { - let (data, mid) = { - let node = C::decode(&node_data).expect("encoded data read from db; qed"); - match node { - Node::Leaf(slice, _) => { - if slice >= key { - self.trail.push(Crumb { - status: Status::Entering, - node: node.clone().into(), - }); - } else { - self.trail.push(Crumb { - status: Status::Exiting, - node: node.clone().into(), - }); - } - - self.key_nibbles.extend(slice.iter()); - return Ok(()) - }, - Node::Extension(ref slice, ref item) => { - if key.starts_with(slice) { - self.trail.push(Crumb { - status: Status::At, - node: node.clone().into(), - }); - self.key_nibbles.extend(slice.iter()); - let data = self.db.get_raw_or_lookup(&*item)?; - (data, slice.len()) - } else { - self.descend(&node_data)?; - return Ok(()) - } - }, - Node::Branch(ref nodes, _) => match key.is_empty() { - true => { - self.trail.push(Crumb { - status: Status::Entering, - node: node.clone().into(), - }); - return Ok(()) - }, - false => { - let i = key.at(0); - self.trail.push(Crumb { - status: Status::AtChild(i as usize), - node: node.clone().into(), - }); - self.key_nibbles.push(i); - let child = self.db.get_raw_or_lookup(&*nodes[i as usize])?; - (child, 1) - } - }, - _ => return Ok(()), - } - }; - - node_data = data; - key = key.mid(mid); - } - } - - /// Descend into a payload. - fn descend(&mut self, d: &[u8]) -> Result<(), H::Out, C::Error> { - let node_data = &self.db.get_raw_or_lookup(d)?; - let node = C::decode(&node_data).expect("encoded node read from db; qed"); - Ok(self.descend_into_node(node.into())) - } - - /// Descend into a payload. - fn descend_into_node(&mut self, node: OwnedNode) { - self.trail.push(Crumb { status: Status::Entering, node }); - match &self.trail.last().expect("just pushed item; qed").node { - &OwnedNode::Leaf(ref n, _) | &OwnedNode::Extension(ref n, _) => { - self.key_nibbles.extend((0..n.len()).map(|i| n.at(i))); - }, - _ => {} - } - } - - /// The present key. - fn key(&self) -> Bytes { - // collapse the key_nibbles down to bytes. - let nibbles = &self.key_nibbles; - let mut i = 1; - let mut result = Bytes::with_capacity(nibbles.len() / 2); - let len = nibbles.len(); - while i < len { - result.push(nibbles[i - 1] * 16 + nibbles[i]); - i += 2; - } - result - } -} - -impl<'a, H: Hasher, C: NodeCodec> TrieIterator for TrieDBIterator<'a, H, C> { - /// Position the iterator on the first element with key >= `key` - fn seek(&mut self, key: &[u8]) -> Result<(), H::Out, C::Error> { - self.trail.clear(); - self.key_nibbles.clear(); - let root_rlp = self.db.root_data()?; - self.seek(&root_rlp, NibbleSlice::new(key.as_ref())) - } -} - -impl<'a, H: Hasher, C: NodeCodec> Iterator for TrieDBIterator<'a, H, C> { - type Item = TrieItem<'a, H::Out, C::Error>; - - fn next(&mut self) -> Option { - enum IterStep<'b, O, E> { - Continue, - PopTrail, - Descend(Result, O, E>), - } - loop { - let iter_step = { - self.trail.last_mut()?.increment(); - let b = self.trail.last().expect("trail.last_mut().is_some(); qed"); - - match (b.status.clone(), &b.node) { - (Status::Exiting, n) => { - match *n { - OwnedNode::Leaf(ref n, _) | OwnedNode::Extension(ref n, _) => { - let l = self.key_nibbles.len(); - self.key_nibbles.truncate(l - n.len()); - }, - OwnedNode::Branch(_) => { self.key_nibbles.pop(); }, - _ => {} - } - IterStep::PopTrail - }, - (Status::At, &OwnedNode::Branch(ref branch)) if branch.has_value() => { - let value = branch.get_value().expect("already checked `has_value`"); - return Some(Ok((self.key(), DBValue::from_slice(value)))); - }, - (Status::At, &OwnedNode::Leaf(_, ref v)) => { - return Some(Ok((self.key(), v.clone()))); - }, - (Status::At, &OwnedNode::Extension(_, ref d)) => { - IterStep::Descend::(self.db.get_raw_or_lookup(&*d)) - }, - (Status::At, &OwnedNode::Branch(_)) => IterStep::Continue, - (Status::AtChild(i), &OwnedNode::Branch(ref branch)) if !branch[i].is_empty() => { - match i { - 0 => self.key_nibbles.push(0), - i => *self.key_nibbles.last_mut() - .expect("pushed as 0; moves sequentially; removed afterwards; qed") = i as u8, - } - IterStep::Descend::(self.db.get_raw_or_lookup(&branch[i])) - }, - (Status::AtChild(i), &OwnedNode::Branch(_)) => { - if i == 0 { - self.key_nibbles.push(0); - } - IterStep::Continue - }, - _ => panic!() // Should never see Entering or AtChild without a Branch here. - } - }; - - match iter_step { - IterStep::PopTrail => { - self.trail.pop(); - }, - IterStep::Descend::(Ok(d)) => { - let node = C::decode(&d).expect("encoded data read from db; qed"); - self.descend_into_node(node.into()) - }, - IterStep::Descend::(Err(e)) => { - return Some(Err(e)) - } - IterStep::Continue => {}, - } - } - } -} - -#[cfg(test)] -mod tests { - use DBValue; - use keccak_hasher::KeccakHasher; - use memorydb::MemoryDB; - use ethtrie::{TrieDB, TrieDBMut, RlpCodec, trie::{Trie, TrieMut, Lookup}}; - use ethereum_types::H256; - - #[test] - fn iterator() { - let d = vec![DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B")]; - - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for x in &d { - t.insert(x, x).unwrap(); - } - } - - let t = TrieDB::new(&memdb, &root).unwrap(); - assert_eq!(d.iter().map(|i| i.clone().into_vec()).collect::>(), t.iter().unwrap().map(|x| x.unwrap().0).collect::>()); - assert_eq!(d, t.iter().unwrap().map(|x| x.unwrap().1).collect::>()); - } - - #[test] - fn iterator_seek() { - let d = vec![ DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B") ]; - - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for x in &d { - t.insert(x, x).unwrap(); - } - } - - let t = TrieDB::new(&memdb, &root).unwrap(); - let mut iter = t.iter().unwrap(); - assert_eq!(iter.next().unwrap().unwrap(), (b"A".to_vec(), DBValue::from_slice(b"A"))); - iter.seek(b"!").unwrap(); - assert_eq!(d, iter.map(|x| x.unwrap().1).collect::>()); - let mut iter = t.iter().unwrap(); - iter.seek(b"A").unwrap(); - assert_eq!(d, &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"AA").unwrap(); - assert_eq!(&d[1..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"A!").unwrap(); - assert_eq!(&d[1..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"AB").unwrap(); - assert_eq!(&d[2..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"AB!").unwrap(); - assert_eq!(&d[3..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"B").unwrap(); - assert_eq!(&d[3..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - let mut iter = t.iter().unwrap(); - iter.seek(b"C").unwrap(); - assert_eq!(&d[4..], &iter.map(|x| x.unwrap().1).collect::>()[..]); - } - - #[test] - fn get_len() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(b"A", b"ABC").unwrap(); - t.insert(b"B", b"ABCBA").unwrap(); - } - - let t = TrieDB::new(&memdb, &root).unwrap(); - assert_eq!(t.get_with(b"A", |x: &[u8]| x.len()).unwrap(), Some(3)); - assert_eq!(t.get_with(b"B", |x: &[u8]| x.len()).unwrap(), Some(5)); - assert_eq!(t.get_with(b"C", |x: &[u8]| x.len()).unwrap(), None); - } - - #[test] - fn debug_output_supports_pretty_print() { - let d = vec![ DBValue::from_slice(b"A"), DBValue::from_slice(b"AA"), DBValue::from_slice(b"AB"), DBValue::from_slice(b"B") ]; - - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let root = { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - for x in &d { - t.insert(x, x).unwrap(); - } - t.root().clone() - }; - let t = TrieDB::new(&memdb, &root).unwrap(); - - assert_eq!(format!("{:?}", t), "TrieDB { hash_count: 0, root: Node::Extension { slice: 4, item: Node::Branch { nodes: [Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Branch { nodes: [Node::Empty, Node::Leaf { slice: , value: [65, 65] }, Node::Leaf { slice: , value: [65, 66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: Some([65]) }, Node::Leaf { slice: , value: [66] }, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty, Node::Empty], value: None } } }"); - assert_eq!(format!("{:#?}", t), -"TrieDB { - hash_count: 0, - root: Node::Extension { - slice: 4, - item: Node::Branch { - nodes: [ - Node::Empty, - Node::Branch { - nodes: [ - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Branch { - nodes: [ - Node::Empty, - Node::Leaf { - slice: , - value: [ - 65, - 65 - ] - }, - Node::Leaf { - slice: , - value: [ - 65, - 66 - ] - }, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty - ], - value: None - }, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty - ], - value: Some( - [ - 65 - ] - ) - }, - Node::Leaf { - slice: , - value: [ - 66 - ] - }, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty, - Node::Empty - ], - value: None - } - } -}"); - } - - #[test] - fn test_lookup_with_corrupt_data_returns_decoder_error() { - use rlp; - use ethereum_types::H512; - use std::marker::PhantomData; - use ethtrie::trie::NibbleSlice; - - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(b"A", b"ABC").unwrap(); - t.insert(b"B", b"ABCBA").unwrap(); - } - - let t = TrieDB::new(&memdb, &root).unwrap(); - - // query for an invalid data type to trigger an error - let q = rlp::decode::; - let lookup = Lookup::<_, RlpCodec, _>{ db: t.db(), query: q, hash: root, marker: PhantomData }; - let query_result = lookup.look_up(NibbleSlice::new(b"A")); - assert_eq!(query_result.unwrap().unwrap().unwrap_err(), rlp::DecoderError::RlpIsTooShort); - } -} diff --git a/patricia_trie/src/triedbmut.rs b/patricia_trie/src/triedbmut.rs deleted file mode 100644 index ebe585e..0000000 --- a/patricia_trie/src/triedbmut.rs +++ /dev/null @@ -1,1346 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! In-memory trie representation. - -use super::{Result, TrieError, TrieMut}; -use super::lookup::Lookup; -use super::node::Node as EncodedNode; -use node_codec::NodeCodec; -use super::{DBValue, node::NodeKey}; - -use bytes::ToPretty; -use hashdb::{HashDB, Hasher}; -use nibbleslice::NibbleSlice; - -use std::collections::{HashSet, VecDeque}; -use std::marker::PhantomData; -use std::mem; -use std::ops::Index; -use std::{fmt::Debug, hash::Hash}; - -// For lookups into the Node storage buffer. -// This is deliberately non-copyable. -#[derive(Debug)] -struct StorageHandle(usize); - -// Handles to nodes in the trie. -#[derive(Debug)] -enum NodeHandle { - /// Loaded into memory. - InMemory(StorageHandle), - /// Either a hash or an inline node - Hash(H), -} - -impl From for NodeHandle { - fn from(handle: StorageHandle) -> Self { - NodeHandle::InMemory(handle) - } -} - -fn empty_children() -> Box<[Option>; 16]> { - Box::new([ - None, None, None, None, None, None, None, None, - None, None, None, None, None, None, None, None, - ]) -} - -/// Node types in the Trie. -#[derive(Debug)] -enum Node { - /// Empty node. - Empty, - /// A leaf node contains the end of a key and a value. - /// This key is encoded from a `NibbleSlice`, meaning it contains - /// a flag indicating it is a leaf. - Leaf(NodeKey, DBValue), - /// An extension contains a shared portion of a key and a child node. - /// The shared portion is encoded from a `NibbleSlice` meaning it contains - /// a flag indicating it is an extension. - /// The child node is always a branch. - Extension(NodeKey, NodeHandle), - /// A branch has up to 16 children and an optional value. - Branch(Box<[Option>; 16]>, Option) -} - -impl Node -where - O: AsRef<[u8]> + AsMut<[u8]> + Default + Debug + PartialEq + Eq + Hash + Send + Sync + Clone + Copy -{ - // load an inline node into memory or get the hash to do the lookup later. - fn inline_or_hash( - node: &[u8], - db: &HashDB, - storage: &mut NodeStorage - ) -> NodeHandle - where - C: NodeCodec, - H: Hasher, - { - C::try_decode_hash(&node) - .map(NodeHandle::Hash) - .unwrap_or_else(|| { - let child = Node::from_encoded::(node, db, storage); - NodeHandle::InMemory(storage.alloc(Stored::New(child))) - }) - } - - // decode a node from encoded bytes without getting its children. - fn from_encoded(data: &[u8], db: &HashDB, storage: &mut NodeStorage) -> Self - where C: NodeCodec, - H: Hasher, - { - match C::decode(data).expect("encoded bytes read from db; qed") { - EncodedNode::Empty => Node::Empty, - EncodedNode::Leaf(k, v) => Node::Leaf(k.encoded(true), DBValue::from_slice(&v)), - EncodedNode::Extension(key, cb) => { - Node::Extension( - key.encoded(false), - Self::inline_or_hash::(cb, db, storage)) - } - EncodedNode::Branch(ref encoded_children, val) => { - let mut child = |i:usize| { - let raw = encoded_children[i]; - if !C::is_empty_node(raw) { - Some(Self::inline_or_hash::(raw, db, storage)) - } else { - None - } - }; - - let children = Box::new([ - child(0), child(1), child(2), child(3), - child(4), child(5), child(6), child(7), - child(8), child(9), child(10), child(11), - child(12), child(13), child(14), child(15), - ]); - - Node::Branch(children, val.map(DBValue::from_slice)) - } - } - } - - // TODO: parallelize - fn into_encoded(self, mut child_cb: F) -> Vec - where - C: NodeCodec, - F: FnMut(NodeHandle) -> ChildReference, - H: Hasher, - { - match self { - Node::Empty => C::empty_node(), - Node::Leaf(partial, value) => C::leaf_node(&partial, &value), - Node::Extension(partial, child) => C::ext_node(&partial, child_cb(child)), - Node::Branch(mut children, value) => { - C::branch_node( - // map the `NodeHandle`s from the Branch to `ChildReferences` - children.iter_mut() - .map(Option::take) - .map(|maybe_child| - maybe_child.map(|child| child_cb(child)) - ), - value - ) - } - } - } -} - -// post-inspect action. -enum Action { - // Replace a node with a new one. - Replace(Node), - // Restore the original node. This trusts that the node is actually the original. - Restore(Node), - // if it is a new node, just clears the storage. - Delete, -} - -// post-insert action. Same as action without delete -enum InsertAction { - // Replace a node with a new one. - Replace(Node), - // Restore the original node. - Restore(Node), -} - -impl InsertAction { - fn into_action(self) -> Action { - match self { - InsertAction::Replace(n) => Action::Replace(n), - InsertAction::Restore(n) => Action::Restore(n), - } - } - - // unwrap the node, disregarding replace or restore state. - fn unwrap_node(self) -> Node { - match self { - InsertAction::Replace(n) | InsertAction::Restore(n) => n, - } - } -} - -// What kind of node is stored here. -enum Stored { - // A new node. - New(Node), - // A cached node, loaded from the DB. - Cached(Node, H), -} - -/// Used to build a collection of child nodes from a collection of `NodeHandle`s -pub enum ChildReference { // `HO` is e.g. `H256`, i.e. the output of a `Hasher` - Hash(HO), - Inline(HO, usize), // usize is the length of the node data we store in the `H::Out` -} - -/// Compact and cache-friendly storage for Trie nodes. -struct NodeStorage { - nodes: Vec>, - free_indices: VecDeque, -} - -impl NodeStorage { - /// Create a new storage. - fn empty() -> Self { - NodeStorage { - nodes: Vec::new(), - free_indices: VecDeque::new(), - } - } - - /// Allocate a new node in the storage. - fn alloc(&mut self, stored: Stored) -> StorageHandle { - if let Some(idx) = self.free_indices.pop_front() { - self.nodes[idx] = stored; - StorageHandle(idx) - } else { - self.nodes.push(stored); - StorageHandle(self.nodes.len() - 1) - } - } - - /// Remove a node from the storage, consuming the handle and returning the node. - fn destroy(&mut self, handle: StorageHandle) -> Stored { - let idx = handle.0; - - self.free_indices.push_back(idx); - mem::replace(&mut self.nodes[idx], Stored::New(Node::Empty)) - } -} - -impl<'a, H> Index<&'a StorageHandle> for NodeStorage { - type Output = Node; - - fn index(&self, handle: &'a StorageHandle) -> &Node { - match self.nodes[handle.0] { - Stored::New(ref node) => node, - Stored::Cached(ref node, _) => node, - } - } -} - -/// A `Trie` implementation using a generic `HashDB` backing database. -/// -/// Use it as a `TrieMut` trait object. You can use `db()` to get the backing database object. -/// Note that changes are not committed to the database until `commit` is called. -/// Querying the root or dropping the trie will commit automatically. -/// -/// # Example -/// ``` -/// extern crate patricia_trie as trie; -/// extern crate patricia_trie_ethereum as ethtrie; -/// extern crate hashdb; -/// extern crate keccak_hash; -/// extern crate keccak_hasher; -/// extern crate memorydb; -/// extern crate ethereum_types; -/// -/// use keccak_hash::KECCAK_NULL_RLP; -/// use ethtrie::{TrieDBMut, trie::TrieMut}; -/// use trie::DBValue; -/// use keccak_hasher::KeccakHasher; -/// use memorydb::*; -/// use ethereum_types::H256; -/// -/// fn main() { -/// let mut memdb = MemoryDB::::new(); -/// let mut root = H256::new(); -/// let mut t = TrieDBMut::new(&mut memdb, &mut root); -/// assert!(t.is_empty()); -/// assert_eq!(*t.root(), KECCAK_NULL_RLP); -/// t.insert(b"foo", b"bar").unwrap(); -/// assert!(t.contains(b"foo").unwrap()); -/// assert_eq!(t.get(b"foo").unwrap().unwrap(), DBValue::from_slice(b"bar")); -/// t.remove(b"foo").unwrap(); -/// assert!(!t.contains(b"foo").unwrap()); -/// } -/// ``` -pub struct TrieDBMut<'a, H, C> -where - H: Hasher + 'a, - C: NodeCodec -{ - storage: NodeStorage, - db: &'a mut HashDB, - root: &'a mut H::Out, - root_handle: NodeHandle, - death_row: HashSet, - /// The number of hash operations this trie has performed. - /// Note that none are performed until changes are committed. - hash_count: usize, - marker: PhantomData, // TODO: rpheimer: "we could have the NodeCodec trait take &self to its methods and then we don't need PhantomData. we can just store an instance of C: NodeCodec in the trie struct. If it's a ZST it won't have any additional overhead anyway" -} - -impl<'a, H, C> TrieDBMut<'a, H, C> -where - H: Hasher, - C: NodeCodec -{ - /// Create a new trie with backing database `db` and empty `root`. - pub fn new(db: &'a mut HashDB, root: &'a mut H::Out) -> Self { - *root = C::HASHED_NULL_NODE; - let root_handle = NodeHandle::Hash(C::HASHED_NULL_NODE); - - TrieDBMut { - storage: NodeStorage::empty(), - db: db, - root: root, - root_handle: root_handle, - death_row: HashSet::new(), - hash_count: 0, - marker: PhantomData, - } - } - - /// Create a new trie with the backing database `db` and `root. - /// Returns an error if `root` does not exist. - pub fn from_existing(db: &'a mut HashDB, root: &'a mut H::Out) -> Result { - if !db.contains(root) { - return Err(Box::new(TrieError::InvalidStateRoot(*root))); - } - - let root_handle = NodeHandle::Hash(*root); - Ok(TrieDBMut { - storage: NodeStorage::empty(), - db: db, - root: root, - root_handle: root_handle, - death_row: HashSet::new(), - hash_count: 0, - marker: PhantomData, - }) - } - /// Get the backing database. - pub fn db(&self) -> &HashDB { - self.db - } - - /// Get the backing database mutably. - pub fn db_mut(&mut self) -> &mut HashDB { - self.db - } - - // cache a node by hash - fn cache(&mut self, hash: H::Out) -> Result { - let node_encoded = self.db.get(&hash).ok_or_else(|| Box::new(TrieError::IncompleteDatabase(hash)))?; - let node = Node::from_encoded::( - &node_encoded, - &*self.db, - &mut self.storage - ); - Ok(self.storage.alloc(Stored::Cached(node, hash))) - } - - // inspect a node, choosing either to replace, restore, or delete it. - // if restored or replaced, returns the new node along with a flag of whether it was changed. - fn inspect(&mut self, stored: Stored, inspector: F) -> Result, bool)>, H::Out, C::Error> - where F: FnOnce(&mut Self, Node) -> Result, H::Out, C::Error> { - Ok(match stored { - Stored::New(node) => match inspector(self, node)? { - Action::Restore(node) => Some((Stored::New(node), false)), - Action::Replace(node) => Some((Stored::New(node), true)), - Action::Delete => None, - }, - Stored::Cached(node, hash) => match inspector(self, node)? { - Action::Restore(node) => Some((Stored::Cached(node, hash), false)), - Action::Replace(node) => { - self.death_row.insert(hash); - Some((Stored::New(node), true)) - } - Action::Delete => { - self.death_row.insert(hash); - None - } - }, - }) - } - - // walk the trie, attempting to find the key's node. - fn lookup<'x, 'key>(&'x self, mut partial: NibbleSlice<'key>, handle: &NodeHandle) -> Result, H::Out, C::Error> - where 'x: 'key - { - let mut handle = handle; - loop { - let (mid, child) = match *handle { - NodeHandle::Hash(ref hash) => return Lookup{ - db: &*self.db, - query: DBValue::from_slice, - hash: hash.clone(), - marker: PhantomData::, - }.look_up(partial), - NodeHandle::InMemory(ref handle) => match self.storage[handle] { - Node::Empty => return Ok(None), - Node::Leaf(ref key, ref value) => { - if NibbleSlice::from_encoded(key).0 == partial { - return Ok(Some(DBValue::from_slice(value))); - } else { - return Ok(None); - } - } - Node::Extension(ref slice, ref child) => { - let slice = NibbleSlice::from_encoded(slice).0; - if partial.starts_with(&slice) { - (slice.len(), child) - } else { - return Ok(None); - } - } - Node::Branch(ref children, ref value) => { - if partial.is_empty() { - return Ok(value.as_ref().map(|v| DBValue::from_slice(v))); - } else { - let idx = partial.at(0); - match children[idx as usize].as_ref() { - Some(child) => (1, child), - None => return Ok(None), - } - } - } - } - }; - - partial = partial.mid(mid); - handle = child; - } - } - - /// insert a key-value pair into the trie, creating new nodes if necessary. - fn insert_at(&mut self, handle: NodeHandle, partial: NibbleSlice, value: DBValue, old_val: &mut Option) -> Result<(StorageHandle, bool), H::Out, C::Error> { - let h = match handle { - NodeHandle::InMemory(h) => h, - NodeHandle::Hash(h) => self.cache(h)?, - }; - let stored = self.storage.destroy(h); - let (new_stored, changed) = self.inspect(stored, move |trie, stored| { - trie.insert_inspector(stored, partial, value, old_val).map(|a| a.into_action()) - })?.expect("Insertion never deletes."); - - Ok((self.storage.alloc(new_stored), changed)) - } - - /// the insertion inspector. - fn insert_inspector(&mut self, node: Node, partial: NibbleSlice, value: DBValue, old_val: &mut Option) -> Result, H::Out, C::Error> { - trace!(target: "trie", "augmented (partial: {:?}, value: {:?})", partial, value.pretty()); - - Ok(match node { - Node::Empty => { - trace!(target: "trie", "empty: COMPOSE"); - InsertAction::Replace(Node::Leaf(partial.encoded(true), value)) - } - Node::Branch(mut children, stored_value) => { - trace!(target: "trie", "branch: ROUTE,AUGMENT"); - - if partial.is_empty() { - let unchanged = stored_value.as_ref() == Some(&value); - let branch = Node::Branch(children, Some(value)); - *old_val = stored_value; - - match unchanged { - true => InsertAction::Restore(branch), - false => InsertAction::Replace(branch), - } - } else { - let idx = partial.at(0) as usize; - let partial = partial.mid(1); - if let Some(child) = children[idx].take() { - // original had something there. recurse down into it. - let (new_child, changed) = self.insert_at(child, partial, value, old_val)?; - children[idx] = Some(new_child.into()); - if !changed { - // the new node we composed didn't change. that means our branch is untouched too. - return Ok(InsertAction::Restore(Node::Branch(children, stored_value))); - } - } else { - // original had nothing there. compose a leaf. - let leaf = self.storage.alloc(Stored::New(Node::Leaf(partial.encoded(true), value))); - children[idx] = Some(leaf.into()); - } - - InsertAction::Replace(Node::Branch(children, stored_value)) - } - } - Node::Leaf(encoded, stored_value) => { - let existing_key = NibbleSlice::from_encoded(&encoded).0; - let cp = partial.common_prefix(&existing_key); - if cp == existing_key.len() && cp == partial.len() { - trace!(target: "trie", "equivalent-leaf: REPLACE"); - // equivalent leaf. - let unchanged = stored_value == value; - *old_val = Some(stored_value); - - match unchanged { - // unchanged. restore - true => InsertAction::Restore(Node::Leaf(encoded.clone(), value)), - false => InsertAction::Replace(Node::Leaf(encoded.clone(), value)), - } - } else if cp == 0 { - trace!(target: "trie", "no-common-prefix, not-both-empty (exist={:?}; new={:?}): TRANSMUTE,AUGMENT", existing_key.len(), partial.len()); - - // one of us isn't empty: transmute to branch here - let mut children = empty_children(); - let branch = if existing_key.is_empty() { - // always replace since branch isn't leaf. - Node::Branch(children, Some(stored_value)) - } else { - let idx = existing_key.at(0) as usize; - let new_leaf = Node::Leaf(existing_key.mid(1).encoded(true), stored_value); - children[idx] = Some(self.storage.alloc(Stored::New(new_leaf)).into()); - - Node::Branch(children, None) - }; - - // always replace because whatever we get out here is not the branch we started with. - let branch_action = self.insert_inspector(branch, partial, value, old_val)?.unwrap_node(); - InsertAction::Replace(branch_action) - } else if cp == existing_key.len() { - trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp); - - // fully-shared prefix for an extension. - // make a stub branch and an extension. - let branch = Node::Branch(empty_children(), Some(stored_value)); - // augment the new branch. - let branch = self.insert_inspector(branch, partial.mid(cp), value, old_val)?.unwrap_node(); - - // always replace since we took a leaf and made an extension. - let branch_handle = self.storage.alloc(Stored::New(branch)).into(); - InsertAction::Replace(Node::Extension(existing_key.encoded(false), branch_handle)) - } else { - trace!(target: "trie", "partially-shared-prefix (exist={:?}; new={:?}; cp={:?}): AUGMENT-AT-END", existing_key.len(), partial.len(), cp); - - // partially-shared prefix for an extension. - // start by making a leaf. - let low = Node::Leaf(existing_key.mid(cp).encoded(true), stored_value); - - // augment it. this will result in the Leaf -> cp == 0 routine, - // which creates a branch. - let augmented_low = self.insert_inspector(low, partial.mid(cp), value, old_val)?.unwrap_node(); - - // make an extension using it. this is a replacement. - InsertAction::Replace(Node::Extension( - existing_key.encoded_leftmost(cp, false), - self.storage.alloc(Stored::New(augmented_low)).into() - )) - } - } - Node::Extension(encoded, child_branch) => { - let existing_key = NibbleSlice::from_encoded(&encoded).0; - let cp = partial.common_prefix(&existing_key); - if cp == 0 { - trace!(target: "trie", "no-common-prefix, not-both-empty (exist={:?}; new={:?}): TRANSMUTE,AUGMENT", existing_key.len(), partial.len()); - - // partial isn't empty: make a branch here - // extensions may not have empty partial keys. - assert!(!existing_key.is_empty()); - let idx = existing_key.at(0) as usize; - - let mut children = empty_children(); - children[idx] = if existing_key.len() == 1 { - // direct extension, just replace. - Some(child_branch) - } else { - // more work required after branching. - let ext = Node::Extension(existing_key.mid(1).encoded(false), child_branch); - Some(self.storage.alloc(Stored::New(ext)).into()) - }; - - // continue inserting. - let branch_action = self.insert_inspector(Node::Branch(children, None), partial, value, old_val)?.unwrap_node(); - InsertAction::Replace(branch_action) - } else if cp == existing_key.len() { - trace!(target: "trie", "complete-prefix (cp={:?}): AUGMENT-AT-END", cp); - - // fully-shared prefix. - - // insert into the child node. - let (new_child, changed) = self.insert_at(child_branch, partial.mid(cp), value, old_val)?; - let new_ext = Node::Extension(existing_key.encoded(false), new_child.into()); - - // if the child branch wasn't changed, meaning this extension remains the same. - match changed { - true => InsertAction::Replace(new_ext), - false => InsertAction::Restore(new_ext), - } - } else { - trace!(target: "trie", "partially-shared-prefix (exist={:?}; new={:?}; cp={:?}): AUGMENT-AT-END", existing_key.len(), partial.len(), cp); - - // partially-shared. - let low = Node::Extension(existing_key.mid(cp).encoded(false), child_branch); - // augment the extension. this will take the cp == 0 path, creating a branch. - let augmented_low = self.insert_inspector(low, partial.mid(cp), value, old_val)?.unwrap_node(); - - // always replace, since this extension is not the one we started with. - // this is known because the partial key is only the common prefix. - InsertAction::Replace(Node::Extension( - existing_key.encoded_leftmost(cp, false), - self.storage.alloc(Stored::New(augmented_low)).into() - )) - } - } - }) - } - - /// Remove a node from the trie based on key. - fn remove_at(&mut self, handle: NodeHandle, partial: NibbleSlice, old_val: &mut Option) -> Result, H::Out, C::Error> { - let stored = match handle { - NodeHandle::InMemory(h) => self.storage.destroy(h), - NodeHandle::Hash(h) => { - let handle = self.cache(h)?; - self.storage.destroy(handle) - } - }; - - let opt = self.inspect(stored, move |trie, node| trie.remove_inspector(node, partial, old_val))?; - - Ok(opt.map(|(new, changed)| (self.storage.alloc(new), changed))) - } - - /// the removal inspector - fn remove_inspector(&mut self, node: Node, partial: NibbleSlice, old_val: &mut Option) -> Result, H::Out, C::Error> { - Ok(match (node, partial.is_empty()) { - (Node::Empty, _) => Action::Delete, - (Node::Branch(c, None), true) => Action::Restore(Node::Branch(c, None)), - (Node::Branch(children, Some(val)), true) => { - *old_val = Some(val); - // always replace since we took the value out. - Action::Replace(self.fix(Node::Branch(children, None))?) - } - (Node::Branch(mut children, value), false) => { - let idx = partial.at(0) as usize; - if let Some(child) = children[idx].take() { - trace!(target: "trie", "removing value out of branch child, partial={:?}", partial); - match self.remove_at(child, partial.mid(1), old_val)? { - Some((new, changed)) => { - children[idx] = Some(new.into()); - let branch = Node::Branch(children, value); - match changed { - // child was changed, so we were too. - true => Action::Replace(branch), - // unchanged, so we are too. - false => Action::Restore(branch), - } - } - None => { - // the child we took was deleted. - // the node may need fixing. - trace!(target: "trie", "branch child deleted, partial={:?}", partial); - Action::Replace(self.fix(Node::Branch(children, value))?) - } - } - } else { - // no change needed. - Action::Restore(Node::Branch(children, value)) - } - } - (Node::Leaf(encoded, value), _) => { - if NibbleSlice::from_encoded(&encoded).0 == partial { - // this is the node we were looking for. Let's delete it. - *old_val = Some(value); - Action::Delete - } else { - // leaf the node alone. - trace!(target: "trie", "restoring leaf wrong partial, partial={:?}, existing={:?}", partial, NibbleSlice::from_encoded(&encoded).0); - Action::Restore(Node::Leaf(encoded, value)) - } - } - (Node::Extension(encoded, child_branch), _) => { - let (cp, existing_len) = { - let existing_key = NibbleSlice::from_encoded(&encoded).0; - (existing_key.common_prefix(&partial), existing_key.len()) - }; - if cp == existing_len { - // try to remove from the child branch. - trace!(target: "trie", "removing from extension child, partial={:?}", partial); - match self.remove_at(child_branch, partial.mid(cp), old_val)? { - Some((new_child, changed)) => { - let new_child = new_child.into(); - - // if the child branch was unchanged, then the extension is too. - // otherwise, this extension may need fixing. - match changed { - true => Action::Replace(self.fix(Node::Extension(encoded, new_child))?), - false => Action::Restore(Node::Extension(encoded, new_child)), - } - } - None => { - // the whole branch got deleted. - // that means that this extension is useless. - Action::Delete - } - } - } else { - // partway through an extension -- nothing to do here. - Action::Restore(Node::Extension(encoded, child_branch)) - } - } - }) - } - - /// Given a node which may be in an _invalid state_, fix it such that it is then in a valid - /// state. - /// - /// _invalid state_ means: - /// - Branch node where there is only a single entry; - /// - Extension node followed by anything other than a Branch node. - fn fix(&mut self, node: Node) -> Result, H::Out, C::Error> { - match node { - Node::Branch(mut children, value) => { - // if only a single value, transmute to leaf/extension and feed through fixed. - #[derive(Debug)] - enum UsedIndex { - None, - One(u8), - Many, - }; - let mut used_index = UsedIndex::None; - for i in 0..16 { - match (children[i].is_none(), &used_index) { - (false, &UsedIndex::None) => used_index = UsedIndex::One(i as u8), - (false, &UsedIndex::One(_)) => { - used_index = UsedIndex::Many; - break; - } - _ => continue, - } - } - - match (used_index, value) { - (UsedIndex::None, None) => panic!("Branch with no subvalues. Something went wrong."), - (UsedIndex::One(a), None) => { - // only one onward node. make an extension. - let new_partial = NibbleSlice::new_offset(&[a], 1).encoded(false); - let child = children[a as usize].take().expect("used_index only set if occupied; qed"); - let new_node = Node::Extension(new_partial, child); - self.fix(new_node) - } - (UsedIndex::None, Some(value)) => { - // make a leaf. - trace!(target: "trie", "fixing: branch -> leaf"); - Ok(Node::Leaf(NibbleSlice::new(&[]).encoded(true), value)) - } - (_, value) => { - // all is well. - trace!(target: "trie", "fixing: restoring branch"); - Ok(Node::Branch(children, value)) - } - } - } - Node::Extension(partial, child) => { - let stored = match child { - NodeHandle::InMemory(h) => self.storage.destroy(h), - NodeHandle::Hash(h) => { - let handle = self.cache(h)?; - self.storage.destroy(handle) - } - }; - - let (child_node, maybe_hash) = match stored { - Stored::New(node) => (node, None), - Stored::Cached(node, hash) => (node, Some(hash)) - }; - - match child_node { - Node::Extension(sub_partial, sub_child) => { - // combine with node below. - if let Some(hash) = maybe_hash { - // delete the cached child since we are going to replace it. - self.death_row.insert(hash); - } - let partial = NibbleSlice::from_encoded(&partial).0; - let sub_partial = NibbleSlice::from_encoded(&sub_partial).0; - - let new_partial = NibbleSlice::new_composed(&partial, &sub_partial); - trace!(target: "trie", "fixing: extension combination. new_partial={:?}", new_partial); - self.fix(Node::Extension(new_partial.encoded(false), sub_child)) - } - Node::Leaf(sub_partial, value) => { - // combine with node below. - if let Some(hash) = maybe_hash { - // delete the cached child since we are going to replace it. - self.death_row.insert(hash); - } - let partial = NibbleSlice::from_encoded(&partial).0; - let sub_partial = NibbleSlice::from_encoded(&sub_partial).0; - - let new_partial = NibbleSlice::new_composed(&partial, &sub_partial); - trace!(target: "trie", "fixing: extension -> leaf. new_partial={:?}", new_partial); - Ok(Node::Leaf(new_partial.encoded(true), value)) - } - child_node => { - trace!(target: "trie", "fixing: restoring extension"); - - // reallocate the child node. - let stored = if let Some(hash) = maybe_hash { - Stored::Cached(child_node, hash) - } else { - Stored::New(child_node) - }; - - Ok(Node::Extension(partial, self.storage.alloc(stored).into())) - } - } - } - other => Ok(other), // only ext and branch need fixing. - } - } - - /// Commit the in-memory changes to disk, freeing their storage and - /// updating the state root. - pub fn commit(&mut self) { - trace!(target: "trie", "Committing trie changes to db."); - - // always kill all the nodes on death row. - trace!(target: "trie", "{:?} nodes to remove from db", self.death_row.len()); - for hash in self.death_row.drain() { - self.db.remove(&hash); - } - - let handle = match self.root_handle() { - NodeHandle::Hash(_) => return, // no changes necessary. - NodeHandle::InMemory(h) => h, - }; - - match self.storage.destroy(handle) { - Stored::New(node) => { - let encoded_root = node.into_encoded::<_, C, H>(|child| self.commit_child(child) ); - *self.root = self.db.insert(&encoded_root[..]); - self.hash_count += 1; - - trace!(target: "trie", "encoded root node: {:?}", (&encoded_root[..]).pretty()); - self.root_handle = NodeHandle::Hash(*self.root); - } - Stored::Cached(node, hash) => { - // probably won't happen, but update the root and move on. - *self.root = hash; - self.root_handle = NodeHandle::InMemory(self.storage.alloc(Stored::Cached(node, hash))); - } - } - } - - /// Commit a node by hashing it and writing it to the db. Returns a - /// `ChildReference` which in most cases carries a normal hash but for the - /// case where we can fit the actual data in the `Hasher`s output type, we - /// store the data inline. This function is used as the callback to the - /// `into_encoded` method of `Node`. - fn commit_child(&mut self, handle: NodeHandle) -> ChildReference { - match handle { - NodeHandle::Hash(hash) => ChildReference::Hash(hash), - NodeHandle::InMemory(storage_handle) => { - match self.storage.destroy(storage_handle) { - Stored::Cached(_, hash) => ChildReference::Hash(hash), - Stored::New(node) => { - let encoded = node.into_encoded::<_, C, H>(|node_handle| self.commit_child(node_handle) ); - if encoded.len() >= H::LENGTH { - let hash = self.db.insert(&encoded[..]); - self.hash_count +=1; - ChildReference::Hash(hash) - } else { - // it's a small value, so we cram it into a `H::Out` and tag with length - let mut h = H::Out::default(); - let len = encoded.len(); - h.as_mut()[..len].copy_from_slice(&encoded[..len]); - ChildReference::Inline(h, len) - } - } - } - } - } - } - - // a hack to get the root node's handle - fn root_handle(&self) -> NodeHandle { - match self.root_handle { - NodeHandle::Hash(h) => NodeHandle::Hash(h), - NodeHandle::InMemory(StorageHandle(x)) => NodeHandle::InMemory(StorageHandle(x)), - } - } -} - -impl<'a, H, C> TrieMut for TrieDBMut<'a, H, C> -where - H: Hasher, - C: NodeCodec -{ - fn root(&mut self) -> &H::Out { - self.commit(); - self.root - } - - fn is_empty(&self) -> bool { - match self.root_handle { - NodeHandle::Hash(h) => h == C::HASHED_NULL_NODE, - NodeHandle::InMemory(ref h) => match self.storage[h] { - Node::Empty => true, - _ => false, - } - } - } - - fn get<'x, 'key>(&'x self, key: &'key [u8]) -> Result, H::Out, C::Error> - where 'x: 'key - { - self.lookup(NibbleSlice::new(key), &self.root_handle) - } - - fn insert(&mut self, key: &[u8], value: &[u8]) -> Result, H::Out, C::Error> { - if value.is_empty() { return self.remove(key) } - - let mut old_val = None; - - trace!(target: "trie", "insert: key={:?}, value={:?}", key.pretty(), value.pretty()); - - let root_handle = self.root_handle(); - let (new_handle, changed) = self.insert_at( - root_handle, - NibbleSlice::new(key), - DBValue::from_slice(value), - &mut old_val, - )?; - - trace!(target: "trie", "insert: altered trie={}", changed); - self.root_handle = NodeHandle::InMemory(new_handle); - - Ok(old_val) - } - - fn remove(&mut self, key: &[u8]) -> Result, H::Out, C::Error> { - trace!(target: "trie", "remove: key={:?}", key.pretty()); - - let root_handle = self.root_handle(); - let key = NibbleSlice::new(key); - let mut old_val = None; - - match self.remove_at(root_handle, key, &mut old_val)? { - Some((handle, changed)) => { - trace!(target: "trie", "remove: altered trie={}", changed); - self.root_handle = NodeHandle::InMemory(handle); - } - None => { - trace!(target: "trie", "remove: obliterated trie"); - self.root_handle = NodeHandle::Hash(C::HASHED_NULL_NODE); - *self.root = C::HASHED_NULL_NODE; - } - } - - Ok(old_val) - } -} - -impl<'a, H, C> Drop for TrieDBMut<'a, H, C> -where - H: Hasher, - C: NodeCodec -{ - fn drop(&mut self) { - self.commit(); - } -} - -#[cfg(test)] -mod tests { - use bytes::ToPretty; - use hashdb::{Hasher, HashDB}; - use keccak_hasher::KeccakHasher; - use memorydb::MemoryDB; - use rlp::{Decodable, Encodable}; - use triehash::trie_root; - use standardmap::*; - use ethtrie::{TrieDBMut, RlpCodec, trie::{TrieMut, NodeCodec}}; - use env_logger; - use ethereum_types::H256; - use DBValue; - - fn populate_trie<'db, H, C>( - db: &'db mut HashDB, - root: &'db mut H256, - v: &[(Vec, Vec)] - ) -> TrieDBMut<'db> - where - H: Hasher, - H::Out: Decodable + Encodable, - C: NodeCodec, - { - let mut t = TrieDBMut::new(db, root); - for i in 0..v.len() { - let key: &[u8]= &v[i].0; - let val: &[u8] = &v[i].1; - t.insert(key, val).unwrap(); - } - t - } - - fn unpopulate_trie<'db>(t: &mut TrieDBMut<'db>, v: &[(Vec, Vec)]) { - for i in v { - let key: &[u8]= &i.0; - t.remove(key).unwrap(); - } - } - - #[test] - fn playpen() { - env_logger::init(); - let mut seed = H256::new(); - for test_i in 0..10 { - if test_i % 50 == 0 { - debug!("{:?} of 10000 stress tests done", test_i); - } - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 100, - }.make_with(&mut seed); - - let real = trie_root::(x.clone()); - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut memtrie = populate_trie::<_, RlpCodec>(&mut memdb, &mut root, &x); - - memtrie.commit(); - if *memtrie.root() != real { - println!("TRIE MISMATCH"); - println!(""); - println!("{:?} vs {:?}", memtrie.root(), real); - for i in &x { - println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); - } - } - assert_eq!(*memtrie.root(), real); - unpopulate_trie(&mut memtrie, &x); - memtrie.commit(); - if *memtrie.root() != RlpCodec::HASHED_NULL_NODE { - println!("- TRIE MISMATCH"); - println!(""); - println!("{:?} vs {:?}", memtrie.root(), real); - for i in &x { - println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); - } - } - assert_eq!(*memtrie.root(), RlpCodec::HASHED_NULL_NODE); - } - } - - #[test] - fn init() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - assert_eq!(*t.root(), RlpCodec::HASHED_NULL_NODE); - } - - #[test] - fn insert_on_empty() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - assert_eq!(*t.root(), trie_root::(vec![ (vec![0x01u8, 0x23], vec![0x01u8, 0x23]) ])); - } - - #[test] - fn remove_to_empty() { - let big_value = b"00000000000000000000000000000000"; - - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t1 = TrieDBMut::new(&mut memdb, &mut root); - t1.insert(&[0x01, 0x23], big_value).unwrap(); - t1.insert(&[0x01, 0x34], big_value).unwrap(); - let mut memdb2 = MemoryDB::::new(); - let mut root2 = H256::new(); - let mut t2 = TrieDBMut::new(&mut memdb2, &mut root2); - - t2.insert(&[0x01], big_value).unwrap(); - t2.insert(&[0x01, 0x23], big_value).unwrap(); - t2.insert(&[0x01, 0x34], big_value).unwrap(); - t2.remove(&[0x01]).unwrap(); - } - - #[test] - fn insert_replace_root() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[0x01u8, 0x23], &[0x23u8, 0x45]).unwrap(); - assert_eq!(*t.root(), trie_root::(vec![ (vec![0x01u8, 0x23], vec![0x23u8, 0x45]) ])); - } - - #[test] - fn insert_make_branch_root() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[0x11u8, 0x23], &[0x11u8, 0x23]).unwrap(); - assert_eq!(*t.root(), trie_root::(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0x11u8, 0x23], vec![0x11u8, 0x23]) - ])); - } - - #[test] - fn insert_into_branch_root() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap(); - t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap(); - assert_eq!(*t.root(), trie_root::(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), - (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), - ])); - } - - #[test] - fn insert_value_into_branch_root() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[], &[0x0]).unwrap(); - assert_eq!(*t.root(), trie_root::(vec![ - (vec![], vec![0x0]), - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - ])); - } - - #[test] - fn insert_split_leaf() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[0x01u8, 0x34], &[0x01u8, 0x34]).unwrap(); - assert_eq!(*t.root(), trie_root::(vec![ - (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), - (vec![0x01u8, 0x34], vec![0x01u8, 0x34]), - ])); - } - - #[test] - fn insert_split_extenstion() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01, 0x23, 0x45], &[0x01]).unwrap(); - t.insert(&[0x01, 0xf3, 0x45], &[0x02]).unwrap(); - t.insert(&[0x01, 0xf3, 0xf5], &[0x03]).unwrap(); - assert_eq!(*t.root(), trie_root::(vec![ - (vec![0x01, 0x23, 0x45], vec![0x01]), - (vec![0x01, 0xf3, 0x45], vec![0x02]), - (vec![0x01, 0xf3, 0xf5], vec![0x03]), - ])); - } - - #[test] - fn insert_big_value() { - let big_value0 = b"00000000000000000000000000000000"; - let big_value1 = b"11111111111111111111111111111111"; - - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], big_value0).unwrap(); - t.insert(&[0x11u8, 0x23], big_value1).unwrap(); - assert_eq!(*t.root(), trie_root::(vec![ - (vec![0x01u8, 0x23], big_value0.to_vec()), - (vec![0x11u8, 0x23], big_value1.to_vec()) - ])); - } - - #[test] - fn insert_duplicate_value() { - let big_value = b"00000000000000000000000000000000"; - - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], big_value).unwrap(); - t.insert(&[0x11u8, 0x23], big_value).unwrap(); - assert_eq!(*t.root(), trie_root::(vec![ - (vec![0x01u8, 0x23], big_value.to_vec()), - (vec![0x11u8, 0x23], big_value.to_vec()) - ])); - } - - #[test] - fn test_at_empty() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let t = TrieDBMut::new(&mut memdb, &mut root); - assert_eq!(t.get(&[0x5]).unwrap(), None); - } - - #[test] - fn test_at_one() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x1u8, 0x23])); - t.commit(); - assert_eq!(t.get(&[0x1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x1u8, 0x23])); - } - - #[test] - fn test_at_three() { - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut memdb, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]).unwrap(); - t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]).unwrap(); - assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); - assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0xf1u8, 0x23])); - assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x81u8, 0x23])); - assert_eq!(t.get(&[0x82, 0x23]).unwrap(), None); - t.commit(); - assert_eq!(t.get(&[0x01, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x01u8, 0x23])); - assert_eq!(t.get(&[0xf1, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0xf1u8, 0x23])); - assert_eq!(t.get(&[0x81, 0x23]).unwrap().unwrap(), DBValue::from_slice(&[0x81u8, 0x23])); - assert_eq!(t.get(&[0x82, 0x23]).unwrap(), None); - } - - #[test] - fn stress() { - let mut seed = H256::new(); - for _ in 0..50 { - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 4, - }.make_with(&mut seed); - - let real = trie_root::(x.clone()); - let mut memdb = MemoryDB::::new(); - let mut root = H256::new(); - let mut memtrie = populate_trie::<_, RlpCodec>(&mut memdb, &mut root, &x); - let mut y = x.clone(); - y.sort_by(|ref a, ref b| a.0.cmp(&b.0)); - let mut memdb2 = MemoryDB::::new(); - let mut root2 = H256::new(); - let mut memtrie_sorted = populate_trie::<_, RlpCodec>(&mut memdb2, &mut root2, &y); - if *memtrie.root() != real || *memtrie_sorted.root() != real { - println!("TRIE MISMATCH"); - println!(""); - println!("ORIGINAL... {:?}", memtrie.root()); - for i in &x { - println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); - } - println!("SORTED... {:?}", memtrie_sorted.root()); - for i in &y { - println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); - } - } - assert_eq!(*memtrie.root(), real); - assert_eq!(*memtrie_sorted.root(), real); - } - } - - #[test] - fn test_trie_existing() { - let mut db = MemoryDB::::new(); - let mut root = H256::new(); - { - let mut t = TrieDBMut::new(&mut db, &mut root); - t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]).unwrap(); - } - - { - let _ = TrieDBMut::from_existing(&mut db, &mut root); - } - } - - #[test] - fn insert_empty() { - let mut seed = H256::new(); - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 4, - }.make_with(&mut seed); - - let mut db = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut db, &mut root); - for &(ref key, ref value) in &x { - t.insert(key, value).unwrap(); - } - - assert_eq!(*t.root(), trie_root::(x.clone())); - - for &(ref key, _) in &x { - t.insert(key, &[]).unwrap(); - } - - assert!(t.is_empty()); - assert_eq!(*t.root(), RlpCodec::HASHED_NULL_NODE); - } - - #[test] - fn return_old_values() { - let mut seed = H256::new(); - let x = StandardMap { - alphabet: Alphabet::Custom(b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_".to_vec()), - min_key: 5, - journal_key: 0, - value_mode: ValueMode::Index, - count: 4, - }.make_with(&mut seed); - - let mut db = MemoryDB::::new(); - let mut root = H256::new(); - let mut t = TrieDBMut::new(&mut db, &mut root); - for &(ref key, ref value) in &x { - assert!(t.insert(key, value).unwrap().is_none()); - assert_eq!(t.insert(key, value).unwrap(), Some(DBValue::from_slice(value))); - } - - for (key, value) in x { - assert_eq!(t.remove(&key).unwrap(), Some(DBValue::from_slice(&value))); - assert!(t.remove(&key).unwrap().is_none()); - } - } -} diff --git a/test-support/keccak-hasher/Cargo.toml b/test-support/keccak-hasher/Cargo.toml deleted file mode 100644 index 53d07d0..0000000 --- a/test-support/keccak-hasher/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -name = "keccak-hasher" -version = "0.1.0" -authors = ["Parity Technologies "] -description = "Keccak-256 implementation of the Hasher trait" -repository = "https://github.com/paritytech/parity/" -license = "GPL-3.0" - -[dependencies] -ethereum-types = "0.4" -tiny-keccak = "1.4.2" -hashdb = { version = "0.3.0", path = "../../hashdb" } -plain_hasher = { path = "../../plain_hasher" } diff --git a/test-support/keccak-hasher/src/lib.rs b/test-support/keccak-hasher/src/lib.rs deleted file mode 100644 index b7237db..0000000 --- a/test-support/keccak-hasher/src/lib.rs +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2015-2018 Parity Technologies (UK) Ltd. -// This file is part of Parity. - -// Parity is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// Parity is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. - -// You should have received a copy of the GNU General Public License -// along with Parity. If not, see . - -//! Hasher implementation for the Keccak-256 hash -//! -//! This is deprecated in favor of trie crate. -extern crate hashdb; -extern crate ethereum_types; -extern crate tiny_keccak; -extern crate plain_hasher; - -use hashdb::Hasher; -use ethereum_types::H256; -use tiny_keccak::Keccak; -use plain_hasher::PlainHasher; -/// Concrete `Hasher` impl for the Keccak-256 hash -#[derive(Default, Debug, Clone, PartialEq)] -pub struct KeccakHasher; -impl Hasher for KeccakHasher { - type Out = H256; - type StdHasher = PlainHasher; - const LENGTH: usize = 32; - fn hash(x: &[u8]) -> Self::Out { - let mut out = [0;32]; - Keccak::keccak256(x, &mut out); - out.into() - } -}