Merge branch 'master' of github.com:gavofyork/ethcore-util into network

This commit is contained in:
arkpar 2016-01-08 13:32:52 +01:00
commit 1ffd999f96
15 changed files with 327 additions and 34 deletions

View File

@ -92,7 +92,10 @@ pub type Bytes = Vec<u8>;
/// Slice of bytes to underlying memory /// Slice of bytes to underlying memory
pub trait BytesConvertable { pub trait BytesConvertable {
// TODO: rename to as_slice
fn bytes(&self) -> &[u8]; fn bytes(&self) -> &[u8];
fn as_slice(&self) -> &[u8] { self.bytes() }
fn to_bytes(&self) -> Bytes { self.as_slice().to_vec() }
} }
impl<'a> BytesConvertable for &'a [u8] { impl<'a> BytesConvertable for &'a [u8] {
@ -322,10 +325,28 @@ impl <T>FromBytes for T where T: FixedHash {
use std::{mem, ptr}; use std::{mem, ptr};
let mut res: T = mem::uninitialized(); let mut res: T = mem::uninitialized();
ptr::copy(bytes.as_ptr(), res.mut_bytes().as_mut_ptr(), T::size()); ptr::copy(bytes.as_ptr(), res.as_slice_mut().as_mut_ptr(), T::size());
Ok(res) Ok(res)
} }
} }
} }
// TODO: tests and additional docs for these two.
/// Simple trait to allow for raw population of a Sized object from a byte slice.
pub trait Populatable {
/// Populate self from byte slice `d` in a raw fashion.
fn populate_raw(&mut self, d: &[u8]);
}
impl<T> Populatable for T where T: Sized {
fn populate_raw(&mut self, d: &[u8]) {
use std::mem;
use std::slice;
use std::io::Write;
unsafe {
slice::from_raw_parts_mut(self as *mut T as *mut u8, mem::size_of::<T>())
}.write(&d).unwrap();
}
}

View File

