diff --git a/src/rlp.rs b/src/rlp.rs index ef1232c55..5b08aca2b 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -446,7 +446,7 @@ impl RlpStream { stream } - /// apends value to the end of stream, chainable + /// Apends value to the end of stream, chainable. pub fn append<'a, E>(&'a mut self, object: &E) -> &'a mut RlpStream where E: Encodable { @@ -454,13 +454,13 @@ impl RlpStream { object.encode(&mut self.encoder); // if list is finished, prepend the length - self.try_to_finish(); + self.try_to_finish(1); // return chainable self self } - /// declare appending the list of given size + /// Declare appending the list of given size, chainable. pub fn append_list<'a>(&'a mut self, len: usize) -> &'a mut RlpStream { // push new list let position = self.encoder.bytes.len(); @@ -468,7 +468,7 @@ impl RlpStream { 0 => { // we may finish, if the appended list len is equal 0 self.encoder.bytes.push(0xc0u8); - self.try_to_finish(); + self.try_to_finish(1); } _ => self.unfinished_lists.push_back(ListInfo::new(position, len)), } @@ -477,6 +477,18 @@ impl RlpStream { self } + /// Appends raw (pre-serialised) RLP data. Use with caution. Chainable. + pub fn append_raw<'a>(&'a mut self, bytes: &[u8], item_count: usize) -> &'a RlpStream { + // push raw items + self.encoder.bytes.extend(bytes); + + // try to finish and prepend the length + self.try_to_finish(item_count); + + // return chainable self + self + } + /// return true if stream is ready pub fn is_finished(&self) -> bool { self.unfinished_lists.back().is_none() @@ -491,11 +503,14 @@ impl RlpStream { } /// try to finish lists - fn try_to_finish(&mut self) -> () { + fn try_to_finish(&mut self, inserted_items: usize) -> () { let should_finish = match self.unfinished_lists.back_mut() { None => false, Some(ref mut x) => { - x.current += 1; + x.current += inserted_items; + if x.current > x.max { + panic!("You cannot append more items then you expect!"); + } x.current == x.max } }; @@ -504,7 +519,7 @@ impl RlpStream { let x = self.unfinished_lists.pop_back().unwrap(); let len = self.encoder.bytes.len() - x.position; self.encoder.insert_list_len_at_pos(len, x.position); - self.try_to_finish(); + self.try_to_finish(1); } } } diff --git a/src/triehash.rs b/src/triehash.rs index 5da09e747..7059cb5f9 100644 --- a/src/triehash.rs +++ b/src/triehash.rs @@ -1,8 +1,11 @@ //! Generete trie root -//use std::collections::HashMap; -//use hash::*; -//use rlp; +use std::collections::BTreeMap; +use std::cmp; +use hash::*; +use sha3::*; +use rlp; +use rlp::RlpStream; /// Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1. /// @@ -106,6 +109,63 @@ pub fn as_nibbles(bytes: &[u8]) -> Vec { res } +struct NibblePair { + nibble: Vec, + data: Vec +} + +pub fn ordered_trie_root(data: Vec>) -> H256 { + let vec: Vec = data + // first put elements into btree to sort them by nibbles + // optimize it later + .into_iter() + .fold(BTreeMap::new(), | mut acc, vec | { + let len = acc.len(); + acc.insert(as_nibbles(&rlp::encode(&len)), vec); + acc + }) + // then move them to a vector + .into_iter() + .map(|(k, v)| NibblePair { nibble: k, data: v } ) + .collect(); + + let out = match vec.len() { + 0 => rlp::encode(&""), + _ => { + let mut stream = RlpStream::new(); + hash256rlp(&vec, 0, &mut stream); + stream.out().unwrap() + } + }; + + out.sha3() +} + +fn shared_prefix_length(v1: &[T], v2: &[T]) -> usize where T: Eq { + let len = cmp::min(v1.len(), v2.len()); + (0..len).take_while(|&i| v1[i] == v2[i]).count() +} + +fn hash256rlp(vec: &[NibblePair], pre_len: usize, stream: &mut RlpStream) { + match vec.len() { + 0 => stream.append(&""), + 1 => stream.append_list(2).append(&hex_prefix_encode(&vec[0].nibble, true)).append(&vec[0].data), + _ => { + let shared_prefix = vec.iter() + // skip first element + .skip(1) + // get minimum number of shared nibbles between first string and each successive + .fold(usize::max_value(), | acc, pair | cmp::min(shared_prefix_length(&vec[0].nibble, &pair.nibble), acc) ); + //match shared_prefix > pre_len { + + //true => hex_prefix_encode(&vec[0].nibble + //} + panic!(); + + } + }; +} + #[cfg(test)] mod tests { } diff --git a/src/vector.rs b/src/vector.rs index ce891beba..7032335cc 100644 --- a/src/vector.rs +++ b/src/vector.rs @@ -1,4 +1,3 @@ - use std::ptr; pub trait InsertSlice { @@ -32,3 +31,6 @@ impl InsertSlice for Vec { } } } + +pub trait SharedPreifx { +}