diff --git a/src/trie.rs b/src/trie.rs index 30a186e80..8cf32037e 100644 --- a/src/trie.rs +++ b/src/trie.rs @@ -115,6 +115,7 @@ impl Diff { self.0.push(Operation::New(rlp_sha3, rlp)); } else { + trace!("new_node: inline node {:?}", &rlp); out.append_raw(&rlp, 1); } } @@ -142,13 +143,11 @@ pub struct TrieDB { } impl TrieDB { - pub fn new(db: T) -> Self where T: HashDB + 'static { TrieDB{ db: Box::new(db), root: H256::new() } } + pub fn new_boxed(db_box: Box) -> 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) -> Self { TrieDB{ db: db_box, root: H256::new() } } + pub fn new(db: T) -> Self where T: HashDB + 'static { Self::new_boxed(Box::new(db)) } - pub fn new_memory() -> Self { TrieDB{ db: Box::new(MemoryDB::new()), root: H256::new() } } - - pub fn init(&mut self) { self.set_root_rlp(&NULL_RLP); } + pub fn new_memory() -> Self { Self::new(MemoryDB::new()) } pub fn db(&self) -> &HashDB { self.db.as_ref() } @@ -159,6 +158,7 @@ impl TrieDB { } fn apply(&mut self, diff: Diff) { + trace!("applying {:?} changes", diff.0.len()); for d in diff.0.into_iter() { match d { Operation::Delete(h) => { @@ -198,11 +198,13 @@ impl TrieDB { } fn add(&mut self, key: &NibbleSlice, value: &[u8]) { + trace!("ADD: {:?} {:?}", key, value); // determine what the new root is, insert new nodes and remove old as necessary. let mut todo: Diff = Diff::new(); let root_rlp = self.augmented(self.db.lookup(&self.root).expect("Trie root not found!"), key, value, &mut todo); self.apply(todo); self.set_root_rlp(&root_rlp); + trace!("---"); } fn compose_leaf(partial: &NibbleSlice, value: &[u8]) -> Bytes { @@ -211,7 +213,7 @@ impl TrieDB { s.append(&partial.encoded(true)); s.append(&value); let r = s.out(); - trace!("output: -> {:?}", &r); + trace!("compose_leaf: -> {:?}", &r); r } @@ -221,7 +223,7 @@ impl TrieDB { s.append(&partial.encoded(is_leaf)); s.append_raw(raw_payload, 1); let r = s.out(); - println!("output: -> {:?}", &r); + println!("compose_raw: -> {:?}", &r); r } @@ -310,22 +312,16 @@ impl TrieDB { let mut s = RlpStream::new_list(17); let index = if partial.is_empty() {16} else {partial.at(0) as usize}; for i in 0usize..17 { - if index == i { - // this is node to augment into... - if orig.at(i).is_empty() { - // easy - original had empty slot. - diff.new_node(Self::compose_leaf(&partial.mid(if i == 16 {0} else {1}), value), &mut s); - } else if i == 16 { - // leaf entry - just replace. - let new = Self::compose_leaf(&partial.mid(if i == 16 {0} else {1}), value); - diff.replace_node(&orig.at(i), new, &mut s); - } else { - // harder - original has something there already + match (index == i, i) { + (true, 16) => // leaf entry - just replace. + { s.append(&value); }, + (true, i) if orig.at(i).is_empty() => // easy - original had empty slot. + diff.new_node(Self::compose_leaf(&partial.mid(1), value), &mut s), + (true, i) => { // harder - original has something there already let new = self.augmented(orig.at(i).raw(), &partial.mid(1), value, diff); diff.replace_node(&orig.at(i), new, &mut s); } - } else { - s.append_raw(orig.at(i).raw(), 1); + (false, i) => { s.append_raw(orig.at(i).raw(), 1); }, } } s.out() @@ -345,6 +341,7 @@ impl TrieDB { let old_rlp = Rlp::new(old); match old_rlp.prototype() { Prototype::List(17) => { + trace!("branch: ROUTE,AUGMENT"); // already have a branch. route and augment. self.augmented_into_branch(&old_rlp, partial, value, diff) }, @@ -396,6 +393,7 @@ impl TrieDB { } }, Prototype::Data(0) => { + trace!("empty: COMPOSE"); Self::compose_leaf(partial, value) }, _ => panic!("Invalid RLP for node."), @@ -425,7 +423,6 @@ impl Trie for TrieDB { #[cfg(test)] mod tests { - use memorydb::*; use triehash::*; use super::*; use nibbleslice::*; @@ -479,15 +476,13 @@ mod tests { #[test] fn test_at_empty() { - let mut t = TrieDB::new(MemoryDB::new()); - t.init(); + let mut t = TrieDB::new_memory(); assert_eq!(t.at(&[0x5]), None); } #[test] fn test_at_one() { - let mut t = TrieDB::new(MemoryDB::new()); - t.init(); + let mut t = TrieDB::new_memory(); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); assert_eq!(t.at(&[0x1, 0x23]).unwrap(), &[0x1u8, 0x23]); } @@ -496,33 +491,58 @@ mod tests { fn playpen() { env_logger::init().unwrap(); - let mut t = TrieDB::new(MemoryDB::new()); - t.init(); + let mut t = TrieDB::new_memory(); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); + t.insert(&[], &[0x0]); + assert_eq!(*t.root(), trie_root(vec![ + (vec![], vec![0x0]), + (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), + ])); } #[test] fn init() { - let mut t = TrieDB::new(MemoryDB::new()); - t.init(); + let t = TrieDB::new_memory(); assert_eq!(*t.root(), SHA3_NULL_RLP); assert!(t.is_empty()); } #[test] fn insert_on_empty() { - let mut t = TrieDB::new(MemoryDB::new()); - t.init(); + let mut t = TrieDB::new_memory(); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x01u8, 0x23]) ])); } #[test] fn insert_replace_root() { - let mut t = TrieDB::new(MemoryDB::new()); - t.init(); + let mut t = TrieDB::new_memory(); t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); t.insert(&[0x01u8, 0x23], &[0x23u8, 0x45]); assert_eq!(*t.root(), trie_root(vec![ (vec![0x01u8, 0x23], vec![0x23u8, 0x45]) ])); } + + #[test] + fn insert_make_branch_root() { + let mut t = TrieDB::new_memory(); + t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); + t.insert(&[0x11u8, 0x23], &[0x11u8, 0x23]); + assert_eq!(*t.root(), trie_root(vec![ + (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), + (vec![0x11u8, 0x23], vec![0x11u8, 0x23]) + ])); + } + + #[test] + fn insert_into_branch_root() { + let mut t = TrieDB::new_memory(); + t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); + t.insert(&[0xf1u8, 0x23], &[0xf1u8, 0x23]); + t.insert(&[0x81u8, 0x23], &[0x81u8, 0x23]); + assert_eq!(*t.root(), trie_root(vec![ + (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), + (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), + (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), + ])); + } } diff --git a/src/triehash.rs b/src/triehash.rs index e26cc255f..8be23e210 100644 --- a/src/triehash.rs +++ b/src/triehash.rs @@ -319,6 +319,20 @@ mod tests { assert_eq!(trie_root(v), H256::from_str("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84").unwrap()); } + #[test] + fn out_of_order() { + assert!(trie_root(vec![ + (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), + (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), + (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), + ]) == + trie_root(vec![ + (vec![0x01u8, 0x23], vec![0x01u8, 0x23]), + (vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), + (vec![0x81u8, 0x23], vec![0x81u8, 0x23]), + ])); + } + #[test] fn test_trie_root() { let v = vec![