@ -1,13 +1,28 @@
use hash::*; use hash::*;
use secp256k1::Secp256k1; use secp256k1::{key, Secp256k1};
use secp256k1::key;
use rand::os::OsRng; use rand::os::OsRng;
pub type Secret=H256;
pub type Public=H512;
pub use ::sha3::Hashable; pub use ::sha3::Hashable;
pub type Secret = H256;
pub type Public = H512;
pub type Signature = H520;
impl Signature {
/// Create a new signature from the R, S and V componenets.
pub fn from_rsv(r: &H256, s: &H256, v: u8) -> Signature {
use std::ptr;
let mut ret: Signature = Signature::new();
unsafe {
let retslice: &mut [u8] = &mut ret;
ptr::copy(r.as_ptr(), retslice.as_mut_ptr(), 32);
ptr::copy(s.as_ptr(), retslice.as_mut_ptr().offset(32), 32);
}
ret[64] = v;
ret
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum CryptoError { pub enum CryptoError {
InvalidSecret, InvalidSecret,
@ -93,13 +108,16 @@ impl KeyPair {
pub fn secret(&self) -> &Secret { pub fn secret(&self) -> &Secret {
&self.secret &self.secret
} }
/// Sign a message with our secret key.
pub fn sign(&self, message: &H256) -> Result<Signature, CryptoError> { ec::sign(&self.secret, message) }
} }
pub mod ec { pub mod ec {
use hash::*; use hash::*;
use crypto::*; use crypto::*;
use crypto::{self};
pub type Signature = H520;
/// Recovers Public key from signed message hash. /// Recovers Public key from signed message hash.
pub fn recover(signature: &Signature, message: &H256) -> Result<Public, CryptoError> { pub fn recover(signature: &Signature, message: &H256) -> Result<Public, CryptoError> {
use secp256k1::*; use secp256k1::*;
@ -108,6 +126,7 @@ pub mod ec {
let publ = try!(context.recover(&try!(Message::from_slice(&message)), &rsig)); let publ = try!(context.recover(&try!(Message::from_slice(&message)), &rsig));
let serialized = publ.serialize_vec(&context, false); let serialized = publ.serialize_vec(&context, false);
let p: Public = Public::from_slice(&serialized[1..65]); let p: Public = Public::from_slice(&serialized[1..65]);
//TODO: check if it's the zero key and fail if so.
Ok(p) Ok(p)
} }
/// Returns siganture of message hash. /// Returns siganture of message hash.
@ -117,7 +136,7 @@ pub mod ec {
let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) }; let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) };
let s = try!(context.sign_recoverable(&try!(Message::from_slice(&message)), sec)); let s = try!(context.sign_recoverable(&try!(Message::from_slice(&message)), sec));
let (rec_id, data) = s.serialize_compact(&context); let (rec_id, data) = s.serialize_compact(&context);
let mut signature: ec::Signature = unsafe { ::std::mem::uninitialized() }; let mut signature: crypto::Signature = unsafe { ::std::mem::uninitialized() };
signature.clone_from_slice(&data); signature.clone_from_slice(&data);
signature[64] = rec_id.to_i32() as u8; signature[64] = rec_id.to_i32() as u8;
Ok(signature) Ok(signature)
@ -140,6 +159,15 @@ pub mod ec {
Err(x) => Err(<CryptoError as From<Error>>::from(x)) Err(x) => Err(<CryptoError as From<Error>>::from(x))
} }
} }
/// Check if each component of the signature is in range.
pub fn is_valid(sig: &Signature) -> bool {
sig[64] <= 1 &&
H256::from_slice(&sig[0..32]) < h256_from_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") &&
H256::from_slice(&sig[32..64]) < h256_from_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141") &&
H256::from_slice(&sig[32..64]) >= h256_from_u64(1) &&
H256::from_slice(&sig[0..32]) >= h256_from_u64(1)
}
} }
pub mod ecdh { pub mod ecdh {
@ -290,6 +318,8 @@ mod tests {
use hash::*; use hash::*;
use crypto::*; use crypto::*;
// TODO: tests for sign/recover roundtrip, at least.
#[test] #[test]
fn test_signature() { fn test_signature() {
let pair = KeyPair::create().unwrap(); let pair = KeyPair::create().unwrap();
@ -302,14 +332,14 @@ mod tests {
#[test] #[test]
fn test_invalid_key() { fn test_invalid_key() {
assert!(KeyPair::from_secret(Secret::from_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()).is_err()); assert!(KeyPair::from_secret(h256_from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")).is_err());
assert!(KeyPair::from_secret(Secret::from_str("0000000000000000000000000000000000000000000000000000000000000000").unwrap()).is_err()); assert!(KeyPair::from_secret(h256_from_hex("0000000000000000000000000000000000000000000000000000000000000000")).is_err());
assert!(KeyPair::from_secret(Secret::from_str("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141").unwrap()).is_err()); assert!(KeyPair::from_secret(h256_from_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141")).is_err());
} }
#[test] #[test]
fn test_key() { fn test_key() {
let pair = KeyPair::from_secret(Secret::from_str("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2").unwrap()).unwrap(); let pair = KeyPair::from_secret(h256_from_hex("6f7b0d801bc7b5ce7bbd930b84fd0369b3eb25d09be58d64ba811091046f3aa2")).unwrap();
assert_eq!(pair.public().hex(), "101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c"); assert_eq!(pair.public().hex(), "101b3ef5a4ea7a1c7928e24c4c75fd053c235d7b80c22ae5c03d145d0ac7396e2a4ffff9adee3133a7b05044a5cee08115fd65145e5165d646bde371010d803c");
} }
} }

View File

@ -13,7 +13,7 @@ pub enum EthcoreError {
FromHex(FromHexError), FromHex(FromHexError),
BaseData(BaseDataError), BaseData(BaseDataError),
BadSize, BadSize,
UnknownName UnknownName,
} }
impl From<FromHexError> for EthcoreError { impl From<FromHexError> for EthcoreError {

View File

@ -5,6 +5,7 @@ use std::fmt;
use std::ops; use std::ops;
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};
use std::ops::{Index, IndexMut, Deref, DerefMut, BitOr, BitAnd, BitXor}; use std::ops::{Index, IndexMut, Deref, DerefMut, BitOr, BitAnd, BitXor};
use std::cmp::{PartialOrd, Ordering};
use rustc_serialize::hex::*; use rustc_serialize::hex::*;
use error::EthcoreError; use error::EthcoreError;
use rand::Rng; use rand::Rng;
@ -21,7 +22,7 @@ pub trait FixedHash: Sized + BytesConvertable {
fn random() -> Self; fn random() -> Self;
fn randomize(&mut self); fn randomize(&mut self);
fn size() -> usize; fn size() -> usize;
fn mut_bytes(&mut self) -> &mut [u8]; fn as_slice_mut(&mut self) -> &mut [u8];
fn from_slice(src: &[u8]) -> Self; fn from_slice(src: &[u8]) -> Self;
fn clone_from_slice(&mut self, src: &[u8]) -> usize; fn clone_from_slice(&mut self, src: &[u8]) -> usize;
fn copy_to(&self, dest: &mut [u8]); fn copy_to(&self, dest: &mut [u8]);
@ -78,7 +79,7 @@ macro_rules! impl_hash {
$size $size
} }
fn mut_bytes(&mut self) -> &mut [u8] { fn as_slice_mut(&mut self) -> &mut [u8] {
&mut self.0 &mut self.0
} }
@ -150,7 +151,7 @@ macro_rules! impl_hash {
ptr += 1; ptr += 1;
} }
index &= mask; index &= mask;
ret.mut_bytes()[m - 1 - index / 8] |= 1 << (index % 8); ret.as_slice_mut()[m - 1 - index / 8] |= 1 << (index % 8);
} }
ret ret
@ -216,6 +217,19 @@ macro_rules! impl_hash {
} }
} }
impl PartialOrd for $from {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
for i in 0..$size {
if self.0[i] > other.0[i] {
return Some(Ordering::Greater);
} else if self.0[i] < other.0[i] {
return Some(Ordering::Less);
}
}
Some(Ordering::Equal)
}
}
impl Hash for $from { impl Hash for $from {
fn hash<H>(&self, state: &mut H) where H: Hasher { fn hash<H>(&self, state: &mut H) where H: Hasher {
state.write(&self.0); state.write(&self.0);
@ -343,7 +357,7 @@ macro_rules! impl_hash {
} }
impl<'a> From<&'a U256> for H256 { impl<'a> From<&'a U256> for H256 {
fn from(value: &'a U256) -> H256 { fn from(value: &'a U256) -> H256 {
unsafe { unsafe {
let mut ret: H256 = ::std::mem::uninitialized(); let mut ret: H256 = ::std::mem::uninitialized();
value.to_bytes(&mut ret); value.to_bytes(&mut ret);
@ -352,6 +366,46 @@ impl<'a> From<&'a U256> for H256 {
} }
} }
impl From<H256> for Address {
fn from(value: H256) -> Address {
unsafe {
let mut ret: Address = ::std::mem::uninitialized();
::std::ptr::copy(value.as_ptr().offset(12), ret.as_mut_ptr(), 20);
ret
}
}
}
impl From<Address> for H256 {
fn from(value: Address) -> H256 {
unsafe {
let mut ret = H256::new();
::std::ptr::copy(value.as_ptr(), ret.as_mut_ptr().offset(12), 20);
ret
}
}
}
pub fn h256_from_hex(s: &str) -> H256 {
use std::str::FromStr;
H256::from_str(s).unwrap()
}
pub fn h256_from_u64(n: u64) -> H256 {
use uint::U256;
H256::from(&U256::from(n))
}
pub fn address_from_hex(s: &str) -> Address {
use std::str::FromStr;
Address::from_str(s).unwrap()
}
pub fn address_from_u64(n: u64) -> Address {
let h256 = h256_from_u64(n);
From::from(h256)
}
impl_hash!(H32, 4); impl_hash!(H32, 4);
impl_hash!(H64, 8); impl_hash!(H64, 8);
impl_hash!(H128, 16); impl_hash!(H128, 16);
@ -414,5 +468,13 @@ mod tests {
assert!(my_bloom.contains_bloom(&address.sha3())); assert!(my_bloom.contains_bloom(&address.sha3()));
assert!(my_bloom.contains_bloom(&topic.sha3())); assert!(my_bloom.contains_bloom(&topic.sha3()));
} }
#[test]
fn from_and_to_address() {
let address = Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap();
let h = H256::from(address.clone());
let a = Address::from(h);
assert_eq!(address, a);
}
} }

8
src/key_manager.rs Normal file
View File

@ -0,0 +1,8 @@
enum Kdf {
Pbkdf2Sha256,
Scrypt
}

View File

@ -123,7 +123,7 @@ impl Handshake {
self.remote_public.clone_from_slice(pubk); self.remote_public.clone_from_slice(pubk);
self.remote_nonce.clone_from_slice(nonce); self.remote_nonce.clone_from_slice(nonce);
let shared = try!(ecdh::agree(host.secret(), &self.remote_public)); let shared = try!(ecdh::agree(host.secret(), &self.remote_public));
let signature = ec::Signature::from_slice(sig); let signature = Signature::from_slice(sig);
let spub = try!(ec::recover(&signature, &(&shared ^ &self.remote_nonce))); let spub = try!(ec::recover(&signature, &(&shared ^ &self.remote_nonce)));
if &spub.sha3()[..] != hepubk { if &spub.sha3()[..] != hepubk {
trace!(target:"net", "Handshake hash mismath with {:?}", self.connection.socket.peer_addr()); trace!(target:"net", "Handshake hash mismath with {:?}", self.connection.socket.peer_addr());

View File

@ -193,8 +193,11 @@ impl Encoder for BasicEncoder {
} }
} }
fn emit_list<F>(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> () fn emit_raw(&mut self, bytes: &[u8]) -> () {
{ self.bytes.append_slice(bytes);
}
fn emit_list<F>(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> () {
// get len before inserting a list // get len before inserting a list
let before_len = self.bytes.len(); let before_len = self.bytes.len();

View File

@ -6,6 +6,7 @@ pub trait Decoder: Sized {
fn as_list(&self) -> Result<Vec<Self>, DecoderError>; fn as_list(&self) -> Result<Vec<Self>, DecoderError>;
fn as_rlp<'a>(&'a self) -> &'a UntrustedRlp<'a>; fn as_rlp<'a>(&'a self) -> &'a UntrustedRlp<'a>;
fn as_raw(&self) -> &[u8];
} }
pub trait Decodable: Sized { pub trait Decodable: Sized {
@ -186,6 +187,7 @@ pub trait View<'a, 'view>: Sized {
pub trait Encoder { pub trait Encoder {
fn emit_value(&mut self, bytes: &[u8]) -> (); fn emit_value(&mut self, bytes: &[u8]) -> ();
fn emit_list<F>(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> (); fn emit_list<F>(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> ();
fn emit_raw(&mut self, bytes: &[u8]) -> ();
} }
pub trait Encodable { pub trait Encodable {

View File

@ -315,6 +315,10 @@ impl<'a> Decoder for BasicDecoder<'a> {
} }
} }
fn as_raw(&self) -> &[u8] {
self.rlp.raw()
}
fn as_list(&self) -> Result<Vec<Self>, DecoderError> { fn as_list(&self) -> Result<Vec<Self>, DecoderError> {
let v: Vec<BasicDecoder<'a>> = self.rlp.iter() let v: Vec<BasicDecoder<'a>> = self.rlp.iter()
.map(| i | BasicDecoder::new(i)) .map(| i | BasicDecoder::new(i))

View File

@ -30,7 +30,7 @@ impl<T> Hashable for T where T: BytesConvertable {
let mut keccak = Keccak::new_keccak256(); let mut keccak = Keccak::new_keccak256();
keccak.update(self.bytes()); keccak.update(self.bytes());
let mut ret: H256 = uninitialized(); let mut ret: H256 = uninitialized();
keccak.finalize(ret.mut_bytes()); keccak.finalize(ret.as_slice_mut());
ret ret
} }
} }

View File

@ -4,8 +4,12 @@ pub mod journal;
pub mod node; pub mod node;
pub mod triedb; pub mod triedb;
pub mod triedbmut; pub mod triedbmut;
pub mod sectriedb;
pub mod sectriedbmut;
pub use self::trietraits::*; pub use self::trietraits::*;
pub use self::standardmap::*; pub use self::standardmap::*;
pub use self::triedbmut::*; pub use self::triedbmut::*;
pub use self::triedb::*; pub use self::triedb::*;
pub use self::sectriedbmut::*;
pub use self::sectriedb::*;

59
src/trie/sectriedb.rs Normal file
View File

@ -0,0 +1,59 @@
use hash::*;
use sha3::*;
use hashdb::*;
use rlp::*;
use super::triedb::*;
use super::trietraits::*;
/// A `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
///
/// Use it as a `Trie` trait object. You can use `raw()` to get the backing TrieDB object.
pub struct SecTrieDB<'db> {
raw: TrieDB<'db>
}
impl<'db> SecTrieDB<'db> {
/// Create a new trie with the backing database `db` and empty `root`
/// Initialise to the state entailed by the genesis block.
/// This guarantees the trie is built correctly.
pub fn new(db: &'db HashDB, root: &'db H256) -> Self {
SecTrieDB { raw: TrieDB::new(db, root) }
}
/// Get a reference to the underlying raw TrieDB struct.
pub fn raw(&self) -> &TrieDB {
&self.raw
}
/// Get a mutable reference to the underlying raw TrieDB struct.
pub fn raw_mut(&mut self) -> &TrieDB {
&mut self.raw
}
}
impl<'db> Trie for SecTrieDB<'db> {
fn root(&self) -> &H256 { self.raw.root() }
fn contains(&self, key: &[u8]) -> bool {
self.raw.contains(&key.sha3())
}
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.raw.get(&key.sha3())
}
}
#[test]
fn trie_to_sectrie() {
use memorydb::*;
use super::triedbmut::*;
let mut memdb = MemoryDB::new();
let mut root = H256::new();
{
let mut t = TrieDBMut::new(&mut memdb, &mut root);
t.insert(&(&[0x01u8, 0x23]).sha3(), &[0x01u8, 0x23]);
}
let t = SecTrieDB::new(&memdb, &root);
assert_eq!(t.get(&[0x01u8, 0x23]).unwrap(), &[0x01u8, 0x23]);
}

65
src/trie/sectriedbmut.rs Normal file
View File

@ -0,0 +1,65 @@
use hash::*;
use sha3::*;
use hashdb::*;
use rlp::*;
use super::triedbmut::*;
use super::trietraits::*;
/// A mutable `Trie` implementation which hashes keys and uses a generic `HashDB` backing database.
///
/// Use it as a `Trie` or `TrieMut` trait object. You can use `raw()` to get the backing TrieDBMut object.
pub struct SecTrieDBMut<'db> {
raw: TrieDBMut<'db>
}
impl<'db> SecTrieDBMut<'db> {
/// Create a new trie with the backing database `db` and empty `root`
/// Initialise to the state entailed by the genesis block.
/// This guarantees the trie is built correctly.
pub fn new(db: &'db mut HashDB, root: &'db mut H256) -> Self {
SecTrieDBMut { raw: TrieDBMut::new(db, root) }
}
/// Create a new trie with the backing database `db` and `root`
/// Panics, if `root` does not exist
pub fn new_existing(db: &'db mut HashDB, root: &'db mut H256) -> Self {
SecTrieDBMut { raw: TrieDBMut::new_existing(db, root) }
}
}
impl<'db> Trie for SecTrieDBMut<'db> {
fn root(&self) -> &H256 { self.raw.root() }
fn contains(&self, key: &[u8]) -> bool {
self.raw.contains(&key.sha3())
}
fn get<'a, 'key>(&'a self, key: &'key [u8]) -> Option<&'a [u8]> where 'a: 'key {
self.raw.get(&key.sha3())
}
}
impl<'db> TrieMut for SecTrieDBMut<'db> {
fn insert(&mut self, key: &[u8], value: &[u8]) {
self.raw.insert(&key.sha3(), value);
}
fn remove(&mut self, key: &[u8]) {
self.raw.remove(&key.sha3());
}
}
#[test]
fn sectrie_to_trie() {
use memorydb::*;
use super::triedb::*;
let mut memdb = MemoryDB::new();
let mut root = H256::new();
{
let mut t = SecTrieDBMut::new(&mut memdb, &mut root);
t.insert(&[0x01u8, 0x23], &[0x01u8, 0x23]);
}
let t = TrieDB::new(&memdb, &root);
assert_eq!(t.get(&(&[0x01u8, 0x23]).sha3()).unwrap(), &[0x01u8, 0x23]);
}

View File

@ -9,18 +9,6 @@ use super::node::*;
use super::journal::*; use super::journal::*;
use super::trietraits::*; use super::trietraits::*;
pub struct TrieDBMut<'db> {
db: &'db mut HashDB,
root: &'db mut H256,
pub hash_count: usize,
}
/// Option-like type allowing either a Node object passthrough or Bytes in the case of data alteration.
enum MaybeChanged<'a> {
Same(Node<'a>),
Changed(Bytes),
}
/// A `Trie` implementation using a generic `HashDB` backing database. /// A `Trie` implementation using a generic `HashDB` backing database.
/// ///
/// Use it as a `Trie` trait object. You can use `db()` to get the backing database object, `keys` /// Use it as a `Trie` trait object. You can use `db()` to get the backing database object, `keys`
@ -52,6 +40,18 @@ enum MaybeChanged<'a> {
/// assert!(t.db_items_remaining().is_empty()); /// assert!(t.db_items_remaining().is_empty());
/// } /// }
/// ``` /// ```
pub struct TrieDBMut<'db> {
db: &'db mut HashDB,
root: &'db mut H256,
pub hash_count: usize,
}
/// Option-like type allowing either a Node object passthrough or Bytes in the case of data alteration.
enum MaybeChanged<'a> {
Same(Node<'a>),
Changed(Bytes),
}
impl<'db> TrieDBMut<'db> { impl<'db> TrieDBMut<'db> {
/// Create a new trie with the backing database `db` and empty `root` /// Create a new trie with the backing database `db` and empty `root`
/// Initialise to the state entailed by the genesis block. /// Initialise to the state entailed by the genesis block.
@ -686,7 +686,7 @@ mod tests {
0 => encode(&j), 0 => encode(&j),
_ => { _ => {
let mut h = H256::new(); let mut h = H256::new();
h.mut_bytes()[31] = j as u8; h.as_slice_mut()[31] = j as u8;
encode(&h) encode(&h)
}, },
} }

View File

@ -77,6 +77,41 @@ pub fn trie_root(input: Vec<(Vec<u8>, Vec<u8>)>) -> H256 {
gen_trie_root(gen_input) gen_trie_root(gen_input)
} }
/// Generates a key-hashed (secure) trie root hash for a vector of key-values.
///
/// ```rust
/// extern crate ethcore_util as util;
/// use std::str::FromStr;
/// use util::triehash::*;
/// use util::hash::*;
///
/// fn main() {
/// let v = vec![
/// (From::from("doe"), From::from("reindeer")),
/// (From::from("dog"), From::from("puppy")),
/// (From::from("dogglesworth"), From::from("cat")),
/// ];
///
/// let root = "d4cd937e4a4368d7931a9cf51686b7e10abb3dce38a39000fd7902a092b64585";
/// assert_eq!(sec_trie_root(v), H256::from_str(root).unwrap());
/// }
/// ```
pub fn sec_trie_root(input: Vec<(Vec<u8>, Vec<u8>)>) -> H256 {
let gen_input = input
// first put elements into btree to sort them and to remove duplicates
.into_iter()
.fold(BTreeMap::new(), | mut acc, (k, v) | {
acc.insert(k.sha3().to_vec(), v);
acc
})
// then move them to a vector
.into_iter()
.map(|(k, v)| (as_nibbles(&k), v) )
.collect();
gen_trie_root(gen_input)
}
fn gen_trie_root(input: Vec<(Vec<u8>, Vec<u8>)>) -> H256 { fn gen_trie_root(input: Vec<(Vec<u8>, Vec<u8>)>) -> H256 {
let mut stream = RlpStream::new(); let mut stream = RlpStream::new();
hash256rlp(&input, 0, &mut stream); hash256rlp(&input, 0, &mut stream);