From c91bc6b419722199392381fff690919e1dd62e6d Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 30 Nov 2015 02:57:02 +0100 Subject: [PATCH 1/5] Bug fix in nibble slice. Trie. --- src/hashdb.rs | 4 +++ src/memorydb.rs | 24 +++++++++++-- src/nibbleslice.rs | 22 ++++++++++++ src/overlaydb.rs | 1 + src/trie.rs | 86 +++++++++++++++++++++++++++++++++++++--------- 5 files changed, 119 insertions(+), 18 deletions(-) diff --git a/src/hashdb.rs b/src/hashdb.rs index 561c7843d..dd0973bb3 100644 --- a/src/hashdb.rs +++ b/src/hashdb.rs @@ -1,4 +1,5 @@ use hash::*; +use bytes::*; pub trait HashDB { /// Look up a given hash into the bytes that hash to it, returning None if the @@ -56,6 +57,9 @@ pub trait HashDB { /// ``` fn insert(&mut self, value: &[u8]) -> H256; + /// Like `insert()` , except you provide the key and the data is all moved. + fn emplace(&mut self, key: H256, value: Bytes); + /// 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. /// diff --git a/src/memorydb.rs b/src/memorydb.rs index 4ec02bd5e..14fae12d0 100644 --- a/src/memorydb.rs +++ b/src/memorydb.rs @@ -37,6 +37,12 @@ use std::collections::HashMap; /// m.kill(&k); /// assert!(!m.exists(&k)); /// +/// m.kill(&k); +/// assert!(!m.exists(&k)); +/// +/// m.insert(d); +/// assert!(!m.exists(&k)); + /// m.insert(d); /// assert!(m.exists(&k)); /// assert_eq!(m.lookup(&k).unwrap(), d); @@ -130,9 +136,9 @@ impl HashDB for MemoryDB { fn insert(&mut self, value: &[u8]) -> H256 { let key = value.sha3(); if match self.data.get_mut(&key) { - Some(&mut (ref mut old_value, ref mut rc @ 0)) => { + Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => { *old_value = From::from(value.bytes()); - *rc = 1; + *rc += 1; false }, Some(&mut (_, ref mut x)) => { *x += 1; false } , @@ -143,6 +149,20 @@ impl HashDB for MemoryDB { key } + fn emplace(&mut self, key: H256, value: Bytes) { + match self.data.get_mut(&key) { + Some(&mut (ref mut old_value, ref mut rc @ -0x80000000i32 ... 0)) => { + *old_value = value; + *rc += 1; + return; + }, + Some(&mut (_, ref mut x)) => { *x += 1; return; } , + None => {}, + } + // ... None falls through into... + self.data.insert(key, (value, 1)); + } + fn kill(&mut self, key: &H256) { if match self.data.get_mut(key) { Some(&mut (_, ref mut x)) => { *x -= 1; false } diff --git a/src/nibbleslice.rs b/src/nibbleslice.rs index e49244325..5866ed8f0 100644 --- a/src/nibbleslice.rs +++ b/src/nibbleslice.rs @@ -1,5 +1,6 @@ //! Nibble-orientated view onto byte-slice, allowing nibble-precision offsets. use std::cmp::*; +use bytes::*; /// Nibble-orientated view onto byte-slice, allowing nibble-precision offsets. /// @@ -69,6 +70,18 @@ impl<'a> NibbleSlice<'a> { } i } + + pub fn encoded(&self, is_leaf: bool) -> Bytes { + let l = self.len(); + let mut r = Bytes::with_capacity(l / 2 + 1); + let mut i = l % 2; + r.push(if i == 1 {0x10 + self.at(0)} else {0} + if is_leaf {0x20} else {0}); + while i < l { + r.push(self.at(i) * 16 + self.at(i + 1)); + i += 2; + } + r + } } impl<'a> PartialEq for NibbleSlice<'a> { @@ -126,6 +139,15 @@ mod tests { } } + #[test] + fn encoded() { + let n = NibbleSlice::new(D); + assert_eq!(n.encoded(false), &[0x00, 0x01, 0x23, 0x45]); + assert_eq!(n.encoded(true), &[0x20, 0x01, 0x23, 0x45]); + assert_eq!(n.mid(1).encoded(false), &[0x11, 0x23, 0x45]); + assert_eq!(n.mid(1).encoded(true), &[0x31, 0x23, 0x45]); + } + #[test] fn shared() { let n = NibbleSlice::new(D); diff --git a/src/overlaydb.rs b/src/overlaydb.rs index b6f2b3eb2..3c35d7255 100644 --- a/src/overlaydb.rs +++ b/src/overlaydb.rs @@ -186,6 +186,7 @@ impl HashDB for OverlayDB { } } fn insert(&mut self, value: &[u8]) -> H256 { self.overlay.insert(value) } + fn emplace(&mut self, key: H256, value: Bytes) { self.overlay.emplace(key, value); } fn kill(&mut self, key: &H256) { self.overlay.kill(key); } } diff --git a/src/trie.rs b/src/trie.rs index 889c9b5dc..80e753f84 100644 --- a/src/trie.rs +++ b/src/trie.rs @@ -1,8 +1,9 @@ use memorydb::*; use hashdb::*; use hash::*; -//use rlp::*; -//use bytes::*; +use nibbleslice::*; +use bytes::*; +use rlp::*; 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] ); @@ -17,10 +18,10 @@ pub trait Trie { fn is_empty(&self) -> bool { *self.root() == SHA3_NULL_RLP } // TODO: consider returning &[u8]... - fn contains(key: &[u8]) -> bool; - fn at(key: &[u8]) -> Option<&[u8]>; - fn insert(key: &[u8], value: &[u8]); - fn remove(key: &[u8]); + fn contains(&self, key: &[u8]) -> bool; + fn at(&self, key: &[u8]) -> Option<&[u8]>; + fn insert(&mut self, key: &[u8], value: &[u8]); + fn remove(&mut self, key: &[u8]); } pub struct TrieDB { @@ -28,6 +29,11 @@ pub struct TrieDB { root: H256, } +struct Diff { + new: Vec<(H256, Bytes)>, + old: Vec, +} + impl TrieDB { pub fn new(db: T) -> Self where T: HashDB + 'static { TrieDB{ db: Box::new(db), root: H256::new() } } @@ -35,36 +41,85 @@ impl TrieDB { pub fn new_memory() -> Self { TrieDB{ db: Box::new(MemoryDB::new()), root: H256::new() } } - pub fn init(&mut self) { self.insert_root(&NULL_RLP); } + pub fn init(&mut self) { self.set_root_rlp(&NULL_RLP); } pub fn db(&self) -> &HashDB { self.db.as_ref() } - fn insert_root(&mut self, root_data: &[u8]) { self.root = self.db.insert(root_data); } + fn set_root_rlp(&mut self, root_data: &[u8]) { + self.root = self.db.insert(root_data); + } + fn insert(&mut self, key: &NibbleSlice, value: &[u8]) { + // determine what the new root is, insert new nodes and remove old as necessary. + let mut todo: (Bytes, Diff); + { + let root_rlp = self.db.lookup(&self.root).unwrap(); + todo = self.merge(root_rlp, key, value); + } + self.apply(todo.1); + self.set_root_rlp(&todo.0); + } + + fn apply(&mut self, diff: Diff) { + for d in diff.old.iter() { + self.db.kill(&d); + } + for d in diff.new.into_iter() { + self.db.emplace(d.0, d.1); + } + } + + /// Determine the RLP of the node, assuming we're inserting `partial_key` into the + /// node at `old`. This will *not* delete the old mode; it will just return the new RLP + /// that includes the new node. + /// + /// The database will be updated so as to make the returned RLP valid through inserting + /// and deleting nodes as necessary. + fn merge(&self, old: &[u8], partial_key: &NibbleSlice, value: &[u8]) -> (Bytes, Diff) { + let o = Rlp::new(old); + match (o.type()) { + List(17) => { + // already have a branch. route and merge. + }, + List(2) => { + // already have an extension. either fast_forward, cleve or transmute_to_branch. + }, + Data(0) => compose_extension(partial_key), + _ -> panic!("Invalid RLP for node."), + } + } + + fn compose_extension(partial_key: &NibbleSlice, value: &[u8], is_leaf: bool) -> Bytes { + let mut s = RlpStream::new_list(2); + s.append(&partial_key.encoded(is_leaf)); + s.append(&value.to_vec()); // WTF?!?! + //s.append(value); // <-- should be. + s.out().unwrap() + } } impl Trie for TrieDB { fn root(&self) -> &H256 { &self.root } - fn contains(_key: &[u8]) -> bool { + fn contains(&self, _key: &[u8]) -> bool { unimplemented!(); } - fn at(_key: &[u8]) -> Option<&[u8]> { + fn at(&self, _key: &[u8]) -> Option<&[u8]> { unimplemented!(); } - fn insert(_key: &[u8], _value: &[u8]) { - unimplemented!(); + fn insert(&mut self, key: &[u8], value: &[u8]) { + (self as &mut TrieDB).insert(&NibbleSlice::new(key), value); } - fn remove(_key: &[u8]) { + fn remove(&mut self, _key: &[u8]) { unimplemented!(); } } #[test] -fn it_works() { +fn playpen() { use overlaydb::*; (&[1, 2, 3]).starts_with(&[1, 2]); @@ -73,6 +128,5 @@ fn it_works() { t.init(); assert_eq!(*t.root(), SHA3_NULL_RLP); assert!(t.is_empty()); - // TODO: make work: - //assert_eq!(t.root(), SHA3_NULL_RLP); + t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); } \ No newline at end of file From 2d556d6f06d25afa5a677e8ce37e1704105a7a70 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 30 Nov 2015 13:19:55 +0100 Subject: [PATCH 2/5] Add prototype. --- src/rlp.rs | 199 ++++++++++++++++++++++++++++------------------------ src/trie.rs | 13 ++-- 2 files changed, 116 insertions(+), 96 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index b9f58e78f..81355fb5d 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -126,6 +126,12 @@ impl<'a> From> for UntrustedRlp<'a> { } } +pub enum Prototype { + Null, + Data(usize), + List(usize), +} + impl<'a> Rlp<'a> { /// Create a new instance of `Rlp` pub fn new(bytes: &'a [u8]) -> Rlp<'a> { @@ -134,6 +140,19 @@ impl<'a> Rlp<'a> { } } + /// Get the prototype of the RLP. + pub fn prototype(&self) -> Prototype { + if self.is_data() { + Prototype::Data(self.size()) + } + else if self.is_list() { + Prototype::List(self.item_count()) + } + else { + Prototype::Null + } + } + /// The bare data of the rlp. /// /// ```rust @@ -148,7 +167,7 @@ impl<'a> Rlp<'a> { /// assert_eq!(dog, &[0x83, b'd', b'o', b'g']); /// } /// ``` - pub fn data(&'a self) -> &'a [u8] { + pub fn data(&self) -> &[u8] { self.rlp.data() } @@ -588,7 +607,7 @@ pub struct UntrustedRlpIterator<'a> { impl<'a> IntoIterator for &'a UntrustedRlp<'a> { type Item = UntrustedRlp<'a>; - type IntoIter = UntrustedRlpIterator<'a>; + type IntoIter = UntrustedRlpIterator<'a>; fn into_iter(self) -> Self::IntoIter { UntrustedRlpIterator { @@ -617,7 +636,7 @@ pub struct RlpIterator<'a> { impl<'a> IntoIterator for &'a Rlp<'a> { type Item = Rlp<'a>; - type IntoIter = RlpIterator<'a>; + type IntoIter = RlpIterator<'a>; fn into_iter(self) -> Self::IntoIter { RlpIterator { @@ -1147,63 +1166,63 @@ mod tests { #[test] fn encode_u16() { let tests = vec![ - ETestPair(0u16, vec![0x80u8]), - ETestPair(0x100, vec![0x82, 0x01, 0x00]), - ETestPair(0xffff, vec![0x82, 0xff, 0xff]), - ]; + ETestPair(0u16, vec![0x80u8]), + ETestPair(0x100, vec![0x82, 0x01, 0x00]), + ETestPair(0xffff, vec![0x82, 0xff, 0xff]), + ]; run_encode_tests(tests); } #[test] fn encode_u32() { let tests = vec![ - ETestPair(0u32, vec![0x80u8]), - ETestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]), - ETestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]), - ]; + ETestPair(0u32, vec![0x80u8]), + ETestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]), + ETestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]), + ]; run_encode_tests(tests); } #[test] fn encode_u64() { let tests = vec![ - ETestPair(0u64, vec![0x80u8]), - ETestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]), - ETestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]), - ]; + ETestPair(0u64, vec![0x80u8]), + ETestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]), + ETestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]), + ]; run_encode_tests(tests); } #[test] fn encode_u256() { let tests = vec![ETestPair(U256::from(0u64), vec![0x80u8]), - ETestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), - ETestPair(U256::from(0xffffffffu64), - vec![0x84, 0xff, 0xff, 0xff, 0xff]), - ETestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000\ - 000100000000000012f0") - .unwrap(), - vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, - 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])]; + ETestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + ETestPair(U256::from(0xffffffffu64), + vec![0x84, 0xff, 0xff, 0xff, 0xff]), + ETestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000\ + 000100000000000012f0") + .unwrap(), + vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])]; run_encode_tests(tests); } #[test] fn encode_str() { let tests = vec![ETestPair("cat", vec![0x83, b'c', b'a', b't']), - ETestPair("dog", vec![0x83, b'd', b'o', b'g']), - ETestPair("Marek", vec![0x85, b'M', b'a', b'r', b'e', b'k']), - ETestPair("", vec![0x80]), - ETestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit", - vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', - b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', - b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', - b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c', - b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i', - b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ', - b'e', b'l', b'i', b't'])]; + ETestPair("dog", vec![0x83, b'd', b'o', b'g']), + ETestPair("Marek", vec![0x85, b'M', b'a', b'r', b'e', b'k']), + ETestPair("", vec![0x80]), + ETestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit", + vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', + b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', + b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', + b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c', + b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i', + b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ', + b'e', b'l', b'i', b't'])]; run_encode_tests(tests); } @@ -1214,8 +1233,8 @@ mod tests { let tests = vec![ ETestPair(Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(), vec![0x94, 0xef, 0x2d, 0x6d, 0x19, 0x40, 0x84, 0xc2, 0xde, - 0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46, - 0xb3, 0x7d, 0x11, 0x06]) + 0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46, + 0xb3, 0x7d, 0x11, 0x06]) ]; run_encode_tests(tests); } @@ -1235,18 +1254,18 @@ mod tests { #[test] fn encode_vector_u64() { let tests = vec![ - ETestPair(vec![], vec![0xc0]), - ETestPair(vec![15u64], vec![0xc1, 0x0f]), - ETestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), - ETestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), - ]; + ETestPair(vec![], vec![0xc0]), + ETestPair(vec![15u64], vec![0xc1, 0x0f]), + ETestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), + ETestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), + ]; run_encode_tests(tests); } #[test] fn encode_vector_str() { let tests = vec![ETestPair(vec!["cat", "dog"], - vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; + vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; run_encode_tests(tests); } @@ -1262,7 +1281,7 @@ mod tests { stream.append(&"cat").append(&"dog"); let out = stream.out(); assert_eq!(out, - vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); + vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); } #[test] @@ -1284,7 +1303,7 @@ mod tests { } let out = stream.out(); assert_eq!(out, vec![0xd1, 0x80, 0x80, 0x80, 0x80, 0x80, - 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80]); } @@ -1326,65 +1345,65 @@ mod tests { #[test] fn decode_untrusted_u16() { let tests = vec![ - DTestPair(0u16, vec![0u8]), - DTestPair(0x100, vec![0x82, 0x01, 0x00]), - DTestPair(0xffff, vec![0x82, 0xff, 0xff]), - ]; + DTestPair(0u16, vec![0u8]), + DTestPair(0x100, vec![0x82, 0x01, 0x00]), + DTestPair(0xffff, vec![0x82, 0xff, 0xff]), + ]; run_decode_tests(tests); } #[test] fn decode_untrusted_u32() { let tests = vec![ - DTestPair(0u32, vec![0u8]), - DTestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]), - DTestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]), - ]; + DTestPair(0u32, vec![0u8]), + DTestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]), + DTestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]), + ]; run_decode_tests(tests); } #[test] fn decode_untrusted_u64() { let tests = vec![ - DTestPair(0u64, vec![0u8]), - DTestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]), - DTestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]), - ]; + DTestPair(0u64, vec![0u8]), + DTestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]), + DTestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]), + ]; run_decode_tests(tests); } #[test] fn decode_untrusted_u256() { let tests = vec![DTestPair(U256::from(0u64), vec![0x80u8]), - DTestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), - DTestPair(U256::from(0xffffffffu64), - vec![0x84, 0xff, 0xff, 0xff, 0xff]), - DTestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000\ - 000100000000000012f0") - .unwrap(), - vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, - 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])]; + DTestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + DTestPair(U256::from(0xffffffffu64), + vec![0x84, 0xff, 0xff, 0xff, 0xff]), + DTestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000\ + 000100000000000012f0") + .unwrap(), + vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])]; run_decode_tests(tests); } #[test] fn decode_untrusted_str() { let tests = vec![DTestPair("cat".to_string(), vec![0x83, b'c', b'a', b't']), - DTestPair("dog".to_string(), vec![0x83, b'd', b'o', b'g']), - DTestPair("Marek".to_string(), - vec![0x85, b'M', b'a', b'r', b'e', b'k']), - DTestPair("".to_string(), vec![0x80]), - DTestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit" - .to_string(), - vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', - b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', - b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', - b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c', - b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i', - b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ', - b'e', b'l', b'i', b't'])]; + DTestPair("dog".to_string(), vec![0x83, b'd', b'o', b'g']), + DTestPair("Marek".to_string(), + vec![0x85, b'M', b'a', b'r', b'e', b'k']), + DTestPair("".to_string(), vec![0x80]), + DTestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit" + .to_string(), + vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', + b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', + b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', + b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c', + b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i', + b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ', + b'e', b'l', b'i', b't'])]; run_decode_tests(tests); } @@ -1395,8 +1414,8 @@ mod tests { let tests = vec![ DTestPair(Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(), vec![0x94, 0xef, 0x2d, 0x6d, 0x19, 0x40, 0x84, 0xc2, 0xde, - 0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46, - 0xb3, 0x7d, 0x11, 0x06]) + 0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46, + 0xb3, 0x7d, 0x11, 0x06]) ]; run_decode_tests(tests); } @@ -1404,25 +1423,25 @@ mod tests { #[test] fn decode_untrusted_vector_u64() { let tests = vec![ - DTestPair(vec![], vec![0xc0]), - DTestPair(vec![15u64], vec![0xc1, 0x0f]), - DTestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), - DTestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), - ]; + DTestPair(vec![], vec![0xc0]), + DTestPair(vec![15u64], vec![0xc1, 0x0f]), + DTestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), + DTestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), + ]; run_decode_tests(tests); } #[test] fn decode_untrusted_vector_str() { let tests = vec![DTestPair(vec!["cat".to_string(), "dog".to_string()], - vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; + vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; run_decode_tests(tests); } #[test] fn decode_untrusted_vector_of_vectors_str() { let tests = vec![DTestPair(vec![vec!["cat".to_string()]], - vec![0xc5, 0xc4, 0x83, b'c', b'a', b't'])]; + vec![0xc5, 0xc4, 0x83, b'c', b'a', b't'])]; run_decode_tests(tests); } } diff --git a/src/trie.rs b/src/trie.rs index 80e753f84..9aaa83477 100644 --- a/src/trie.rs +++ b/src/trie.rs @@ -49,7 +49,7 @@ impl TrieDB { self.root = self.db.insert(root_data); } - fn insert(&mut self, key: &NibbleSlice, value: &[u8]) { + fn add(&mut self, key: &NibbleSlice, value: &[u8]) { // determine what the new root is, insert new nodes and remove old as necessary. let mut todo: (Bytes, Diff); { @@ -76,7 +76,8 @@ impl TrieDB { /// The database will be updated so as to make the returned RLP valid through inserting /// and deleting nodes as necessary. fn merge(&self, old: &[u8], partial_key: &NibbleSlice, value: &[u8]) -> (Bytes, Diff) { - let o = Rlp::new(old); + unimplemented!(); +/* let o = Rlp::new(old); match (o.type()) { List(17) => { // already have a branch. route and merge. @@ -85,8 +86,8 @@ impl TrieDB { // already have an extension. either fast_forward, cleve or transmute_to_branch. }, Data(0) => compose_extension(partial_key), - _ -> panic!("Invalid RLP for node."), - } + _ => panic!("Invalid RLP for node."), + }*/ } fn compose_extension(partial_key: &NibbleSlice, value: &[u8], is_leaf: bool) -> Bytes { @@ -94,7 +95,7 @@ impl TrieDB { s.append(&partial_key.encoded(is_leaf)); s.append(&value.to_vec()); // WTF?!?! //s.append(value); // <-- should be. - s.out().unwrap() + s.out() } } @@ -110,7 +111,7 @@ impl Trie for TrieDB { } fn insert(&mut self, key: &[u8], value: &[u8]) { - (self as &mut TrieDB).insert(&NibbleSlice::new(key), value); + (self as &mut TrieDB).add(&NibbleSlice::new(key), value); } fn remove(&mut self, _key: &[u8]) { From 7fd62527727dafc56424b8131127c3bf00466cf8 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 30 Nov 2015 13:25:37 +0100 Subject: [PATCH 3/5] Fix warnings, use Prototype. --- src/trie.rs | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/trie.rs b/src/trie.rs index 9aaa83477..8dd7fce90 100644 --- a/src/trie.rs +++ b/src/trie.rs @@ -34,6 +34,10 @@ struct Diff { old: Vec, } +impl Diff { + pub fn new() -> Diff { Diff { new: vec![], old: vec![] }} +} + impl TrieDB { pub fn new(db: T) -> Self where T: HashDB + 'static { TrieDB{ db: Box::new(db), root: H256::new() } } @@ -51,11 +55,11 @@ impl TrieDB { fn add(&mut self, key: &NibbleSlice, value: &[u8]) { // determine what the new root is, insert new nodes and remove old as necessary. - let mut todo: (Bytes, Diff); + let todo = { let root_rlp = self.db.lookup(&self.root).unwrap(); - todo = self.merge(root_rlp, key, value); - } + self.merge(root_rlp, key, value) + }; self.apply(todo.1); self.set_root_rlp(&todo.0); } @@ -76,18 +80,19 @@ impl TrieDB { /// The database will be updated so as to make the returned RLP valid through inserting /// and deleting nodes as necessary. fn merge(&self, old: &[u8], partial_key: &NibbleSlice, value: &[u8]) -> (Bytes, Diff) { - unimplemented!(); -/* let o = Rlp::new(old); - match (o.type()) { - List(17) => { + let o = Rlp::new(old); + match o.prototype() { + Prototype::List(17) => { // already have a branch. route and merge. + unimplemented!(); }, - List(2) => { + Prototype::List(2) => { // already have an extension. either fast_forward, cleve or transmute_to_branch. + unimplemented!(); }, - Data(0) => compose_extension(partial_key), + Prototype::Data(0) => (Self::compose_extension(partial_key, value, true), Diff::new()), _ => panic!("Invalid RLP for node."), - }*/ + } } fn compose_extension(partial_key: &NibbleSlice, value: &[u8], is_leaf: bool) -> Bytes { From 972b78d47bc159682f3b2603f0fec557dd395db3 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 30 Nov 2015 14:53:22 +0100 Subject: [PATCH 4/5] First insert in trie works! --- src/trie.rs | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/trie.rs b/src/trie.rs index 8dd7fce90..13b0a4e9a 100644 --- a/src/trie.rs +++ b/src/trie.rs @@ -50,14 +50,15 @@ impl TrieDB { pub fn db(&self) -> &HashDB { self.db.as_ref() } fn set_root_rlp(&mut self, root_data: &[u8]) { + self.db.kill(&self.root); self.root = self.db.insert(root_data); + println!("set_root_rlp {:?} {:?}", root_data, self.root); } fn add(&mut self, key: &NibbleSlice, value: &[u8]) { // determine what the new root is, insert new nodes and remove old as necessary. - let todo = - { - let root_rlp = self.db.lookup(&self.root).unwrap(); + let todo = { + let root_rlp = self.db.lookup(&self.root).expect("Trie root not found!"); self.merge(root_rlp, key, value) }; self.apply(todo.1); @@ -90,17 +91,22 @@ impl TrieDB { // already have an extension. either fast_forward, cleve or transmute_to_branch. unimplemented!(); }, - Prototype::Data(0) => (Self::compose_extension(partial_key, value, true), Diff::new()), + Prototype::Data(0) => { + (Self::compose_extension(partial_key, value, true), Diff::new()) + }, _ => panic!("Invalid RLP for node."), } } fn compose_extension(partial_key: &NibbleSlice, value: &[u8], is_leaf: bool) -> Bytes { + println!("compose_extension {:?} {:?} {:?} ({:?})", partial_key, value, is_leaf, partial_key.encoded(is_leaf)); let mut s = RlpStream::new_list(2); s.append(&partial_key.encoded(is_leaf)); s.append(&value.to_vec()); // WTF?!?! //s.append(value); // <-- should be. - s.out() + let r = s.out(); + println!("output: -> {:?}", &r); + r } } @@ -127,6 +133,7 @@ impl Trie for TrieDB { #[test] fn playpen() { use overlaydb::*; + use triehash::*; (&[1, 2, 3]).starts_with(&[1, 2]); @@ -134,5 +141,7 @@ fn playpen() { t.init(); assert_eq!(*t.root(), SHA3_NULL_RLP); assert!(t.is_empty()); + t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]); + assert_eq!(*t.root(), hash256(&[ NibblePair::new_raw(vec![0x01u8, 0x23], vec![0x01u8, 0x23])])); } \ No newline at end of file From ddd0baa70a9982a5e0d00f361065f5412d8c9c99 Mon Sep 17 00:00:00 2001 From: Gav Wood Date: Mon, 30 Nov 2015 15:01:43 +0100 Subject: [PATCH 5/5] data_at in RLP. --- src/rlp.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/rlp.rs b/src/rlp.rs index 81355fb5d..c3f237092 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -227,6 +227,10 @@ impl<'a> Rlp<'a> { From::from(self.rlp.at(index).unwrap()) } + pub fn data_at(&self, _index: usize) -> &[u8] { + unimplemented!(); + } + /// No value /// /// ```rust