Merge branch 'master' of github.com:gavofyork/ethcore-util into network
This commit is contained in:
commit
1ffd999f96
23
src/bytes.rs
23
src/bytes.rs
@ -92,7 +92,10 @@ pub type Bytes = Vec<u8>;
|
||||
|
||||
/// Slice of bytes to underlying memory
|
||||
pub trait BytesConvertable {
|
||||
// TODO: rename to as_slice
|
||||
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] {
|
||||
@ -322,10 +325,28 @@ impl <T>FromBytes for T where T: FixedHash {
|
||||
use std::{mem, ptr};
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,28 @@
|
||||
use hash::*;
|
||||
use secp256k1::Secp256k1;
|
||||
use secp256k1::key;
|
||||
use secp256k1::{key, Secp256k1};
|
||||
use rand::os::OsRng;
|
||||
|
||||
pub type Secret=H256;
|
||||
pub type Public=H512;
|
||||
|
||||
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)]
|
||||
pub enum CryptoError {
|
||||
InvalidSecret,
|
||||
@ -93,13 +108,16 @@ impl KeyPair {
|
||||
pub fn 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 {
|
||||
use hash::*;
|
||||
use crypto::*;
|
||||
use crypto::{self};
|
||||
|
||||
pub type Signature = H520;
|
||||
/// Recovers Public key from signed message hash.
|
||||
pub fn recover(signature: &Signature, message: &H256) -> Result<Public, CryptoError> {
|
||||
use secp256k1::*;
|
||||
@ -108,6 +126,7 @@ pub mod ec {
|
||||
let publ = try!(context.recover(&try!(Message::from_slice(&message)), &rsig));
|
||||
let serialized = publ.serialize_vec(&context, false);
|
||||
let p: Public = Public::from_slice(&serialized[1..65]);
|
||||
//TODO: check if it's the zero key and fail if so.
|
||||
Ok(p)
|
||||
}
|
||||
/// Returns siganture of message hash.
|
||||
@ -117,7 +136,7 @@ pub mod ec {
|
||||
let sec: &key::SecretKey = unsafe { ::std::mem::transmute(secret) };
|
||||
let s = try!(context.sign_recoverable(&try!(Message::from_slice(&message)), sec));
|
||||
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[64] = rec_id.to_i32() as u8;
|
||||
Ok(signature)
|
||||
@ -140,6 +159,15 @@ pub mod ec {
|
||||
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 {
|
||||
@ -290,6 +318,8 @@ mod tests {
|
||||
use hash::*;
|
||||
use crypto::*;
|
||||
|
||||
// TODO: tests for sign/recover roundtrip, at least.
|
||||
|
||||
#[test]
|
||||
fn test_signature() {
|
||||
let pair = KeyPair::create().unwrap();
|
||||
@ -302,14 +332,14 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_invalid_key() {
|
||||
assert!(KeyPair::from_secret(Secret::from_str("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()).is_err());
|
||||
assert!(KeyPair::from_secret(Secret::from_str("0000000000000000000000000000000000000000000000000000000000000000").unwrap()).is_err());
|
||||
assert!(KeyPair::from_secret(Secret::from_str("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141").unwrap()).is_err());
|
||||
assert!(KeyPair::from_secret(h256_from_hex("ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")).is_err());
|
||||
assert!(KeyPair::from_secret(h256_from_hex("0000000000000000000000000000000000000000000000000000000000000000")).is_err());
|
||||
assert!(KeyPair::from_secret(h256_from_hex("fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141")).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
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");
|
||||
}
|
||||
}
|
||||
|
@ -13,7 +13,7 @@ pub enum EthcoreError {
|
||||
FromHex(FromHexError),
|
||||
BaseData(BaseDataError),
|
||||
BadSize,
|
||||
UnknownName
|
||||
UnknownName,
|
||||
}
|
||||
|
||||
impl From<FromHexError> for EthcoreError {
|
||||
|
70
src/hash.rs
70
src/hash.rs
@ -5,6 +5,7 @@ use std::fmt;
|
||||
use std::ops;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::ops::{Index, IndexMut, Deref, DerefMut, BitOr, BitAnd, BitXor};
|
||||
use std::cmp::{PartialOrd, Ordering};
|
||||
use rustc_serialize::hex::*;
|
||||
use error::EthcoreError;
|
||||
use rand::Rng;
|
||||
@ -21,7 +22,7 @@ pub trait FixedHash: Sized + BytesConvertable {
|
||||
fn random() -> Self;
|
||||
fn randomize(&mut self);
|
||||
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 clone_from_slice(&mut self, src: &[u8]) -> usize;
|
||||
fn copy_to(&self, dest: &mut [u8]);
|
||||
@ -78,7 +79,7 @@ macro_rules! impl_hash {
|
||||
$size
|
||||
}
|
||||
|
||||
fn mut_bytes(&mut self) -> &mut [u8] {
|
||||
fn as_slice_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
|
||||
@ -150,7 +151,7 @@ macro_rules! impl_hash {
|
||||
ptr += 1;
|
||||
}
|
||||
index &= mask;
|
||||
ret.mut_bytes()[m - 1 - index / 8] |= 1 << (index % 8);
|
||||
ret.as_slice_mut()[m - 1 - index / 8] |= 1 << (index % 8);
|
||||
}
|
||||
|
||||
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 {
|
||||
fn hash<H>(&self, state: &mut H) where H: Hasher {
|
||||
state.write(&self.0);
|
||||
@ -343,7 +357,7 @@ macro_rules! impl_hash {
|
||||
}
|
||||
|
||||
impl<'a> From<&'a U256> for H256 {
|
||||
fn from(value: &'a U256) -> H256 {
|
||||
fn from(value: &'a U256) -> H256 {
|
||||
unsafe {
|
||||
let mut ret: H256 = ::std::mem::uninitialized();
|
||||
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!(H64, 8);
|
||||
impl_hash!(H128, 16);
|
||||
@ -414,5 +468,13 @@ mod tests {
|
||||
assert!(my_bloom.contains_bloom(&address.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
8
src/key_manager.rs
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
enum Kdf {
|
||||
Pbkdf2Sha256,
|
||||
Scrypt
|
||||
}
|
||||
|
||||
|
||||
|
@ -123,7 +123,7 @@ impl Handshake {
|
||||
self.remote_public.clone_from_slice(pubk);
|
||||
self.remote_nonce.clone_from_slice(nonce);
|
||||
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)));
|
||||
if &spub.sha3()[..] != hepubk {
|
||||
trace!(target:"net", "Handshake hash mismath with {:?}", self.connection.socket.peer_addr());
|
||||
|
@ -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
|
||||
let before_len = self.bytes.len();
|
||||
|
||||
|
@ -6,6 +6,7 @@ pub trait Decoder: Sized {
|
||||
|
||||
fn as_list(&self) -> Result<Vec<Self>, DecoderError>;
|
||||
fn as_rlp<'a>(&'a self) -> &'a UntrustedRlp<'a>;
|
||||
fn as_raw(&self) -> &[u8];
|
||||
}
|
||||
|
||||
pub trait Decodable: Sized {
|
||||
@ -186,6 +187,7 @@ pub trait View<'a, 'view>: Sized {
|
||||
pub trait Encoder {
|
||||
fn emit_value(&mut self, bytes: &[u8]) -> ();
|
||||
fn emit_list<F>(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> ();
|
||||
fn emit_raw(&mut self, bytes: &[u8]) -> ();
|
||||
}
|
||||
|
||||
pub trait Encodable {
|
||||
|
@ -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> {
|
||||
let v: Vec<BasicDecoder<'a>> = self.rlp.iter()
|
||||
.map(| i | BasicDecoder::new(i))
|
||||
|
@ -30,7 +30,7 @@ impl<T> Hashable for T where T: BytesConvertable {
|
||||
let mut keccak = Keccak::new_keccak256();
|
||||
keccak.update(self.bytes());
|
||||
let mut ret: H256 = uninitialized();
|
||||
keccak.finalize(ret.mut_bytes());
|
||||
keccak.finalize(ret.as_slice_mut());
|
||||
ret
|
||||
}
|
||||
}
|
||||
|
@ -4,8 +4,12 @@ pub mod journal;
|
||||
pub mod node;
|
||||
pub mod triedb;
|
||||
pub mod triedbmut;
|
||||
pub mod sectriedb;
|
||||
pub mod sectriedbmut;
|
||||
|
||||
pub use self::trietraits::*;
|
||||
pub use self::standardmap::*;
|
||||
pub use self::triedbmut::*;
|
||||
pub use self::triedb::*;
|
||||
pub use self::sectriedbmut::*;
|
||||
pub use self::sectriedb::*;
|
||||
|
59
src/trie/sectriedb.rs
Normal file
59
src/trie/sectriedb.rs
Normal 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
65
src/trie/sectriedbmut.rs
Normal 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]);
|
||||
}
|
@ -9,18 +9,6 @@ use super::node::*;
|
||||
use super::journal::*;
|
||||
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.
|
||||
///
|
||||
/// 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());
|
||||
/// }
|
||||
/// ```
|
||||
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> {
|
||||
/// Create a new trie with the backing database `db` and empty `root`
|
||||
/// Initialise to the state entailed by the genesis block.
|
||||
@ -686,7 +686,7 @@ mod tests {
|
||||
0 => encode(&j),
|
||||
_ => {
|
||||
let mut h = H256::new();
|
||||
h.mut_bytes()[31] = j as u8;
|
||||
h.as_slice_mut()[31] = j as u8;
|
||||
encode(&h)
|
||||
},
|
||||
}
|
||||
|
@ -77,6 +77,41 @@ pub fn trie_root(input: Vec<(Vec<u8>, Vec<u8>)>) -> H256 {
|
||||
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 {
|
||||
let mut stream = RlpStream::new();
|
||||
hash256rlp(&input, 0, &mut stream);
|
||||
|
Loading…
Reference in New Issue
Block a user