Merge pull request #21 from gavofyork/triemut

Repot Trie and split into mutable and immutable variants.
This commit is contained in:
Arkadiy Paronyan 2015-12-19 13:56:03 +01:00
commit 58b68e0aef
13 changed files with 629 additions and 343 deletions

View File

@ -55,7 +55,7 @@ fn trie_insertions_six_high(b: &mut Bencher) {
b.iter(||{ b.iter(||{
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
for i in d.iter() { for i in d.iter() {
t.insert(&i.0, &i.1); t.insert(&i.0, &i.1);
} }
@ -90,7 +90,7 @@ fn trie_insertions_six_mid(b: &mut Bencher) {
b.iter(||{ b.iter(||{
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
for i in d.iter() { for i in d.iter() {
t.insert(&i.0, &i.1); t.insert(&i.0, &i.1);
} }
@ -127,7 +127,7 @@ fn trie_insertions_random_mid(b: &mut Bencher) {
b.iter(||{ b.iter(||{
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
for i in d.iter() { for i in d.iter() {
t.insert(&i.0, &i.1); t.insert(&i.0, &i.1);
} }
@ -164,7 +164,7 @@ fn trie_insertions_six_low(b: &mut Bencher) {
b.iter(||{ b.iter(||{
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
for i in d.iter() { for i in d.iter() {
t.insert(&i.0, &i.1); t.insert(&i.0, &i.1);
} }

View File

@ -54,8 +54,20 @@ impl<'a> fmt::Debug for PrettySlice<'a> {
} }
} }
impl<'a> fmt::Display for PrettySlice<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
for i in 0..self.0.len() {
try!(write!(f, "{:02x}", self.0[i]));
}
Ok(())
}
}
pub trait ToPretty { pub trait ToPretty {
fn pretty(&self) -> PrettySlice; fn pretty(&self) -> PrettySlice;
fn to_hex(&self) -> String {
format!("{}", self.pretty())
}
} }
impl<'a> ToPretty for &'a [u8] { impl<'a> ToPretty for &'a [u8] {

View File

@ -8,6 +8,8 @@ pub trait HashDB {
/// Get the keys in the database together with number of underlying references. /// Get the keys in the database together with number of underlying references.
fn keys(&self) -> HashMap<H256, i32>; fn keys(&self) -> HashMap<H256, i32>;
/// Deprecated. use `get`.
fn lookup(&self, key: &H256) -> Option<&[u8]>; // TODO: rename to get.
/// Look up a given hash into the bytes that hash to it, returning None if the /// Look up a given hash into the bytes that hash to it, returning None if the
/// hash is not known. /// hash is not known.
/// ///
@ -23,8 +25,10 @@ pub trait HashDB {
/// assert_eq!(m.lookup(&hash).unwrap(), hello_bytes); /// assert_eq!(m.lookup(&hash).unwrap(), hello_bytes);
/// } /// }
/// ``` /// ```
fn lookup(&self, key: &H256) -> Option<&[u8]>; fn get(&self, key: &H256) -> Option<&[u8]> { self.lookup(key) }
/// Deprecated. Use `contains`.
fn exists(&self, key: &H256) -> bool; // TODO: rename to contains.
/// Check for the existance of a hash-key. /// Check for the existance of a hash-key.
/// ///
/// # Examples /// # Examples
@ -43,7 +47,7 @@ pub trait HashDB {
/// assert!(!m.exists(&key)); /// assert!(!m.exists(&key));
/// } /// }
/// ``` /// ```
fn exists(&self, key: &H256) -> bool; fn contains(&self, key: &H256) -> bool { self.exists(key) }
/// Insert a datum item into the DB and return the datum's hash for a later lookup. Insertions /// 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 `kill()`s must be performed before the data /// are counted and the equivalent number of `kill()`s must be performed before the data
@ -66,6 +70,8 @@ pub trait HashDB {
/// Like `insert()` , except you provide the key and the data is all moved. /// Like `insert()` , except you provide the key and the data is all moved.
fn emplace(&mut self, key: H256, value: Bytes); fn emplace(&mut self, key: H256, value: Bytes);
/// Deprecated - use `remove`.
fn kill(&mut self, key: &H256); // TODO: rename to remove.
/// Remove a datum previously inserted. Insertions can be "owed" such that the same number of `insert()`s may /// 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. /// happen without the data being eventually being inserted into the DB.
/// ///
@ -87,5 +93,5 @@ pub trait HashDB {
/// assert_eq!(m.lookup(key).unwrap(), d); /// assert_eq!(m.lookup(key).unwrap(), d);
/// } /// }
/// ``` /// ```
fn kill(&mut self, key: &H256); fn remove(&mut self, key: &H256) { self.kill(key) }
} }

View File

@ -30,8 +30,8 @@
//! * You want to get view onto rlp-slice. //! * You want to get view onto rlp-slice.
//! * You don't want to decode whole rlp at once. //! * You don't want to decode whole rlp at once.
pub mod errors; pub mod rlptraits;
pub mod traits; pub mod rlperrors;
pub mod rlp; pub mod rlp;
pub mod untrusted_rlp; pub mod untrusted_rlp;
pub mod rlpstream; pub mod rlpstream;
@ -39,11 +39,15 @@ pub mod rlpstream;
#[cfg(test)] #[cfg(test)]
mod tests; mod tests;
pub use self::errors::DecoderError; pub use self::rlperrors::DecoderError;
pub use self::traits::{Decoder, Decodable, View, Stream, Encodable, Encoder}; pub use self::rlptraits::{Decoder, Decodable, View, Stream, Encodable, Encoder};
pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype}; pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype};
pub use self::rlp::{Rlp, RlpIterator}; pub use self::rlp::{Rlp, RlpIterator};
pub use self::rlpstream::{RlpStream}; pub use self::rlpstream::{RlpStream};
use super::hash::H256;
pub const NULL_RLP: [u8; 1] = [0x80; 1];
pub const SHA3_NULL_RLP: H256 = H256( [0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, 0xe0, 0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x01, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21] );
/// Shortcut function to decode trusted rlp /// Shortcut function to decode trusted rlp
/// ///

76
src/trie/journal.rs Normal file
View File

@ -0,0 +1,76 @@
use sha3::*;
use hash::H256;
use bytes::*;
use rlp::*;
use hashdb::*;
/// Type of operation for the backing database - either a new node or a node deletion.
#[derive(Debug)]
enum Operation {
New(H256, Bytes),
Delete(H256),
}
pub struct Score {
pub inserts: usize,
pub removes: usize,
}
/// A journal of operations on the backing database.
#[derive(Debug)]
pub struct Journal (Vec<Operation>);
impl Journal {
/// Create a new, empty, object.
pub fn new() -> Journal { Journal(vec![]) }
/// Given the RLP that encodes a node, append a reference to that node `out` and leave `journal`
/// such that the reference is valid, once applied.
pub fn new_node(&mut self, rlp: Bytes, out: &mut RlpStream) {
if rlp.len() >= 32 {
let rlp_sha3 = rlp.sha3();
trace!("new_node: reference node {:?} => {:?}", rlp_sha3, rlp.pretty());
out.append(&rlp_sha3);
self.0.push(Operation::New(rlp_sha3, rlp));
}
else {
trace!("new_node: inline node {:?}", rlp.pretty());
out.append_raw(&rlp, 1);
}
}
/// Given the RLP that encodes a now-unused node, leave `journal` in such a state that it is noted.
pub fn delete_node_sha3(&mut self, old_sha3: H256) {
trace!("delete_node: {:?}", old_sha3);
self.0.push(Operation::Delete(old_sha3));
}
/// Register an RLP-encoded node for deletion (given a slice), if it needs to be deleted.
pub fn delete_node(&mut self, old: &[u8]) {
let r = Rlp::new(old);
if r.is_data() && r.size() == 32 {
self.delete_node_sha3(r.as_val());
}
}
pub fn apply(self, db: &mut HashDB) -> Score {
trace!("applying {:?} changes", self.0.len());
let mut ret = Score{inserts: 0, removes: 0};
for d in self.0.into_iter() {
match d {
Operation::Delete(h) => {
trace!("TrieDBMut::apply --- {:?}", &h);
db.remove(&h);
ret.removes += 1;
},
Operation::New(h, d) => {
trace!("TrieDBMut::apply +++ {:?} -> {:?}", &h, d.pretty());
db.emplace(h, d);
ret.inserts += 1;
}
}
}
ret
}
}

11
src/trie/mod.rs Normal file
View File

@ -0,0 +1,11 @@
pub mod trietraits;
pub mod standardmap;
pub mod journal;
pub mod node;
pub mod triedb;
pub mod triedbmut;
pub use self::trietraits::*;
pub use self::standardmap::*;
pub use self::triedbmut::*;
pub use self::triedb::*;

121
src/trie/node.rs Normal file
View File

@ -0,0 +1,121 @@
use hash::*;
use nibbleslice::*;
use bytes::*;
use rlp::*;
use super::journal::*;
/// Type of node in the trie and essential information thereof.
#[derive(Eq, PartialEq, Debug)]
pub enum Node<'a> {
Empty,
Leaf(NibbleSlice<'a>, &'a[u8]),
Extension(NibbleSlice<'a>, &'a[u8]),
Branch([&'a[u8]; 16], Option<&'a [u8]>)
}
impl<'a> Node<'a> {
/// Decode the `node_rlp` and return the Node.
pub fn decoded(node_rlp: &'a [u8]) -> Node<'a> {
let r = Rlp::new(node_rlp);
match r.prototype() {
// either leaf or extension - decode first item with NibbleSlice::???
// and use is_leaf return to figure out which.
// if leaf, second item is a value (is_data())
// if extension, second item is a node (either SHA3 to be looked up and
// fed back into this function or inline RLP which can be fed back into this function).
Prototype::List(2) => match NibbleSlice::from_encoded(r.at(0).data()) {
(slice, true) => Node::Leaf(slice, r.at(1).data()),
(slice, false) => Node::Extension(slice, r.at(1).raw()),
},
// branch - first 16 are nodes, 17th is a value (or empty).
Prototype::List(17) => {
let mut nodes: [&'a [u8]; 16] = unsafe { ::std::mem::uninitialized() };
for i in 0..16 {
nodes[i] = r.at(i).raw();
}
Node::Branch(nodes, if r.at(16).is_empty() { None } else { Some(r.at(16).data()) })
},
// an empty branch index.
Prototype::Data(0) => Node::Empty,
// something went wrong.
_ => panic!("Rlp is not valid.")
}
}
/// Encode the node into RLP.
///
/// Will always return the direct node RLP even if it's 32 or more bytes. To get the
/// RLP which would be valid for using in another node, use `encoded_and_added()`.
pub fn encoded(&self) -> Bytes {
match *self {
Node::Leaf(ref slice, ref value) => {
let mut stream = RlpStream::new_list(2);
stream.append(&slice.encoded(true));
stream.append(value);
stream.out()
},
Node::Extension(ref slice, ref raw_rlp) => {
let mut stream = RlpStream::new_list(2);
stream.append(&slice.encoded(false));
stream.append_raw(raw_rlp, 1);
stream.out()
},
Node::Branch(ref nodes, ref value) => {
let mut stream = RlpStream::new_list(17);
for i in 0..16 {
stream.append_raw(nodes[i], 1);
}
match *value {
Some(n) => { stream.append(&n); },
None => { stream.append_empty_data(); },
}
stream.out()
},
Node::Empty => {
let mut stream = RlpStream::new();
stream.append_empty_data();
stream.out()
}
}
}
/// Encode the node, adding it to `journal` if necessary and return the RLP valid for
/// insertion into a parent node.
pub fn encoded_and_added(&self, journal: &mut Journal) -> Bytes {
let mut stream = RlpStream::new();
match *self {
Node::Leaf(ref slice, ref value) => {
stream.append_list(2);
stream.append(&slice.encoded(true));
stream.append(value);
},
Node::Extension(ref slice, ref raw_rlp) => {
stream.append_list(2);
stream.append(&slice.encoded(false));
stream.append_raw(raw_rlp, 1);
},
Node::Branch(ref nodes, ref value) => {
stream.append_list(17);
for i in 0..16 {
stream.append_raw(nodes[i], 1);
}
match *value {
Some(n) => { stream.append(&n); },
None => { stream.append_empty_data(); },
}
},
Node::Empty => {
stream.append_empty_data();
}
}
let node = stream.out();
match node.len() {
0 ... 31 => node,
_ => {
let mut stream = RlpStream::new();
journal.new_node(node, &mut stream);
stream.out()
}
}
}
}

75
src/trie/standardmap.rs Normal file
View File

@ -0,0 +1,75 @@
//! Key-value datastore with a modified Merkle tree.
extern crate rand;
use bytes::*;
use sha3::*;
use hash::*;
/// Alphabet to use when creating words for insertion into tries.
pub enum Alphabet {
All,
Low,
Mid,
Custom(Bytes),
}
/// Standard test map for profiling tries.
pub struct StandardMap {
alphabet: Alphabet,
min_key: usize,
journal_key: usize,
count: usize,
}
impl StandardMap {
/// Get a bunch of random bytes, at least `min_count` bytes, at most `min_count` + `journal_count` bytes.
/// `seed` is mutated pseudoramdonly and used.
fn random_bytes(min_count: usize, journal_count: usize, seed: &mut H256) -> Vec<u8> {
assert!(min_count + journal_count <= 32);
*seed = seed.sha3();
let r = min_count + (seed.bytes()[31] as usize % (journal_count + 1));
seed.bytes()[0..r].to_vec()
}
/// Get a random value. Equal chance of being 1 byte as of 32. `seed` is mutated pseudoramdonly and used.
fn random_value(seed: &mut H256) -> Bytes {
*seed = seed.sha3();
match seed.bytes()[0] % 2 {
1 => vec![seed.bytes()[31];1],
_ => seed.bytes().to_vec(),
}
}
/// Get a random word of, at least `min_count` bytes, at most `min_count` + `journal_count` bytes.
/// Each byte is an item from `alphabet`. `seed` is mutated pseudoramdonly and used.
fn random_word(alphabet: &[u8], min_count: usize, journal_count: usize, seed: &mut H256) -> Vec<u8> {
assert!(min_count + journal_count <= 32);
*seed = seed.sha3();
let r = min_count + (seed.bytes()[31] as usize % (journal_count + 1));
let mut ret: Vec<u8> = Vec::with_capacity(r);
for i in 0..r {
ret.push(alphabet[seed.bytes()[i] as usize % alphabet.len()]);
}
ret
}
/// Create the standard map (set of keys and values) for the object's fields.
pub fn make(&self) -> Vec<(Bytes, Bytes)> {
let low = b"abcdef";
let mid = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_";
let mut d: Vec<(Bytes, Bytes)> = Vec::new();
let mut seed = H256::new();
for _ in 0..self.count {
let k = match self.alphabet {
Alphabet::All => Self::random_bytes(self.min_key, self.journal_key, &mut seed),
Alphabet::Low => Self::random_word(low, self.min_key, self.journal_key, &mut seed),
Alphabet::Mid => Self::random_word(mid, self.min_key, self.journal_key, &mut seed),
Alphabet::Custom(ref a) => Self::random_word(&a, self.min_key, self.journal_key, &mut seed),
};
let v = Self::random_value(&mut seed);
d.push((k, v))
}
d
}
}

220
src/trie/triedb.rs Normal file
View File

@ -0,0 +1,220 @@
use std::fmt;
use hashdb::*;
use hash::*;
use nibbleslice::*;
use bytes::*;
use rlp::*;
use std::collections::HashMap;
use super::trietraits::*;
use super::node::*;
/// A `Trie` implementation using a generic `HashDB` backing database.
///
/// Use it as a `Trie` trait object. You can use `db()` to get the backing database object, `keys`
/// to get the keys belonging to the trie in the backing database, and `db_items_remaining()` to get
/// which items in the backing database do not belong to this trie. If this is the only trie in the
/// backing database, then `db_items_remaining()` should be empty.
///
/// # Example
/// ```
/// extern crate ethcore_util as util;
/// use util::trie::*;
/// use util::hashdb::*;
/// use util::memorydb::*;
/// use util::hash::*;
/// use util::rlp::*;
///
/// fn main() {
/// let mut memdb = MemoryDB::new();
/// let mut root = H256::new();
/// TrieDBMut::new(&mut memdb, &mut root).insert(b"foo", b"bar");
/// let t = TrieDB::new(&memdb, &root);
/// assert!(t.contains(b"foo"));
/// assert_eq!(t.get(b"foo").unwrap(), b"bar");
/// assert!(t.db_items_remaining().is_empty());
/// }
/// ```
pub struct TrieDB<'db> {
db: &'db HashDB,
root: &'db H256,
pub hash_count: usize,
}
impl<'db> TrieDB<'db> {
/// Create a new trie with the backing database `db` and `root`
/// Panics, if `root` does not exist
pub fn new(db: &'db HashDB, root: &'db H256) -> Self {
assert!(db.exists(root));
TrieDB {
db: db,
root: root,
hash_count: 0
}
}
/// Get the backing database.
pub fn db(&'db self) -> &'db HashDB {
self.db
}
/// Determine all the keys in the backing database that belong to the trie.
pub fn keys(&self) -> Vec<H256> {
let mut ret: Vec<H256> = Vec::new();
ret.push(self.root.clone());
self.accumulate_keys(self.root_node(), &mut ret);
ret
}
/// Convert a vector of hashes to a hashmap of hash to occurances.
pub fn to_map(hashes: Vec<H256>) -> HashMap<H256, u32> {
let mut r: HashMap<H256, u32> = HashMap::new();
for h in hashes.into_iter() {
let c = *r.get(&h).unwrap_or(&0);
r.insert(h, c + 1);
}
r
}
/// Determine occurances of items in the backing database which are not related to this
/// trie.
pub fn db_items_remaining(&self) -> HashMap<H256, i32> {
let mut ret = self.db.keys();
for (k, v) in Self::to_map(self.keys()).into_iter() {
let keycount = *ret.get(&k).unwrap_or(&0);
match keycount == v as i32 {
true => ret.remove(&k),
_ => ret.insert(k, keycount - v as i32),
};
}
ret
}
/// Recursion helper for `keys`.
fn accumulate_keys(&self, node: Node, acc: &mut Vec<H256>) {
let mut handle_payload = |payload| {
let p = Rlp::new(payload);
if p.is_data() && p.size() == 32 {
acc.push(p.as_val());
}
self.accumulate_keys(self.get_node(payload), acc);
};
match node {
Node::Extension(_, payload) => handle_payload(payload),
Node::Branch(payloads, _) => for payload in payloads.iter() { handle_payload(payload) },
_ => {},
}
}
/// Get the root node's RLP.
fn root_node(&self) -> Node {
Node::decoded(self.db.lookup(&self.root).expect("Trie root not found!"))
}
/// Get the root node as a `Node`.
fn get_node<'a>(&'a self, node: &'a [u8]) -> Node {
Node::decoded(self.get_raw_or_lookup(node))
}
/// Indentation helper for `formal_all`.
fn fmt_indent(&self, f: &mut fmt::Formatter, size: usize) -> fmt::Result {
for _ in 0..size {
try!(write!(f, " "));
}
Ok(())
}
/// Recursion helper for implementation of formatting trait.
fn fmt_all(&self, node: Node, f: &mut fmt::Formatter, deepness: usize) -> fmt::Result {
match node {
Node::Leaf(slice, value) => try!(writeln!(f, "'{:?}: {:?}.", slice, value.pretty())),
Node::Extension(ref slice, ref item) => {
try!(write!(f, "'{:?} ", slice));
try!(self.fmt_all(self.get_node(item), f, deepness));
},
Node::Branch(ref nodes, ref value) => {
try!(writeln!(f, ""));
match value {
&Some(v) => {
try!(self.fmt_indent(f, deepness + 1));
try!(writeln!(f, "=: {:?}", v.pretty()))
},
&None => {}
}
for i in 0..16 {
match self.get_node(nodes[i]) {
Node::Empty => {},
n => {
try!(self.fmt_indent(f, deepness + 1));
try!(write!(f, "'{:x} ", i));
try!(self.fmt_all(n, f, deepness + 1));
}
}
}
},
// empty
Node::Empty => {
try!(writeln!(f, "<empty>"));
}
};
Ok(())
}
/// Return optional data for a key given as a `NibbleSlice`. Returns `None` if no data exists.
fn do_lookup<'a, 'key>(&'a self, key: &NibbleSlice<'key>) -> Option<&'a [u8]> where 'a: 'key {
let root_rlp = self.db.lookup(&self.root).expect("Trie root not found!");
self.get_from_node(&root_rlp, key)
}
/// Recursible function to retrieve the value given a `node` and a partial `key`. `None` if no
/// value exists for the key.
///
/// Note: Not a public API; use Trie trait functions.
fn get_from_node<'a, 'key>(&'a self, node: &'a [u8], key: &NibbleSlice<'key>) -> Option<&'a [u8]> where 'a: 'key {
match Node::decoded(node) {
Node::Leaf(ref slice, ref value) if key == slice => Some(value),
Node::Extension(ref slice, ref item) if key.starts_with(slice) => {
self.get_from_node(self.get_raw_or_lookup(item), &key.mid(slice.len()))
},
Node::Branch(ref nodes, value) => match key.is_empty() {
true => value,
false => self.get_from_node(self.get_raw_or_lookup(nodes[key.at(0) as usize]), &key.mid(1))
},
_ => None
}
}
/// 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<'a>(&'a self, node: &'a [u8]) -> &'a [u8] {
// check if its sha3 + len
let r = Rlp::new(node);
match r.is_data() && r.size() == 32 {
true => self.db.lookup(&r.as_val::<H256>()).expect("Not found!"),
false => node
}
}
}
impl<'db> Trie for TrieDB<'db> {
fn root(&self) -> &H256 { &self.root }
fn contains(&self, key: &[u8]) -> bool {
self.get(key).is_some()
}
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.do_lookup(&NibbleSlice::new(key))
}
}
impl<'db> fmt::Debug for TrieDB<'db> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(writeln!(f, "c={:?} [", self.hash_count));
let root_rlp = self.db.lookup(&self.root).expect("Trie root not found!");
try!(self.fmt_all(Node::decoded(root_rlp), f, 0));
writeln!(f, "]")
}
}

View File

@ -1,272 +1,24 @@
//! Key-value datastore with a modified Merkle tree.
extern crate rand;
use std::fmt; use std::fmt;
use sha3::*;
use hashdb::*; use hashdb::*;
use hash::*; use hash::*;
use nibbleslice::*; use nibbleslice::*;
use bytes::*; use bytes::*;
use rlp::*; use rlp::*;
use std::collections::HashMap; use std::collections::HashMap;
use super::node::*;
use super::journal::*;
use super::trietraits::*;
//use log::*; pub struct TrieDBMut<'db> {
db: &'db mut HashDB,
pub const NULL_RLP: [u8; 1] = [0x80; 1]; root: &'db mut H256,
pub const SHA3_NULL_RLP: H256 = H256( [0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, 0xe0, 0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x01, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21] ); pub hash_count: usize,
/// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait Trie {
/// Return the root of the trie.
fn root(&self) -> &H256;
/// Is the trie empty?
fn is_empty(&self) -> bool { *self.root() == SHA3_NULL_RLP }
/// Does the trie contain a given key?
fn contains(&self, key: &[u8]) -> bool;
/// What is the value of the given key in this trie?
fn at<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key;
/// Insert a `key`/`value` pair into the trie. An `empty` value is equivalent to removing
/// `key` from the trie.
fn insert(&mut self, key: &[u8], value: &[u8]);
/// Remove a `key` from the trie. Equivalent to making it equal to the empty
/// value.
fn remove(&mut self, key: &[u8]);
} }
/// Alphabet to use when creating words for insertion into tries. /// Option-like type allowing either a Node object passthrough or Bytes in the case of data alteration.
pub enum Alphabet { enum MaybeChanged<'a> {
All, Same(Node<'a>),
Low, Changed(Bytes),
Mid,
Custom(Bytes),
}
/// Standard test map for profiling tries.
pub struct StandardMap {
alphabet: Alphabet,
min_key: usize,
journal_key: usize,
count: usize,
}
impl StandardMap {
/// Get a bunch of random bytes, at least `min_count` bytes, at most `min_count` + `journal_count` bytes.
/// `seed` is mutated pseudoramdonly and used.
fn random_bytes(min_count: usize, journal_count: usize, seed: &mut H256) -> Vec<u8> {
assert!(min_count + journal_count <= 32);
*seed = seed.sha3();
let r = min_count + (seed.bytes()[31] as usize % (journal_count + 1));
seed.bytes()[0..r].to_vec()
}
/// Get a random value. Equal chance of being 1 byte as of 32. `seed` is mutated pseudoramdonly and used.
fn random_value(seed: &mut H256) -> Bytes {
*seed = seed.sha3();
match seed.bytes()[0] % 2 {
1 => vec![seed.bytes()[31];1],
_ => seed.bytes().to_vec(),
}
}
/// Get a random word of, at least `min_count` bytes, at most `min_count` + `journal_count` bytes.
/// Each byte is an item from `alphabet`. `seed` is mutated pseudoramdonly and used.
fn random_word(alphabet: &[u8], min_count: usize, journal_count: usize, seed: &mut H256) -> Vec<u8> {
assert!(min_count + journal_count <= 32);
*seed = seed.sha3();
let r = min_count + (seed.bytes()[31] as usize % (journal_count + 1));
let mut ret: Vec<u8> = Vec::with_capacity(r);
for i in 0..r {
ret.push(alphabet[seed.bytes()[i] as usize % alphabet.len()]);
}
ret
}
/// Create the standard map (set of keys and values) for the object's fields.
pub fn make(&self) -> Vec<(Bytes, Bytes)> {
let low = b"abcdef";
let mid = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_";
let mut d: Vec<(Bytes, Bytes)> = Vec::new();
let mut seed = H256::new();
for _ in 0..self.count {
let k = match self.alphabet {
Alphabet::All => Self::random_bytes(self.min_key, self.journal_key, &mut seed),
Alphabet::Low => Self::random_word(low, self.min_key, self.journal_key, &mut seed),
Alphabet::Mid => Self::random_word(mid, self.min_key, self.journal_key, &mut seed),
Alphabet::Custom(ref a) => Self::random_word(&a, self.min_key, self.journal_key, &mut seed),
};
let v = Self::random_value(&mut seed);
d.push((k, v))
}
d
}
}
/// Type of node in the trie and essential information thereof.
#[derive(Eq, PartialEq, Debug)]
pub enum Node<'a> {
Empty,
Leaf(NibbleSlice<'a>, &'a[u8]),
Extension(NibbleSlice<'a>, &'a[u8]),
Branch([&'a[u8]; 16], Option<&'a [u8]>)
}
/// Type of operation for the backing database - either a new node or a node deletion.
#[derive(Debug)]
enum Operation {
New(H256, Bytes),
Delete(H256),
}
/// A journal of operations on the backing database.
#[derive(Debug)]
struct Journal (Vec<Operation>);
impl Journal {
/// Create a new, empty, object.
fn new() -> Journal { Journal(vec![]) }
/// Given the RLP that encodes a node, append a reference to that node `out` and leave `journal`
/// such that the reference is valid, once applied.
fn new_node(&mut self, rlp: Bytes, out: &mut RlpStream) {
if rlp.len() >= 32 {
let rlp_sha3 = rlp.sha3();
trace!("new_node: reference node {:?} => {:?}", rlp_sha3, rlp.pretty());
out.append(&rlp_sha3);
self.0.push(Operation::New(rlp_sha3, rlp));
}
else {
trace!("new_node: inline node {:?}", rlp.pretty());
out.append_raw(&rlp, 1);
}
}
/// Given the RLP that encodes a now-unused node, leave `journal` in such a state that it is noted.
fn delete_node_sha3(&mut self, old_sha3: H256) {
trace!("delete_node: {:?}", old_sha3);
self.0.push(Operation::Delete(old_sha3));
}
/// Register an RLP-encoded node for deletion (given a slice), if it needs to be deleted.
fn delete_node(&mut self, old: &[u8]) {
let r = Rlp::new(old);
if r.is_data() && r.size() == 32 {
self.delete_node_sha3(r.as_val());
}
}
}
impl <'a>Node<'a> {
/// Decode the `node_rlp` and return the Node.
fn decoded(node_rlp: &'a [u8]) -> Node<'a> {
let r = Rlp::new(node_rlp);
match r.prototype() {
// either leaf or extension - decode first item with NibbleSlice::???
// and use is_leaf return to figure out which.
// if leaf, second item is a value (is_data())
// if extension, second item is a node (either SHA3 to be looked up and
// fed back into this function or inline RLP which can be fed back into this function).
Prototype::List(2) => match NibbleSlice::from_encoded(r.at(0).data()) {
(slice, true) => Node::Leaf(slice, r.at(1).data()),
(slice, false) => Node::Extension(slice, r.at(1).raw()),
},
// branch - first 16 are nodes, 17th is a value (or empty).
Prototype::List(17) => {
let mut nodes: [&'a [u8]; 16] = unsafe { ::std::mem::uninitialized() };
for i in 0..16 {
nodes[i] = r.at(i).raw();
}
Node::Branch(nodes, if r.at(16).is_empty() { None } else { Some(r.at(16).data()) })
},
// an empty branch index.
Prototype::Data(0) => Node::Empty,
// something went wrong.
_ => panic!("Rlp is not valid.")
}
}
/// Encode the node into RLP.
///
/// Will always return the direct node RLP even if it's 32 or more bytes. To get the
/// RLP which would be valid for using in another node, use `encoded_and_added()`.
fn encoded(&self) -> Bytes {
match *self {
Node::Leaf(ref slice, ref value) => {
let mut stream = RlpStream::new_list(2);
stream.append(&slice.encoded(true));
stream.append(value);
stream.out()
},
Node::Extension(ref slice, ref raw_rlp) => {
let mut stream = RlpStream::new_list(2);
stream.append(&slice.encoded(false));
stream.append_raw(raw_rlp, 1);
stream.out()
},
Node::Branch(ref nodes, ref value) => {
let mut stream = RlpStream::new_list(17);
for i in 0..16 {
stream.append_raw(nodes[i], 1);
}
match *value {
Some(n) => { stream.append(&n); },
None => { stream.append_empty_data(); },
}
stream.out()
},
Node::Empty => {
let mut stream = RlpStream::new();
stream.append_empty_data();
stream.out()
}
}
}
/// Encode the node, adding it to `journal` if necessary and return the RLP valid for
/// insertion into a parent node.
fn encoded_and_added(&self, journal: &mut Journal) -> Bytes {
let mut stream = RlpStream::new();
match *self {
Node::Leaf(ref slice, ref value) => {
stream.append_list(2);
stream.append(&slice.encoded(true));
stream.append(value);
},
Node::Extension(ref slice, ref raw_rlp) => {
stream.append_list(2);
stream.append(&slice.encoded(false));
stream.append_raw(raw_rlp, 1);
},
Node::Branch(ref nodes, ref value) => {
stream.append_list(17);
for i in 0..16 {
stream.append_raw(nodes[i], 1);
}
match *value {
Some(n) => { stream.append(&n); },
None => { stream.append_empty_data(); },
}
},
Node::Empty => {
stream.append_empty_data();
}
}
let node = stream.out();
match node.len() {
0 ... 31 => node,
_ => {
let mut stream = RlpStream::new();
journal.new_node(node, &mut stream);
stream.out()
}
}
}
} }
/// A `Trie` implementation using a generic `HashDB` backing database. /// A `Trie` implementation using a generic `HashDB` backing database.
@ -283,40 +35,29 @@ impl <'a>Node<'a> {
/// use util::hashdb::*; /// use util::hashdb::*;
/// use util::memorydb::*; /// use util::memorydb::*;
/// use util::hash::*; /// use util::hash::*;
/// use util::rlp::*;
/// ///
/// fn main() { /// fn main() {
/// let mut memdb = MemoryDB::new(); /// let mut memdb = MemoryDB::new();
/// let mut root = H256::new(); /// let mut root = H256::new();
/// let mut t = TrieDB::new(&mut memdb, &mut root); /// let mut t = TrieDBMut::new(&mut memdb, &mut root);
/// assert!(t.is_empty()); /// assert!(t.is_empty());
/// assert_eq!(*t.root(), SHA3_NULL_RLP); /// assert_eq!(*t.root(), SHA3_NULL_RLP);
/// t.insert(b"foo", b"bar"); /// t.insert(b"foo", b"bar");
/// assert!(t.contains(b"foo")); /// assert!(t.contains(b"foo"));
/// assert_eq!(t.at(b"foo").unwrap(), b"bar"); /// assert_eq!(t.get(b"foo").unwrap(), b"bar");
/// assert!(t.db_items_remaining().is_empty()); /// assert!(t.db_items_remaining().is_empty());
/// t.remove(b"foo"); /// t.remove(b"foo");
/// assert!(!t.contains(b"foo")); /// assert!(!t.contains(b"foo"));
/// assert!(t.db_items_remaining().is_empty()); /// assert!(t.db_items_remaining().is_empty());
/// } /// }
/// ``` /// ```
pub struct TrieDB<'db> { impl<'db> TrieDBMut<'db> {
db: &'db mut HashDB,
root: &'db mut H256,
pub hash_count: usize,
}
/// Option-like type allowing either a Node object passthrough or Bytes in the case of data alteration.
enum MaybeChanged<'a> {
Same(Node<'a>),
Changed(Bytes),
}
impl<'db> TrieDB<'db> {
/// Create a new trie with the backing database `db` and empty `root` /// Create a new trie with the backing database `db` and empty `root`
/// Initialise to the state entailed by the genesis block. /// Initialise to the state entailed by the genesis block.
/// This guarantees the trie is built correctly. /// This guarantees the trie is built correctly.
pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self { pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self {
let mut r = TrieDB{ let mut r = TrieDBMut{
db: db, db: db,
root: root, root: root,
hash_count: 0 hash_count: 0
@ -331,7 +72,7 @@ impl<'db> TrieDB<'db> {
/// Panics, if `root` does not exist /// Panics, if `root` does not exist
pub fn new_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self { pub fn new_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self {
assert!(db.exists(root)); assert!(db.exists(root));
TrieDB { TrieDBMut {
db: db, db: db,
root: root, root: root,
hash_count: 0 hash_count: 0
@ -386,20 +127,7 @@ impl<'db> TrieDB<'db> {
/// Apply the items in `journal` into the backing database. /// Apply the items in `journal` into the backing database.
fn apply(&mut self, journal: Journal) { fn apply(&mut self, journal: Journal) {
trace!("applying {:?} changes", journal.0.len()); self.hash_count += journal.apply(self.db).inserts;
for d in journal.0.into_iter() {
match d {
Operation::Delete(h) => {
trace!("TrieDB::apply --- {:?}", &h);
self.db.kill(&h);
},
Operation::New(h, d) => {
trace!("TrieDB::apply +++ {:?} -> {:?}", &h, d.pretty());
self.db.emplace(h, d);
self.hash_count += 1;
}
}
}
} }
/// Recursion helper for `keys`. /// Recursion helper for `keys`.
@ -475,7 +203,7 @@ impl<'db> TrieDB<'db> {
} }
/// Return optional data for a key given as a `NibbleSlice`. Returns `None` if no data exists. /// Return optional data for a key given as a `NibbleSlice`. Returns `None` if no data exists.
fn get<'a, 'key>(&'a self, key: &NibbleSlice<'key>) -> Option<&'a [u8]> where 'a: 'key { fn do_lookup<'a, 'key>(&'a self, key: &NibbleSlice<'key>) -> Option<&'a [u8]> where 'a: 'key {
let root_rlp = self.db.lookup(&self.root).expect("Trie root not found!"); let root_rlp = self.db.lookup(&self.root).expect("Trie root not found!");
self.get_from_node(&root_rlp, key) self.get_from_node(&root_rlp, key)
} }
@ -892,17 +620,19 @@ impl<'db> TrieDB<'db> {
} }
} }
impl<'db> Trie for TrieDB<'db> { impl<'db> Trie for TrieDBMut<'db> {
fn root(&self) -> &H256 { &self.root } fn root(&self) -> &H256 { &self.root }
fn contains(&self, key: &[u8]) -> bool { fn contains(&self, key: &[u8]) -> bool {
self.at(key).is_some() self.get(key).is_some()
} }
fn at<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key { fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.get(&NibbleSlice::new(key)) self.do_lookup(&NibbleSlice::new(key))
}
} }
impl<'db> TrieMut for TrieDBMut<'db> {
fn insert(&mut self, key: &[u8], value: &[u8]) { fn insert(&mut self, key: &[u8], value: &[u8]) {
match value.is_empty() { match value.is_empty() {
false => self.insert_ns(&NibbleSlice::new(key), value), false => self.insert_ns(&NibbleSlice::new(key), value),
@ -915,7 +645,7 @@ impl<'db> Trie for TrieDB<'db> {
} }
} }
impl<'db> fmt::Debug for TrieDB<'db> { impl<'db> fmt::Debug for TrieDBMut<'db> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
try!(writeln!(f, "c={:?} [", self.hash_count)); try!(writeln!(f, "c={:?} [", self.hash_count));
let root_rlp = self.db.lookup(&self.root).expect("Trie root not found!"); let root_rlp = self.db.lookup(&self.root).expect("Trie root not found!");
@ -934,11 +664,13 @@ mod tests {
use memorydb::*; use memorydb::*;
use super::*; use super::*;
use nibbleslice::*; use nibbleslice::*;
use rlp; use rlp::*;
use env_logger; use env_logger;
use rand::random; use rand::random;
use std::collections::HashSet; use std::collections::HashSet;
use bytes::{ToPretty,Bytes}; use bytes::{ToPretty,Bytes};
use super::super::node::*;
use super::super::trietraits::*;
fn random_key(alphabet: &[u8], min_count: usize, journal_count: usize) -> Vec<u8> { fn random_key(alphabet: &[u8], min_count: usize, journal_count: usize) -> Vec<u8> {
let mut ret: Vec<u8> = Vec::new(); let mut ret: Vec<u8> = Vec::new();
@ -951,17 +683,17 @@ mod tests {
fn random_value_indexed(j: usize) -> Bytes { fn random_value_indexed(j: usize) -> Bytes {
match random::<usize>() % 2 { match random::<usize>() % 2 {
0 => rlp::encode(&j), 0 => encode(&j),
_ => { _ => {
let mut h = H256::new(); let mut h = H256::new();
h.mut_bytes()[31] = j as u8; h.mut_bytes()[31] = j as u8;
rlp::encode(&h) encode(&h)
}, },
} }
} }
fn populate_trie<'db>(db: &'db mut HashDB, root: &'db mut H256, v: &Vec<(Vec<u8>, Vec<u8>)>) -> TrieDB<'db> { fn populate_trie<'db>(db: &'db mut HashDB, root: &'db mut H256, v: &Vec<(Vec<u8>, Vec<u8>)>) -> TrieDBMut<'db> {
let mut t = TrieDB::new(db, root); let mut t = TrieDBMut::new(db, root);
for i in 0..v.len() { for i in 0..v.len() {
let key: &[u8]= &v[i].0; let key: &[u8]= &v[i].0;
let val: &[u8] = &v[i].1; let val: &[u8] = &v[i].1;
@ -970,7 +702,7 @@ mod tests {
t t
} }
fn unpopulate_trie<'a, 'db>(t: &mut TrieDB<'db>, v: &Vec<(Vec<u8>, Vec<u8>)>) { fn unpopulate_trie<'a, 'db>(t: &mut TrieDBMut<'db>, v: &Vec<(Vec<u8>, Vec<u8>)>) {
for i in v.iter() { for i in v.iter() {
let key: &[u8]= &i.0; let key: &[u8]= &i.0;
t.remove(&key); t.remove(&key);
@ -1011,7 +743,7 @@ mod tests {
let mut x: Vec<(Vec<u8>, Vec<u8>)> = Vec::new(); let mut x: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
let mut got: HashSet<Vec<u8>> = HashSet::new(); let mut got: HashSet<Vec<u8>> = HashSet::new();
let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_";
for j in 0..1000usize { for j in 0..100usize {
let key = random_key(alphabet, 5, 0); let key = random_key(alphabet, 5, 0);
if !got.contains(&key) { if !got.contains(&key) {
x.push((key.clone(), random_value_indexed(j))); x.push((key.clone(), random_value_indexed(j)));
@ -1053,7 +785,7 @@ mod tests {
fn init() { fn init() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let t = TrieDB::new(&mut memdb, &mut root); let t = TrieDBMut::new(&mut memdb, &mut root);
assert_eq!(*t.root(), SHA3_NULL_RLP); assert_eq!(*t.root(), SHA3_NULL_RLP);
assert!(t.is_empty()); assert!(t.is_empty());
} }
@ -1062,7 +794,7 @@ mod tests {
fn insert_on_empty() { fn insert_on_empty() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x01u8, 0x23]) ])); assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x01u8, 0x23]) ]));
} }
@ -1073,14 +805,14 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t1 = TrieDB::new(&mut memdb, &mut root); let mut t1 = TrieDBMut::new(&mut memdb, &mut root);
t1.insert(&[0x01, 0x23], &big_value.to_vec()); t1.insert(&[0x01, 0x23], &big_value.to_vec());
t1.insert(&[0x01, 0x34], &big_value.to_vec()); t1.insert(&[0x01, 0x34], &big_value.to_vec());
trace!("keys remaining {:?}", t1.db_items_remaining()); trace!("keys remaining {:?}", t1.db_items_remaining());
assert!(t1.db_items_remaining().is_empty()); assert!(t1.db_items_remaining().is_empty());
let mut memdb2 = MemoryDB::new(); let mut memdb2 = MemoryDB::new();
let mut root2 = H256::new(); let mut root2 = H256::new();
let mut t2 = TrieDB::new(&mut memdb2, &mut root2); let mut t2 = TrieDBMut::new(&mut memdb2, &mut root2);
t2.insert(&[0x01], &big_value.to_vec()); t2.insert(&[0x01], &big_value.to_vec());
t2.insert(&[0x01, 0x23], &big_value.to_vec()); t2.insert(&[0x01, 0x23], &big_value.to_vec());
t2.insert(&[0x01, 0x34], &big_value.to_vec()); t2.insert(&[0x01, 0x34], &big_value.to_vec());
@ -1096,7 +828,7 @@ mod tests {
fn insert_replace_root() { fn insert_replace_root() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
t.insert(&[0x01u8, 0x23], &[0x23u8, 0x45]); t.insert(&[0x01u8, 0x23], &[0x23u8, 0x45]);
assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x23u8, 0x45]) ])); assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x23u8, 0x45]) ]));
@ -1106,7 +838,7 @@ mod tests {
fn insert_make_branch_root() { fn insert_make_branch_root() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
t.insert(&[0x11u8, 0x23], &[0x11u8, 0x23]); t.insert(&[0x11u8, 0x23], &[0x11u8, 0x23]);
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
@ -1119,7 +851,7 @@ mod tests {
fn insert_into_branch_root() { fn insert_into_branch_root() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]); t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]);
t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]); t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]);
@ -1134,7 +866,7 @@ mod tests {
fn insert_value_into_branch_root() { fn insert_value_into_branch_root() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
t.insert(&[], &[0x0]); t.insert(&[], &[0x0]);
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
@ -1147,7 +879,7 @@ mod tests {
fn insert_split_leaf() { fn insert_split_leaf() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
t.insert(&[0x01u8, 0x34], &[0x01u8, 0x34]); t.insert(&[0x01u8, 0x34], &[0x01u8, 0x34]);
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
@ -1160,7 +892,7 @@ mod tests {
fn insert_split_extenstion() { fn insert_split_extenstion() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01, 0x23, 0x45], &[0x01]); t.insert(&[0x01, 0x23, 0x45], &[0x01]);
t.insert(&[0x01, 0xf3, 0x45], &[0x02]); t.insert(&[0x01, 0xf3, 0x45], &[0x02]);
t.insert(&[0x01, 0xf3, 0xf5], &[0x03]); t.insert(&[0x01, 0xf3, 0xf5], &[0x03]);
@ -1178,7 +910,7 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], big_value0); t.insert(&[0x01u8, 0x23], big_value0);
t.insert(&[0x11u8, 0x23], big_value1); t.insert(&[0x11u8, 0x23], big_value1);
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
@ -1193,7 +925,7 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], big_value); t.insert(&[0x01u8, 0x23], big_value);
t.insert(&[0x11u8, 0x23], big_value); t.insert(&[0x11u8, 0x23], big_value);
assert_eq!(*t.root(), trie_root(vec![ assert_eq!(*t.root(), trie_root(vec![
@ -1218,7 +950,7 @@ mod tests {
fn test_node_extension() { fn test_node_extension() {
let k = vec![0x00u8, 0x01, 0x23, 0x45]; let k = vec![0x00u8, 0x01, 0x23, 0x45];
// in extension, value must be valid rlp // in extension, value must be valid rlp
let v = rlp::encode(&"cat"); let v = encode(&"cat");
let (slice, is_leaf) = NibbleSlice::from_encoded(&k); let (slice, is_leaf) = NibbleSlice::from_encoded(&k);
assert_eq!(is_leaf, false); assert_eq!(is_leaf, false);
let ex = Node::Extension(slice, &v); let ex = Node::Extension(slice, &v);
@ -1239,7 +971,7 @@ mod tests {
#[test] #[test]
fn test_node_branch() { fn test_node_branch() {
let k = rlp::encode(&"cat"); let k = encode(&"cat");
let mut nodes: [&[u8]; 16] = unsafe { ::std::mem::uninitialized() }; let mut nodes: [&[u8]; 16] = unsafe { ::std::mem::uninitialized() };
for i in 0..16 { nodes[i] = &k; } for i in 0..16 { nodes[i] = &k; }
let v: Vec<u8> = From::from("dog"); let v: Vec<u8> = From::from("dog");
@ -1253,38 +985,38 @@ mod tests {
fn test_at_empty() { fn test_at_empty() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let t = TrieDB::new(&mut memdb, &mut root); let t = TrieDBMut::new(&mut memdb, &mut root);
assert_eq!(t.at(&[0x5]), None); assert_eq!(t.get(&[0x5]), None);
} }
#[test] #[test]
fn test_at_one() { fn test_at_one() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
assert_eq!(t.at(&[0x1, 0x23]).unwrap(), &[0x1u8, 0x23]); assert_eq!(t.get(&[0x1, 0x23]).unwrap(), &[0x1u8, 0x23]);
} }
#[test] #[test]
fn test_at_three() { fn test_at_three() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]); t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]);
t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]); t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]);
assert_eq!(t.at(&[0x01, 0x23]).unwrap(), &[0x01u8, 0x23]); assert_eq!(t.get(&[0x01, 0x23]).unwrap(), &[0x01u8, 0x23]);
assert_eq!(t.at(&[0xf1, 0x23]).unwrap(), &[0xf1u8, 0x23]); assert_eq!(t.get(&[0xf1, 0x23]).unwrap(), &[0xf1u8, 0x23]);
assert_eq!(t.at(&[0x81, 0x23]).unwrap(), &[0x81u8, 0x23]); assert_eq!(t.get(&[0x81, 0x23]).unwrap(), &[0x81u8, 0x23]);
assert_eq!(t.at(&[0x82, 0x23]), None); assert_eq!(t.get(&[0x82, 0x23]), None);
} }
#[test] #[test]
fn test_print_trie() { fn test_print_trie() {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
t.insert(&[0x02u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x02u8, 0x23], &[0x01u8, 0x23]);
t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]); t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]);
@ -1296,12 +1028,12 @@ mod tests {
#[test] #[test]
fn stress() { fn stress() {
for _ in 0..500 { for _ in 0..50 {
let mut x: Vec<(Vec<u8>, Vec<u8>)> = Vec::new(); let mut x: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_";
for j in 0..4u32 { for j in 0..4u32 {
let key = random_key(alphabet, 5, 1); let key = random_key(alphabet, 5, 1);
x.push((key, rlp::encode(&j))); x.push((key, encode(&j)));
} }
let real = trie_root(x.clone()); let real = trie_root(x.clone());
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
@ -1339,7 +1071,7 @@ mod tests {
let mut memdb = MemoryDB::new(); let mut memdb = MemoryDB::new();
let mut root = H256::new(); let mut root = H256::new();
let mut t = TrieDB::new(&mut memdb, &mut root); let mut t = TrieDBMut::new(&mut memdb, &mut root);
for operation in input.into_iter() { for operation in input.into_iter() {
match operation { match operation {
trie::Operation::Insert(key, value) => t.insert(&key, &value), trie::Operation::Insert(key, value) => t.insert(&key, &value),
@ -1356,12 +1088,12 @@ mod tests {
let mut root = H256::new(); let mut root = H256::new();
let mut db = MemoryDB::new(); let mut db = MemoryDB::new();
{ {
let mut t = TrieDB::new(&mut db, &mut root); let mut t = TrieDBMut::new(&mut db, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
} }
{ {
let _ = TrieDB::new_existing(&mut db, &mut root); let _ = TrieDBMut::new_existing(&mut db, &mut root);
} }
} }
} }

29
src/trie/trietraits.rs Normal file
View File

@ -0,0 +1,29 @@
use hash::H256;
use rlp::SHA3_NULL_RLP;
/// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait Trie {
/// Return the root of the trie.
fn root(&self) -> &H256;
/// Is the trie empty?
fn is_empty(&self) -> bool { *self.root() == SHA3_NULL_RLP }
/// Does the trie contain a given key?
fn contains(&self, key: &[u8]) -> bool;
/// What is the value of the given key in this trie?
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key;
}
/// A key-value datastore implemented as a database-backed modified Merkle tree.
pub trait TrieMut: Trie {
/// Insert a `key`/`value` pair into the trie. An `empty` value is equivalent to removing
/// `key` from the trie.
fn insert(&mut self, key: &[u8], value: &[u8]);
/// Remove a `key` from the trie. Equivalent to making it equal to the empty
/// value.
fn remove(&mut self, key: &[u8]);
}