From 0c9ef317b23b95df55f7085a5b7555626759bd6c Mon Sep 17 00:00:00 2001 From: debris Date: Mon, 30 Nov 2015 00:28:03 +0100 Subject: [PATCH] fixed encoding of bytes in rlp, fixed encoding of long lists, triehash + basic tests... more tests todo --- src/rlp.rs | 39 +++++++++++--- src/triehash.rs | 136 ++++++++++++++++++++++++++++++++++++++++-------- src/vector.rs | 14 +++++ 3 files changed, 161 insertions(+), 28 deletions(-) diff --git a/src/rlp.rs b/src/rlp.rs index feae875e3..1f791b3b7 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -456,9 +456,8 @@ impl RlpStream { } /// Apends value to the end of stream, chainable. - pub fn append<'a, E>(&'a mut self, object: &E) -> &'a mut RlpStream - where E: Encodable - { + pub fn append<'a, E>(&'a mut self, object: &E) -> &'a mut RlpStream where E: Encodable + fmt::Debug { + //println!("append: {:?}", object); // encode given value and add it at the end of the stream object.encode(&mut self.encoder); @@ -471,6 +470,7 @@ impl RlpStream { /// Declare appending the list of given size, chainable. pub fn append_list<'a>(&'a mut self, len: usize) -> &'a mut RlpStream { + //println!("append_list: {}", len); // push new list let position = self.encoder.bytes.len(); match len { @@ -488,6 +488,7 @@ impl RlpStream { /// Appends raw (pre-serialised) RLP data. Use with caution. Chainable. pub fn append_raw<'a>(&'a mut self, bytes: &[u8], item_count: usize) -> &'a mut RlpStream { + //println!("append_raw: {:?} len: {}, count: {}", bytes, bytes.len(), item_count); // push raw items self.encoder.bytes.extend(bytes); @@ -623,7 +624,7 @@ impl BasicEncoder { match len { 0...55 => res.push(0xc0u8 + len as u8), _ => { - res.push(0x7fu8 + len.to_bytes_len() as u8); + res.push(0xf7u8 + len.to_bytes_len() as u8); res.extend(len.to_bytes()); } }; @@ -658,8 +659,7 @@ impl Encoder for BasicEncoder { } } - fn emit_list(&mut self, f: F) -> () - where F: FnOnce(&mut Self) -> () + fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> () { // get len before inserting a list let before_len = self.bytes.len(); @@ -891,6 +891,33 @@ mod tests { assert_eq!(out, vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]); } + #[test] + fn rlp_stream_list2() { + let mut stream = RlpStream::new(); + stream.append_list(17); + for _ in 0..17 { + stream.append(&""); + } + let out = stream.out().unwrap(); + assert_eq!(out, vec![0xd1, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, + 0x80, 0x80, 0x80, 0x80, 0x80, 0x80]); + } + + #[test] + fn rlp_stream_list3() { + let mut stream = RlpStream::new(); + stream.append_list(17); + + let mut res = vec![0xf8, 0x44]; + for _ in 0..17 { + stream.append(&"aaa"); + res.extend(vec![0x83, b'a', b'a', b'a']); + } + let out = stream.out().unwrap(); + assert_eq!(out, res); + } + struct DTestPair(T, Vec) where T: rlp::Decodable + fmt::Debug + cmp::Eq; fn run_decode_tests(tests: Vec>) where T: rlp::Decodable + fmt::Debug + cmp::Eq { diff --git a/src/triehash.rs b/src/triehash.rs index ad553cf70..ff84695e4 100644 --- a/src/triehash.rs +++ b/src/triehash.rs @@ -139,6 +139,20 @@ impl NibblePair { } } +fn shared_nibble_prefix_len(vec: &[NibblePair]) -> usize { + if vec.len() == 0 { + return 0; + } + + vec.iter() + // skip first element + .skip(1) + // get minimum number of shared nibbles between first and each successive + .fold(vec[0].nibble.len(), | acc, pair | { + cmp::min(vec[0].nibble.shared_prefix_len(&pair.nibble), acc) + }) +} + pub fn ordered_trie_root(data: Vec>) -> H256 { let vec: Vec = data // first put elements into btree to sort them by nibbles @@ -167,7 +181,6 @@ pub fn hash256(vec: &[NibblePair]) -> H256 { } }; - println!("out: {:?}", out); out.sha3() } @@ -182,13 +195,7 @@ fn hash256rlp(vec: &[NibblePair], pre_len: usize, stream: &mut RlpStream) { stream.append(&vec[0].data); }, _ => { - let shared_prefix = vec.iter() - // skip first element - .skip(1) - // get minimum number of shared nibbles between first and each successive - .fold(usize::max_value(), | acc, pair | { - cmp::min(vec[0].nibble.shared_prefix_len(&pair.nibble), acc) - }); + let shared_prefix = shared_nibble_prefix_len(vec); match shared_prefix > pre_len { true => { @@ -199,12 +206,12 @@ fn hash256rlp(vec: &[NibblePair], pre_len: usize, stream: &mut RlpStream) { false => { stream.append_list(17); - // every nibble is longer then previous one - let iter = vec.iter() - // move to first element with len different then pre_len - .take_while(| pair | { pair.nibble.len() == pre_len }); - - let mut begin = iter.count(); + // if first nibble len is equal to pre_len + // move forward + let mut begin = match pre_len == vec[0].nibble.len() { + true => 1, + false => 0 + }; for i in 0..16 { // cout how many successive elements have same next nibble @@ -214,14 +221,14 @@ fn hash256rlp(vec: &[NibblePair], pre_len: usize, stream: &mut RlpStream) { match len { 0 => { stream.append(&""); }, - _ => hash256aux(&vec[begin..begin + len], pre_len + 1, stream) + _ => hash256aux(&vec[begin..(begin + len)], pre_len + 1, stream) } begin += len; } match pre_len == vec[0].nibble.len() { - true => stream.append(&vec[0].data), - false => stream.append(&"") + true => { stream.append(&vec[0].data); } , + false => { stream.append(&""); } }; } } @@ -239,6 +246,39 @@ fn hash256aux(vec: &[NibblePair], pre_len: usize, stream: &mut RlpStream) { }; } + +#[test] +fn test_shared_nibble_len() { + let len = shared_nibble_prefix_len(&vec![ + NibblePair::new(vec![0, 1, 2, 3, 4, 5, 6], vec![]), + NibblePair::new(vec![0, 1, 2, 3, 4, 5, 6], vec![]), + ]); + + assert_eq!(len , 7); +} + +#[test] +fn test_shared_nibble_len2() { + let len = shared_nibble_prefix_len(&vec![ + NibblePair::new(vec![0, 1, 2, 3, 4, 5, 6], vec![]), + NibblePair::new(vec![0, 1, 2, 3, 4, 5, 6], vec![]), + NibblePair::new(vec![4, 1, 2, 3, 4, 5, 6], vec![]) + ]); + + assert_eq!(len , 0); +} + +#[test] +fn test_shared_nibble_len3() { + let len = shared_nibble_prefix_len(&vec![ + NibblePair::new(vec![0, 1, 2, 3, 4, 5, 6], vec![]), + NibblePair::new(vec![0, 1, 2, 3, 4, 5, 6], vec![]), + NibblePair::new(vec![0, 1, 2, 4, 4, 5, 6], vec![]) + ]); + + assert_eq!(len , 3); +} + #[cfg(test)] mod tests { use std::str::FromStr; @@ -246,6 +286,8 @@ mod tests { use hash::*; use triehash::*; + + #[test] fn empty_trie_root() { assert_eq!(hash256(&vec![]), H256::from_str("56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421").unwrap()); @@ -262,9 +304,60 @@ mod tests { assert_eq!(hash256(&v), H256::from_str("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab").unwrap()); } + #[test] + fn foo_trie_item() { + + let v = vec![ + NibblePair::new_raw(From::from("foo"), + From::from("bar")), + NibblePair::new_raw(From::from("food"), + From::from("bass")) + ]; + + assert_eq!(hash256(&v), H256::from_str("17beaa1648bafa633cda809c90c04af50fc8aed3cb40d16efbddee6fdf63c4c3").unwrap()); + } + + #[test] + fn dogs_trie_item() { + + let v = vec![ + NibblePair::new_raw(From::from("doe"), + From::from("reindeer")), + + NibblePair::new_raw(From::from("dog"), + From::from("puppy")), + + NibblePair::new_raw(From::from("dogglesworth"), + From::from("cat")), + ]; + + assert_eq!(hash256(&v), H256::from_str("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3").unwrap()); + } + + #[test] + fn puppy_trie_items() { + + let v = vec![ + NibblePair::new_raw(From::from("do"), + From::from("verb")), + + NibblePair::new_raw(From::from("dog"), + From::from("puppy")), + + NibblePair::new_raw(From::from("doge"), + From::from("coin")), + + NibblePair::new_raw(From::from("horse"), + From::from("stallion")), + + ]; + + assert_eq!(hash256(&v), H256::from_str("5991bb8c6514148a29db676a14ac506cd2cd5775ace63c30a4fe457715e9ac84").unwrap()); + } + #[test] fn test_trie_root() { - let _v = vec![ + let v = vec![ NibblePair::new_raw("0000000000000000000000000000000000000000000000000000000000000045".from_hex().unwrap(), "22b224a1420a802ab51d326e29fa98e34c4f24ea".from_hex().unwrap()), @@ -290,10 +383,9 @@ mod tests { "697c7b8c961b56f675d570498424ac8de1a918f6".from_hex().unwrap()) ]; - let _root = H256::from_str("9f6221ebb8efe7cff60a716ecb886e67dd042014be444669f0159d8e68b42100").unwrap(); + let root = H256::from_str("9f6221ebb8efe7cff60a716ecb886e67dd042014be444669f0159d8e68b42100").unwrap(); - //let res = hash256(&v); - //println!("{:?}", res); - //assert_eq!(res, root); + let res = hash256(&v); + assert_eq!(res, root); } } diff --git a/src/vector.rs b/src/vector.rs index 41c932c92..552e285cf 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -64,8 +64,22 @@ mod test { #[test] fn test_shared_prefix() { + let a = vec![1,2,3,4,5,6]; + let b = vec![4,2,3,4,5,6]; + assert_eq!(a.shared_prefix_len(&b), 0); + } + + #[test] + fn test_shared_prefix2() { let a = vec![1,2,3,3,5]; let b = vec![1,2,3]; assert_eq!(a.shared_prefix_len(&b), 3); } + + #[test] + fn test_shared_prefix3() { + let a = vec![1,2,3,4,5,6]; + let b = vec![1,2,3,4,5,6]; + assert_eq!(a.shared_prefix_len(&b), 6); + } }