Merge branch 'master' of https://github.com/gavofyork/ethcore-util
This commit is contained in:
		
						commit
						816b75cc87
					
				
							
								
								
									
										128
									
								
								benches/trie.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										128
									
								
								benches/trie.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,128 @@ | |||||||
|  | #![feature(test)] | ||||||
|  | 
 | ||||||
|  | extern crate test; | ||||||
|  | extern crate rand; | ||||||
|  | extern crate ethcore_util; | ||||||
|  | #[macro_use] | ||||||
|  | extern crate log; | ||||||
|  | 
 | ||||||
|  | use test::Bencher; | ||||||
|  | use rand::random; | ||||||
|  | //use ethcore_util::BytesConvertable;
 | ||||||
|  | use ethcore_util::hash::*; | ||||||
|  | use ethcore_util::bytes::*; | ||||||
|  | use ethcore_util::trie::*; | ||||||
|  | use ethcore_util::sha3::*; | ||||||
|  | use ethcore_util::ToBytes::*; | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | fn random_word(alphabet: &[u8], min_count: usize, diff_count: usize, seed: &mut H256) -> Vec<u8> { | ||||||
|  | 	assert!(min_count + diff_count <= 32); | ||||||
|  | 	*seed = seed.sha3(); | ||||||
|  | 	let r = min_count + (seed.bytes()[31] as usize % (diff_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 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn random_bytes(min_count: usize, diff_count: usize, seed: &mut H256) -> Vec<u8> { | ||||||
|  | 	assert!(min_count + diff_count <= 32); | ||||||
|  | 	*seed = seed.sha3(); | ||||||
|  | 	let r = min_count + (seed.bytes()[31] as usize % (diff_count + 1)); | ||||||
|  | 	seed.bytes()[0..r].to_vec() | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 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(), | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[bench] | ||||||
|  | fn insertions_six_high(b: &mut Bencher) { | ||||||
|  | 	let mut d: Vec<(Bytes, Bytes)> = Vec::new(); | ||||||
|  | 	let mut seed = H256::new(); | ||||||
|  | 	for _ in 0..1000 { | ||||||
|  | 		let k = random_bytes(6, 0, &mut seed); | ||||||
|  | 		let v = random_value(&mut seed); | ||||||
|  | 		d.push((k, v)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	b.iter(||{ | ||||||
|  | 		let mut t = TrieDB::new_memory(); | ||||||
|  | 		for i in d.iter() { | ||||||
|  | 			t.insert(&i.0, &i.1); | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[bench] | ||||||
|  | fn insertions_six_mid(b: &mut Bencher) { | ||||||
|  | 	let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; | ||||||
|  | 	let mut d: Vec<(Bytes, Bytes)> = Vec::new(); | ||||||
|  | 	let mut seed = H256::new(); | ||||||
|  | 	for _ in 0..1000 { | ||||||
|  | 		let k = random_word(alphabet, 6, 0, &mut seed); | ||||||
|  | 		let v = random_value(&mut seed); | ||||||
|  | 		d.push((k, v)) | ||||||
|  | 	} | ||||||
|  | 	b.iter(||{ | ||||||
|  | 		let mut t = TrieDB::new_memory(); | ||||||
|  | 		for i in d.iter() { | ||||||
|  | 			t.insert(&i.0, &i.1); | ||||||
|  | 		} | ||||||
|  | 		debug!("hash_count={:?}", t.hash_count); | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[bench] | ||||||
|  | fn insertions_random_mid(b: &mut Bencher) { | ||||||
|  | 	let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; | ||||||
|  | 	let mut d: Vec<(Bytes, Bytes)> = Vec::new(); | ||||||
|  | 	let mut seed = H256::new(); | ||||||
|  | 	for _ in 0..1000 { | ||||||
|  | 		let k = random_word(alphabet, 1, 5, &mut seed); | ||||||
|  | 		let v = random_value(&mut seed); | ||||||
|  | 		d.push((k, v)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	b.iter(||{ | ||||||
|  | 		let mut t = TrieDB::new_memory(); | ||||||
|  | 		for i in d.iter() { | ||||||
|  | 			t.insert(&i.0, &i.1); | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[bench] | ||||||
|  | fn insertions_six_low(b: &mut Bencher) { | ||||||
|  | 	let alphabet = b"abcdef"; | ||||||
|  | 	let mut d: Vec<(Bytes, Bytes)> = Vec::new(); | ||||||
|  | 	let mut seed = H256::new(); | ||||||
|  | 	for _ in 0..1000 { | ||||||
|  | 		let k = random_word(alphabet, 6, 0, &mut seed); | ||||||
|  | 		let v = random_value(&mut seed); | ||||||
|  | 		d.push((k, v)) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	b.iter(||{ | ||||||
|  | 		let mut t = TrieDB::new_memory(); | ||||||
|  | 		for i in d.iter() { | ||||||
|  | 			t.insert(&i.0, &i.1); | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | #[bench] | ||||||
|  | fn sha3x1000(b: &mut Bencher) { | ||||||
|  | 	b.iter(||{ | ||||||
|  | 		let mut seed = H256::new(); | ||||||
|  | 		for i in 0..1000 { | ||||||
|  | 			seed = seed.sha3() | ||||||
|  | 		} | ||||||
|  | 	}) | ||||||
|  | } | ||||||
| @ -4,7 +4,7 @@ use std::collections::HashMap; | |||||||
| 
 | 
 | ||||||
| pub trait HashDB { | 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, u32>; | 	fn keys(&self) -> HashMap<H256, i32>; | ||||||
| 
 | 
 | ||||||
| 	/// 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.
 | ||||||
|  | |||||||
| @ -116,10 +116,6 @@ impl MemoryDB { | |||||||
| 		} | 		} | ||||||
| 		self.data.get(key).unwrap() | 		self.data.get(key).unwrap() | ||||||
| 	} | 	} | ||||||
| 
 |  | ||||||
| 	pub fn raw_keys(&self) -> HashMap<H256, i32> { |  | ||||||
| 		self.data.iter().filter_map(|(k, v)| if v.1 != 0 {Some((k.clone(), v.1))} else {None}).collect::<HashMap<H256, i32>>() |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl HashDB for MemoryDB { | impl HashDB for MemoryDB { | ||||||
| @ -130,8 +126,8 @@ impl HashDB for MemoryDB { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn keys(&self) -> HashMap<H256, u32> { | 	fn keys(&self) -> HashMap<H256, i32> { | ||||||
| 		self.data.iter().filter_map(|(k, v)| if v.1 > 0 {Some((k.clone(), v.1 as u32))} else {None} ).collect::<HashMap<H256, u32>>() | 		self.data.iter().filter_map(|(k, v)| if v.1 != 0 {Some((k.clone(), v.1))} else {None}).collect::<HashMap<H256, i32>>() | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn exists(&self, key: &H256) -> bool { | 	fn exists(&self, key: &H256) -> bool { | ||||||
|  | |||||||
| @ -136,17 +136,17 @@ impl OverlayDB { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl HashDB for OverlayDB { | impl HashDB for OverlayDB { | ||||||
| 	fn keys(&self) -> HashMap<H256, u32> { | 	fn keys(&self) -> HashMap<H256, i32> { | ||||||
| 		let mut ret: HashMap<H256, u32> = HashMap::new(); | 		let mut ret: HashMap<H256, i32> = HashMap::new(); | ||||||
| 		for (key, _) in self.backing.iterator().from_start() { | 		for (key, _) in self.backing.iterator().from_start() { | ||||||
| 			let h = H256::from_slice(key.deref()); | 			let h = H256::from_slice(key.deref()); | ||||||
| 			let r = self.payload(&h).unwrap().1; | 			let r = self.payload(&h).unwrap().1; | ||||||
| 			ret.insert(h, r); | 			ret.insert(h, r as i32); | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		for (key, refs) in self.overlay.raw_keys().into_iter() { | 		for (key, refs) in self.overlay.keys().into_iter() { | ||||||
| 			let refs = *ret.get(&key).unwrap_or(&0u32) as i32 + refs as i32; | 			let refs = *ret.get(&key).unwrap_or(&0) + refs; | ||||||
| 			ret.insert(key, refs as u32); | 			ret.insert(key, refs); | ||||||
| 		} | 		} | ||||||
| 		ret | 		ret | ||||||
| 	} | 	} | ||||||
|  | |||||||
							
								
								
									
										268
									
								
								src/trie.rs
									
									
									
									
									
								
							
							
						
						
									
										268
									
								
								src/trie.rs
									
									
									
									
									
								
							| @ -26,6 +26,67 @@ pub trait Trie { | |||||||
| 	fn remove(&mut self, key: &[u8]); | 	fn remove(&mut self, key: &[u8]); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | pub enum Alphabet { | ||||||
|  | 	All, | ||||||
|  | 	Low, | ||||||
|  | 	Mid, | ||||||
|  | 	Custom(Bytes), | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct StandardMap { | ||||||
|  | 	alphabet: Alphabet, | ||||||
|  | 	min_key: usize, | ||||||
|  | 	diff_key: usize, | ||||||
|  | 	count: usize, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl StandardMap { | ||||||
|  | 	fn random_bytes(min_count: usize, diff_count: usize, seed: &mut H256) -> Vec<u8> { | ||||||
|  | 		assert!(min_count + diff_count <= 32); | ||||||
|  | 		*seed = seed.sha3(); | ||||||
|  | 		let r = min_count + (seed.bytes()[31] as usize % (diff_count + 1)); | ||||||
|  | 		seed.bytes()[0..r].to_vec() | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	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(), | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fn random_word(alphabet: &[u8], min_count: usize, diff_count: usize, seed: &mut H256) -> Vec<u8> { | ||||||
|  | 		assert!(min_count + diff_count <= 32); | ||||||
|  | 		*seed = seed.sha3(); | ||||||
|  | 		let r = min_count + (seed.bytes()[31] as usize % (diff_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 | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	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.diff_key, &mut seed), | ||||||
|  | 				Alphabet::Low => Self::random_word(low, self.min_key, self.diff_key, &mut seed), | ||||||
|  | 				Alphabet::Mid => Self::random_word(mid, self.min_key, self.diff_key, &mut seed), | ||||||
|  | 				Alphabet::Custom(ref a) => Self::random_word(&a, self.min_key, self.diff_key, &mut seed), | ||||||
|  | 			}; | ||||||
|  | 			let v = Self::random_value(&mut seed); | ||||||
|  | 			d.push((k, v)) | ||||||
|  | 		} | ||||||
|  | 		d | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Eq, PartialEq, Debug)] | #[derive(Eq, PartialEq, Debug)] | ||||||
| pub enum Node<'a> { | pub enum Node<'a> { | ||||||
| 	Empty, | 	Empty, | ||||||
| @ -34,11 +95,13 @@ pub enum Node<'a> { | |||||||
| 	Branch([&'a[u8]; 16], Option<&'a [u8]>) | 	Branch([&'a[u8]; 16], Option<&'a [u8]>) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
| enum Operation { | enum Operation { | ||||||
| 	New(H256, Bytes), | 	New(H256, Bytes), | ||||||
| 	Delete(H256), | 	Delete(H256), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | #[derive(Debug)] | ||||||
| struct Diff (Vec<Operation>); | struct Diff (Vec<Operation>); | ||||||
| 
 | 
 | ||||||
| impl Diff { | impl Diff { | ||||||
| @ -48,8 +111,9 @@ impl Diff { | |||||||
| 	/// such that the reference is valid, once applied.
 | 	/// such that the reference is valid, once applied.
 | ||||||
| 	fn new_node(&mut self, rlp: Bytes, out: &mut RlpStream) { | 	fn new_node(&mut self, rlp: Bytes, out: &mut RlpStream) { | ||||||
| 		if rlp.len() >= 32 { | 		if rlp.len() >= 32 { | ||||||
| 			trace!("new_node: reference node {:?}", rlp.pretty()); |  | ||||||
| 			let rlp_sha3 = rlp.sha3(); | 			let rlp_sha3 = rlp.sha3(); | ||||||
|  | 
 | ||||||
|  | 			trace!("new_node: reference node {:?} => {:?}", rlp_sha3, rlp.pretty()); | ||||||
| 			out.append(&rlp_sha3); | 			out.append(&rlp_sha3); | ||||||
| 			self.0.push(Operation::New(rlp_sha3, rlp)); | 			self.0.push(Operation::New(rlp_sha3, rlp)); | ||||||
| 		} | 		} | ||||||
| @ -61,25 +125,18 @@ impl Diff { | |||||||
| 
 | 
 | ||||||
| 	/// Given the RLP that encodes a now-unused node, leave `diff` in such a state that it is noted.
 | 	/// Given the RLP that encodes a now-unused node, leave `diff` in such a state that it is noted.
 | ||||||
| 	fn delete_node_sha3(&mut self, old_sha3: H256) { | 	fn delete_node_sha3(&mut self, old_sha3: H256) { | ||||||
|  | 		trace!("delete_node:  {:?}", old_sha3); | ||||||
| 		self.0.push(Operation::Delete(old_sha3)); | 		self.0.push(Operation::Delete(old_sha3)); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn delete_node(&mut self, old: &Rlp) { | 	fn delete_node(&mut self, old: &Rlp) { | ||||||
| 		if old.is_data() && old.size() == 32 { | 		if old.is_data() && old.size() == 32 { | ||||||
| 			self.0.push(Operation::Delete(H256::decode(old))); | 			self.delete_node_sha3(H256::decode(old)); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn delete_node_from_slice(&mut self, old: &[u8]) { | 	fn delete_node_from_slice(&mut self, old: &[u8]) { | ||||||
| 		let r = Rlp::new(old); | 		self.delete_node(&Rlp::new(old)); | ||||||
| 		if r.is_data() && r.size() == 32 { |  | ||||||
| 			self.0.push(Operation::Delete(H256::decode(&r))); |  | ||||||
| 		} |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	fn replace_node(&mut self, old: &Rlp, rlp: Bytes, out: &mut RlpStream) { |  | ||||||
| 		self.delete_node(old); |  | ||||||
| 		self.new_node(rlp, out); |  | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -192,11 +249,12 @@ impl <'a>Node<'a> { | |||||||
| pub struct TrieDB { | pub struct TrieDB { | ||||||
| 	db: Box<HashDB>, | 	db: Box<HashDB>, | ||||||
| 	root: H256, | 	root: H256, | ||||||
|  | 	pub hash_count: usize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl fmt::Debug for TrieDB { | impl fmt::Debug for TrieDB { | ||||||
| 	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||||
| 		try!(writeln!(f, "[")); | 		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!"); | ||||||
| 		try!(self.fmt_all(Node::decoded(root_rlp), f, 0)); | 		try!(self.fmt_all(Node::decoded(root_rlp), f, 0)); | ||||||
| 		writeln!(f, "]") | 		writeln!(f, "]") | ||||||
| @ -209,7 +267,7 @@ enum MaybeChanged<'a> { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl TrieDB { | impl TrieDB { | ||||||
| 	pub fn new_boxed(db_box: Box<HashDB>) -> Self { let mut r = TrieDB{ db: db_box, root: H256::new() }; r.set_root_rlp(&NULL_RLP); r } | 	pub fn new_boxed(db_box: Box<HashDB>) -> Self { let mut r = TrieDB{ db: db_box, root: H256::new(), hash_count: 0 }; r.root = r.db.insert(&NULL_RLP); r } | ||||||
| 
 | 
 | ||||||
| 	pub fn new<T>(db: T) -> Self where T: HashDB + 'static { Self::new_boxed(Box::new(db)) } | 	pub fn new<T>(db: T) -> Self where T: HashDB + 'static { Self::new_boxed(Box::new(db)) } | ||||||
| 
 | 
 | ||||||
| @ -220,6 +278,7 @@ impl TrieDB { | |||||||
| 	fn set_root_rlp(&mut self, root_data: &[u8]) { | 	fn set_root_rlp(&mut self, root_data: &[u8]) { | ||||||
| 		self.db.kill(&self.root); | 		self.db.kill(&self.root); | ||||||
| 		self.root = self.db.insert(root_data); | 		self.root = self.db.insert(root_data); | ||||||
|  | 		self.hash_count += 1; | ||||||
| 		trace!("set_root_rlp {:?} {:?}", root_data.pretty(), self.root); | 		trace!("set_root_rlp {:?} {:?}", root_data.pretty(), self.root); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -234,6 +293,7 @@ impl TrieDB { | |||||||
| 				Operation::New(h, d) => { | 				Operation::New(h, d) => { | ||||||
| 					trace!("TrieDB::apply +++ {:?} -> {:?}", &h, d.pretty()); | 					trace!("TrieDB::apply +++ {:?} -> {:?}", &h, d.pretty()); | ||||||
| 					self.db.emplace(h, d); | 					self.db.emplace(h, d); | ||||||
|  | 					self.hash_count += 1; | ||||||
| 				} | 				} | ||||||
| 			} | 			} | ||||||
| 		} | 		} | ||||||
| @ -272,14 +332,13 @@ impl TrieDB { | |||||||
| 		r | 		r | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	pub fn db_items_remaining(&self) -> HashMap<H256, u32> { | 	pub fn db_items_remaining(&self) -> HashMap<H256, i32> { | ||||||
| 		let mut ret = self.db().keys(); | 		let mut ret = self.db().keys(); | ||||||
| 		for (k, v) in Self::to_map(self.keys()).into_iter() { | 		for (k, v) in Self::to_map(self.keys()).into_iter() { | ||||||
| 			let old = *ret.get(&k).expect("Node in trie is not in database!"); | 			let keycount = *ret.get(&k).unwrap_or(&0); | ||||||
| 			assert!(old >= v); | 			match keycount == v as i32 { | ||||||
| 			match old > v { | 				true => ret.remove(&k), | ||||||
| 				true => ret.insert(k, old - v), | 				_ => ret.insert(k, keycount - v as i32), | ||||||
| 				_ => ret.remove(&k), |  | ||||||
| 			}; | 			}; | ||||||
| 		} | 		} | ||||||
| 		ret | 		ret | ||||||
| @ -437,7 +496,11 @@ impl TrieDB { | |||||||
| 		} | 		} | ||||||
| 		else if rlp.is_data() && rlp.size() == 32 { | 		else if rlp.is_data() && rlp.size() == 32 { | ||||||
| 			let h = H256::decode(rlp); | 			let h = H256::decode(rlp); | ||||||
| 			let r = self.db.lookup(&h).expect("Trie root not found!"); | 			let r = self.db.lookup(&h).unwrap_or_else(||{ | ||||||
|  | 				println!("Node not found! rlp={:?}, node_hash={:?}", rlp.raw().pretty(), h); | ||||||
|  | 				println!("Diff: {:?}", diff); | ||||||
|  | 				panic!(); | ||||||
|  | 			}); | ||||||
| 			trace!("take_node {:?} (indirect for {:?})", rlp.raw().pretty(), r); | 			trace!("take_node {:?} (indirect for {:?})", rlp.raw().pretty(), r); | ||||||
| 			diff.delete_node_sha3(h); | 			diff.delete_node_sha3(h); | ||||||
| 			r | 			r | ||||||
| @ -518,7 +581,7 @@ impl TrieDB { | |||||||
| 					diff.new_node(Self::compose_leaf(&partial.mid(1), value), &mut s), | 					diff.new_node(Self::compose_leaf(&partial.mid(1), value), &mut s), | ||||||
| 				(true, i) => {	// harder - original has something there already
 | 				(true, i) => {	// harder - original has something there already
 | ||||||
| 					let new = self.augmented(self.take_node(&orig.at(i), diff), &partial.mid(1), value, diff); | 					let new = self.augmented(self.take_node(&orig.at(i), diff), &partial.mid(1), value, diff); | ||||||
| 					diff.replace_node(&orig.at(i), new, &mut s); | 					diff.new_node(new, &mut s); | ||||||
| 				} | 				} | ||||||
| 				(false, i) => { s.append_raw(orig.at(i).raw(), 1); }, | 				(false, i) => { s.append_raw(orig.at(i).raw(), 1); }, | ||||||
| 			} | 			} | ||||||
| @ -801,28 +864,113 @@ mod tests { | |||||||
| 	use rlp; | 	use rlp; | ||||||
| 	use env_logger; | 	use env_logger; | ||||||
| 	use rand::random; | 	use rand::random; | ||||||
| 	use bytes::ToPretty; | 	use std::collections::HashSet; | ||||||
|  | 	use bytes::{ToPretty,Bytes}; | ||||||
|  | 
 | ||||||
|  | 	fn random_key(alphabet: &[u8], min_count: usize, diff_count: usize) -> Vec<u8> { | ||||||
|  | 		let mut ret: Vec<u8> = Vec::new(); | ||||||
|  | 		let r = min_count + if diff_count > 0 {random::<usize>() % diff_count} else {0}; | ||||||
|  | 		for _ in 0..r { | ||||||
|  | 			ret.push(alphabet[random::<usize>() % alphabet.len()]); | ||||||
|  | 		} | ||||||
|  | 		ret | ||||||
|  | 	} | ||||||
|  | 	
 | ||||||
|  | 	fn random_value_indexed(j: usize) -> Bytes { | ||||||
|  | 		match random::<usize>() % 2 { | ||||||
|  | 			0 => rlp::encode(&j), | ||||||
|  | 			_ => { | ||||||
|  | 				let mut h = H256::new(); | ||||||
|  | 				h.mut_bytes()[31] = j as u8; | ||||||
|  | 				rlp::encode(&h) | ||||||
|  | 			}, | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fn populate_trie(v: &Vec<(Vec<u8>, Vec<u8>)>) -> TrieDB { | ||||||
|  | 		let mut t = TrieDB::new_memory(); | ||||||
|  | 		for i in 0..v.len() { | ||||||
|  | 			let key: &[u8]= &v[i].0; | ||||||
|  | 			let val: &[u8] = &v[i].1; | ||||||
|  | 			t.insert(&key, &val); | ||||||
|  | 		} | ||||||
|  | 		t | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	fn unpopulate_trie(t: &mut TrieDB, v: &Vec<(Vec<u8>, Vec<u8>)>) { | ||||||
|  | 		for i in v.iter() { | ||||||
|  | 			let key: &[u8]= &i.0; | ||||||
|  | 			t.remove(&key); | ||||||
|  | 		} | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	macro_rules! map({$($key:expr => $value:expr),+ } => { | ||||||
|  | 		{ | ||||||
|  | 			let mut m = ::std::collections::HashMap::new(); | ||||||
|  | 			$( | ||||||
|  | 				m.insert($key, $value); | ||||||
|  | 			)+ | ||||||
|  | 			m | ||||||
|  | 		} | ||||||
|  | 	};); | ||||||
| 
 | 
 | ||||||
| 	#[test] | 	#[test] | ||||||
| 	fn playpen() { | 	fn playpen() { | ||||||
| 		env_logger::init().ok(); | 		env_logger::init().ok(); | ||||||
| 
 | 
 | ||||||
| 		let big_value = b"00000000000000000000000000000000"; | 		let maps = map!{ | ||||||
|  | 			"six-low" => StandardMap{alphabet: Alphabet::Low, min_key: 6, diff_key: 0, count: 1000}, | ||||||
|  | 			"six-mid" => StandardMap{alphabet: Alphabet::Mid, min_key: 6, diff_key: 0, count: 1000}, | ||||||
|  | 			"six-all" => StandardMap{alphabet: Alphabet::All, min_key: 6, diff_key: 0, count: 1000}, | ||||||
|  | 			"mix-mid" => StandardMap{alphabet: Alphabet::Mid, min_key: 1, diff_key: 5, count: 1000} | ||||||
|  | 		}; | ||||||
|  | 		for sm in maps { | ||||||
|  | 			let m = sm.1.make(); | ||||||
|  | 			let t = populate_trie(&m); | ||||||
|  | 			println!("{:?}: root={:?}, hash_count={:?}", sm.0, t.root(), t.hash_count); | ||||||
|  | 		}; | ||||||
|  | 		panic!(); | ||||||
| 
 | 
 | ||||||
| 		let mut t1 = TrieDB::new_memory(); | 		for test_i in 0..1 { | ||||||
| 		t1.insert(&[0x01, 0x23], &big_value.to_vec()); | 			if test_i % 50 == 0 { | ||||||
| 		t1.insert(&[0x01, 0x34], &big_value.to_vec()); | 				debug!("{:?} of 10000 stress tests done", test_i); | ||||||
| 		trace!("keys remaining {:?}", t1.db_items_remaining()); | 			} | ||||||
| 		assert!(t1.db_items_remaining().is_empty()); | 			let mut x: Vec<(Vec<u8>, Vec<u8>)> = Vec::new(); | ||||||
| 		let mut t2 = TrieDB::new_memory(); | 			let mut got: HashSet<Vec<u8>> = HashSet::new(); | ||||||
| 		t2.insert(&[0x01], &big_value.to_vec()); | 			let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; | ||||||
| 		t2.insert(&[0x01, 0x23], &big_value.to_vec()); | 			for j in 0..1000usize { | ||||||
| 		t2.insert(&[0x01, 0x34], &big_value.to_vec()); | 				let key = random_key(alphabet, 5, 0); | ||||||
| 		t2.remove(&[0x01]); | 				if !got.contains(&key) { | ||||||
| 		assert!(t2.db_items_remaining().is_empty()); | 					x.push((key.clone(), random_value_indexed(j))); | ||||||
| 		/*if t1.root() != t2.root()*/ { | 					got.insert(key); | ||||||
| 			trace!("{:?}", t1); | 				} | ||||||
| 			trace!("{:?}", t2); | 			} | ||||||
|  | 
 | ||||||
|  | 			let real = trie_root(x.clone()); | ||||||
|  | 			let mut memtrie = populate_trie(&x); | ||||||
|  | 			if *memtrie.root() != real || !memtrie.db_items_remaining().is_empty() { | ||||||
|  | 				println!("TRIE MISMATCH"); | ||||||
|  | 				println!(""); | ||||||
|  | 				println!("{:?} vs {:?}", memtrie.root(), real); | ||||||
|  | 				for i in x.iter() { | ||||||
|  | 					println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); | ||||||
|  | 				} | ||||||
|  | 				println!("{:?}", memtrie); | ||||||
|  | 			} | ||||||
|  | 			assert_eq!(*memtrie.root(), real); | ||||||
|  | 			assert!(memtrie.db_items_remaining().is_empty()); | ||||||
|  | 			unpopulate_trie(&mut memtrie, &x); | ||||||
|  | 			if *memtrie.root() != SHA3_NULL_RLP || !memtrie.db_items_remaining().is_empty() { | ||||||
|  | 				println!("TRIE MISMATCH"); | ||||||
|  | 				println!(""); | ||||||
|  | 				println!("{:?} vs {:?}", memtrie.root(), real); | ||||||
|  | 				for i in x.iter() { | ||||||
|  | 					println!("{:?} -> {:?}", i.0.pretty(), i.1.pretty()); | ||||||
|  | 				} | ||||||
|  | 				println!("{:?}", memtrie); | ||||||
|  | 			} | ||||||
|  | 			assert_eq!(*memtrie.root(), SHA3_NULL_RLP); | ||||||
|  | 			assert!(memtrie.db_items_remaining().is_empty()); | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -842,6 +990,23 @@ mod tests { | |||||||
| 
 | 
 | ||||||
| 	#[test] | 	#[test] | ||||||
| 	fn remove_to_empty() { | 	fn remove_to_empty() { | ||||||
|  | 		let big_value = b"00000000000000000000000000000000"; | ||||||
|  | 
 | ||||||
|  | 		let mut t1 = TrieDB::new_memory(); | ||||||
|  | 		t1.insert(&[0x01, 0x23], &big_value.to_vec()); | ||||||
|  | 		t1.insert(&[0x01, 0x34], &big_value.to_vec()); | ||||||
|  | 		trace!("keys remaining {:?}", t1.db_items_remaining()); | ||||||
|  | 		assert!(t1.db_items_remaining().is_empty()); | ||||||
|  | 		let mut t2 = TrieDB::new_memory(); | ||||||
|  | 		t2.insert(&[0x01], &big_value.to_vec()); | ||||||
|  | 		t2.insert(&[0x01, 0x23], &big_value.to_vec()); | ||||||
|  | 		t2.insert(&[0x01, 0x34], &big_value.to_vec()); | ||||||
|  | 		t2.remove(&[0x01]); | ||||||
|  | 		assert!(t2.db_items_remaining().is_empty()); | ||||||
|  | 		/*if t1.root() != t2.root()*/ { | ||||||
|  | 			trace!("{:?}", t1); | ||||||
|  | 			trace!("{:?}", t2); | ||||||
|  | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	#[test] | 	#[test] | ||||||
| @ -1022,29 +1187,20 @@ mod tests { | |||||||
| 		//assert!(false);
 | 		//assert!(false);
 | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn random_key() -> Vec<u8> { |  | ||||||
| 		let chars = b"abcdefgrstuvwABCDEFGRSTUVW"; |  | ||||||
| 		let mut ret: Vec<u8> = Vec::new(); |  | ||||||
| 		let r = random::<u8>() % 4 + 1; |  | ||||||
| 		for _ in 0..r { |  | ||||||
| 			ret.push(chars[random::<usize>() % chars.len()]); |  | ||||||
| 		} |  | ||||||
| 		ret |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	#[test] | 	#[test] | ||||||
| 	fn stress() { | 	fn stress() { | ||||||
| 		for _ in 0..5000 { | 		for _ in 0..5000 { | ||||||
| 			let mut x: Vec<(Vec<u8>, Vec<u8>)> = Vec::new(); | 			let mut x: Vec<(Vec<u8>, Vec<u8>)> = Vec::new(); | ||||||
|  | 			let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; | ||||||
| 			for j in 0..4u32 { | 			for j in 0..4u32 { | ||||||
| 				let key = random_key(); | 				let key = random_key(alphabet, 5, 1); | ||||||
| 				x.push((key, rlp::encode(&j))); | 				x.push((key, rlp::encode(&j))); | ||||||
| 			} | 			} | ||||||
| 			let real = trie_root(x.clone()); | 			let real = trie_root(x.clone()); | ||||||
| 			let memtrie = trie_root_mem(&x); | 			let memtrie = populate_trie(&x); | ||||||
| 			let mut y = x.clone(); | 			let mut y = x.clone(); | ||||||
| 			y.sort_by(|ref a, ref b| a.0.cmp(&b.0)); | 			y.sort_by(|ref a, ref b| a.0.cmp(&b.0)); | ||||||
| 			let memtrie_sorted = trie_root_mem(&y); | 			let memtrie_sorted = populate_trie(&y); | ||||||
| 			if *memtrie.root() != real || *memtrie_sorted.root() != real { | 			if *memtrie.root() != real || *memtrie_sorted.root() != real { | ||||||
| 				println!("TRIE MISMATCH"); | 				println!("TRIE MISMATCH"); | ||||||
| 				println!(""); | 				println!(""); | ||||||
| @ -1064,18 +1220,6 @@ mod tests { | |||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	fn trie_root_mem(v: &Vec<(Vec<u8>, Vec<u8>)>) -> TrieDB { |  | ||||||
| 		let mut t = TrieDB::new_memory(); |  | ||||||
| 		
 |  | ||||||
| 		for i in 0..v.len() { |  | ||||||
| 			let key: &[u8]= &v[i].0; |  | ||||||
| 			let val: &[u8] = &v[i].1; |  | ||||||
| 			t.insert(&key, &val); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		t |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	#[test] | 	#[test] | ||||||
| 	fn test_trie_json() { | 	fn test_trie_json() { | ||||||
| 		println!("Json trie test: "); | 		println!("Json trie test: "); | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user