Merge pull request #21 from gavofyork/triemut
Repot Trie and split into mutable and immutable variants.
This commit is contained in:
		
						commit
						58b68e0aef
					
				| @ -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); | ||||||
| 		} | 		} | ||||||
|  | |||||||
							
								
								
									
										12
									
								
								src/bytes.rs
									
									
									
									
									
								
							
							
						
						
									
										12
									
								
								src/bytes.rs
									
									
									
									
									
								
							| @ -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] { | ||||||
|  | |||||||
| @ -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) } | ||||||
| } | } | ||||||
|  | |||||||
| @ -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
									
								
							
							
						
						
									
										76
									
								
								src/trie/journal.rs
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										11
									
								
								src/trie/mod.rs
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										121
									
								
								src/trie/node.rs
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										75
									
								
								src/trie/standardmap.rs
									
									
									
									
									
										Normal 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
									
								
							
							
						
						
									
										220
									
								
								src/trie/triedb.rs
									
									
									
									
									
										Normal 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, "]") | ||||||
|  | 	} | ||||||
|  | } | ||||||
| @ -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
									
								
							
							
						
						
									
										29
									
								
								src/trie/trietraits.rs
									
									
									
									
									
										Normal 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]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user