From 47f8695c3b1f4e688baa64565baedc0b9aeea7ee Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 28 Nov 2015 01:38:00 +0100 Subject: [PATCH 1/5] common changes in hash --- src/bloom.rs | 7 ------- src/hash.rs | 34 ++++++++++++++++++++++++++-------- src/lib.rs | 1 - src/sha3.rs | 2 +- 4 files changed, 27 insertions(+), 17 deletions(-) delete mode 100644 src/bloom.rs diff --git a/src/bloom.rs b/src/bloom.rs deleted file mode 100644 index fe619fae6..000000000 --- a/src/bloom.rs +++ /dev/null @@ -1,7 +0,0 @@ -use bytes::BytesConvertable; -// use hash::FixedHash; - -pub trait Bloomable { - fn shift_bloom(&mut self, bytes: &T) where T: BytesConvertable; - fn contains_bloom(&self, bytes: &T) -> bool where T: BytesConvertable; -} diff --git a/src/hash.rs b/src/hash.rs index 98a76ad87..310a11dbb 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -9,10 +9,13 @@ use rand::os::OsRng; use bytes::BytesConvertable; /// types implementing FixedHash must be also BytesConvertable -pub trait FixedHash: BytesConvertable { +pub trait FixedHash: Sized + BytesConvertable { + fn new() -> Self; fn random() -> Self; fn randomize(&mut self); fn mut_bytes(&mut self) -> &mut [u8]; + fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash; + fn bloom_part(&self) -> T where T: FixedHash; } macro_rules! impl_hash { @@ -20,13 +23,6 @@ macro_rules! impl_hash { #[derive(Eq)] pub struct $from (pub [u8; $size]); - - impl $from { - fn new() -> $from { - $from([0; $size]) - } - } - impl BytesConvertable for $from { fn bytes(&self) -> &[u8] { &self.0 @@ -34,6 +30,10 @@ macro_rules! impl_hash { } impl FixedHash for $from { + fn new() -> $from { + $from([0; $size]) + } + fn random() -> $from { let mut hash = $from::new(); hash.randomize(); @@ -48,6 +48,24 @@ macro_rules! impl_hash { fn mut_bytes(&mut self) -> &mut [u8] { &mut self.0 } + + fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash { + let bp: Self = b.bloom_part(); + let new_self = &bp | self; + + // impl |= instead + + unsafe { + use std::{mem, ptr}; + ptr::copy(new_self.0.as_ptr(), self.0.as_mut_ptr(), mem::size_of::()); + } + + self + } + + fn bloom_part(&self) -> T where T: FixedHash { + panic!() + } } impl FromStr for $from { diff --git a/src/lib.rs b/src/lib.rs index a52e35925..7c480c02b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,7 +16,6 @@ pub mod rlp; pub mod vector; pub mod db; pub mod sha3; -pub mod bloom; //pub mod network; diff --git a/src/sha3.rs b/src/sha3.rs index b7eec2a5f..ee328913c 100644 --- a/src/sha3.rs +++ b/src/sha3.rs @@ -3,7 +3,7 @@ use tiny_keccak::keccak_256; use bytes::BytesConvertable; use hash::{FixedHash, H256}; -trait Hashable { +pub trait Hashable { fn sha3(&self) -> H256; } From 33eeb8f47773b1979bd2f83844459255ceeef565 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 28 Nov 2015 03:02:06 +0100 Subject: [PATCH 2/5] math.rs, log2, FixedHash::shift_bloom, FixedHash::contains_bloom --- src/hash.rs | 147 ++++++++++++++++++++++++++++++++++++++++++---------- src/lib.rs | 1 + src/math.rs | 10 ++++ 3 files changed, 132 insertions(+), 26 deletions(-) create mode 100644 src/math.rs diff --git a/src/hash.rs b/src/hash.rs index 310a11dbb..8612cf226 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -1,12 +1,13 @@ use std::str::FromStr; use std::fmt; use std::hash::{Hash, Hasher}; -use std::ops::{Index, IndexMut, BitOr}; +use std::ops::{Index, IndexMut, BitOr, BitAnd}; use rustc_serialize::hex::*; use error::EthcoreError; use rand::Rng; use rand::os::OsRng; use bytes::BytesConvertable; +use math::log2; /// types implementing FixedHash must be also BytesConvertable pub trait FixedHash: Sized + BytesConvertable { @@ -15,7 +16,8 @@ pub trait FixedHash: Sized + BytesConvertable { fn randomize(&mut self); fn mut_bytes(&mut self) -> &mut [u8]; fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash; - fn bloom_part(&self) -> T where T: FixedHash; + fn bloom_part(&self, m: usize) -> T where T: FixedHash; + fn contains_bloom(&self, b: &T) -> bool where T: FixedHash; } macro_rules! impl_hash { @@ -50,7 +52,7 @@ macro_rules! impl_hash { } fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash { - let bp: Self = b.bloom_part(); + let bp: Self = b.bloom_part($size); let new_self = &bp | self; // impl |= instead @@ -63,8 +65,45 @@ macro_rules! impl_hash { self } - fn bloom_part(&self) -> T where T: FixedHash { - panic!() + fn bloom_part(&self, m: usize) -> T where T: FixedHash { + // numbers of bits + // TODO: move it to some constant + let p = 3; + + let bloom_bits = m * 8; + let mask = bloom_bits - 1; + let bloom_bytes = (log2(bloom_bits) + 7) / 8; + //println!("bb: {}", bloom_bytes); + + // must be a power of 2 + assert_eq!(m & (m - 1), 0); + // out of range + assert!(p * bloom_bytes <= $size); + + // return type + let mut ret = T::new(); + + // 'ptr' to out slice + let mut ptr = 0; + + // set p number of bits, + // p is equal 3 according to yellowpaper + for _ in 0..p { + let mut index = 0 as usize; + for _ in 0..bloom_bytes { + index = (index << 8) | self.0[ptr] as usize; + ptr += 1; + } + index &= mask; + ret.mut_bytes()[m - 1 - index / 8] |= 1 << (index % 8); + } + + ret + } + + fn contains_bloom(&self, b: &T) -> bool where T: FixedHash { + let bp: Self = b.bloom_part($size); + (&bp & self) == bp } } @@ -138,6 +177,7 @@ macro_rules! impl_hash { } } + /// BitOr on references impl<'a> BitOr for &'a $from { type Output = $from; @@ -153,6 +193,7 @@ macro_rules! impl_hash { } } + /// Moving BitOr impl BitOr for $from { type Output = $from; @@ -161,6 +202,31 @@ macro_rules! impl_hash { } } + /// BitAnd on references + impl <'a> BitAnd for &'a $from { + type Output = $from; + + fn bitand(self, rhs: Self) -> Self::Output { + unsafe { + use std::mem; + let mut ret: $from = mem::uninitialized(); + for i in 0..$size { + ret.0[i] = self.0[i] & rhs.0[i]; + } + ret + } + } + } + + /// Moving BitAnd + impl BitAnd for $from { + type Output = $from; + + fn bitand(self, rhs: Self) -> Self::Output { + &self & &rhs + } + } + } } @@ -173,26 +239,55 @@ impl_hash!(H520, 65); impl_hash!(H1024, 128); impl_hash!(H2048, 256); -#[test] -fn hash() { - let h = H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); - assert_eq!(H64::from_str("0123456789abcdef").unwrap(), h); - assert_eq!(format!("{}", h), "0123456789abcdef"); - assert_eq!(format!("{:?}", h), "0123456789abcdef"); - assert!(h == h); - assert!(h != H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xee])); - assert!(h != H64([0; 8])); +#[cfg(test)] +mod tests { + use hash::*; + use std::str::FromStr; + + #[test] + fn hash() { + let h = H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]); + assert_eq!(H64::from_str("0123456789abcdef").unwrap(), h); + assert_eq!(format!("{}", h), "0123456789abcdef"); + assert_eq!(format!("{:?}", h), "0123456789abcdef"); + assert!(h == h); + assert!(h != H64([0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xee])); + assert!(h != H64([0; 8])); + } + + #[test] + fn hash_bitor() { + let a = H64([1; 8]); + let b = H64([2; 8]); + let c = H64([3; 8]); + + // borrow + assert_eq!(&a | &b, c); + + // move + assert_eq!(a | b, c); + } + + #[test] + fn shift_bloom() { + use sha3::Hashable; + + let bloom = H2048::from_str("00000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000002020000000000000000000000000000000000000000000008000000001000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap(); + let address = Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(); + let topic = H256::from_str("02c69be41d0b7e40352fc85be1cd65eb03d40ef8427a0ca4596b1ead9a00e9fc").unwrap(); + + let mut my_bloom = H2048::new(); + assert!(!my_bloom.contains_bloom(&address.sha3())); + assert!(!my_bloom.contains_bloom(&topic.sha3())); + + my_bloom.shift_bloom(&address.sha3()); + assert!(my_bloom.contains_bloom(&address.sha3())); + assert!(!my_bloom.contains_bloom(&topic.sha3())); + + my_bloom.shift_bloom(&topic.sha3()); + assert_eq!(my_bloom, bloom); + assert!(my_bloom.contains_bloom(&address.sha3())); + assert!(my_bloom.contains_bloom(&topic.sha3())); + } } -#[test] -fn hash_bitor() { - let a = H64([1; 8]); - let b = H64([2; 8]); - let c = H64([3; 8]); - - // borrow - assert_eq!(&a | &b, c); - - // move - assert_eq!(a | b, c); -} diff --git a/src/lib.rs b/src/lib.rs index a43585e0c..f94bceb86 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ pub mod db; pub mod sha3; pub mod hashdb; pub mod memorydb; +pub mod math; //pub mod network; diff --git a/src/math.rs b/src/math.rs new file mode 100644 index 000000000..ba039f3d0 --- /dev/null +++ b/src/math.rs @@ -0,0 +1,10 @@ +/// log2 +pub fn log2(x: usize) -> u32 { + if x <= 1 { + return 0; + } + + let n = x.leading_zeros(); + ::std::mem::size_of::() as u32 * 8 - n +} + From 111fc70d0b165324d380dc73570af93d91beb3fb Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 28 Nov 2015 03:58:37 +0100 Subject: [PATCH 3/5] updated docs --- src/bytes.rs | 46 ++++++++++++++++++++++++++++++++++++++++------ src/hash.rs | 2 +- src/lib.rs | 5 +++++ 3 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/bytes.rs b/src/bytes.rs index 9521abdbd..0f82748a1 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -1,17 +1,47 @@ -//! To/From Bytes conversation for basic types -//! -//! Types implementing `ToBytes` and `FromBytes` traits -//! can be easily converted to and from bytes +//! Unified interfaces for bytes operations on basic types //! //! # Examples +//! ```rust +//! extern crate ethcore_util as util; +//! +//! fn bytes_convertable() { +//! use util::bytes::BytesConvertable; //! +//! let arr = [0; 5]; +//! let slice: &[u8] = arr.bytes(); +//! } +//! +//! fn to_bytes() { +//! use util::bytes::ToBytes; +//! +//! let a: Vec = "hello_world".to_bytes(); +//! let b: Vec = 400u32.to_bytes(); +//! let c: Vec = 0xffffffffffffffffu64.to_bytes(); +//! } +//! +//! fn from_bytes() { +//! use util::bytes::FromBytes; +//! +//! let a = String::from_bytes(&[b'd', b'o', b'g']); +//! let b = u8::from_bytes(&[0xfa]); +//! let c = u64::from_bytes(&[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff]); +//! } +//! +//! fn main() { +//! bytes_convertable(); +//! to_bytes(); +//! from_bytes(); +//! } +//! ``` use std::fmt; use std::error::Error as StdError; use uint::{U128, U256}; +/// Vector of bytes pub type Bytes = Vec; +/// Slice of bytes to underlying memory pub trait BytesConvertable { fn bytes(&self) -> &[u8]; } @@ -46,6 +76,8 @@ fn bytes_convertable() { assert_eq!([0u8; 0].bytes(), &[]); } +/// Converts given type to its shortest representation in bytes +/// /// TODO: optimise some conversations pub trait ToBytes { fn to_bytes(&self) -> Vec; @@ -141,6 +173,7 @@ macro_rules! impl_uint_to_bytes { impl_uint_to_bytes!(U256); impl_uint_to_bytes!(U128); +/// Error returned when FromBytes conversation goes wrong #[derive(Debug, PartialEq, Eq)] pub enum FromBytesError { UnexpectedEnd @@ -156,10 +189,11 @@ impl fmt::Display for FromBytesError { } } +/// Alias for the result of FromBytes trait pub type FromBytesResult = Result; -/// implements "Sized", so the compiler can deducate the size -/// of the return type +/// Converts to given type from its bytes representation +/// /// TODO: check size of bytes before conversation and return appropriate error pub trait FromBytes: Sized { fn from_bytes(bytes: &[u8]) -> FromBytesResult; diff --git a/src/hash.rs b/src/hash.rs index 8612cf226..0dfd4f487 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -23,7 +23,7 @@ pub trait FixedHash: Sized + BytesConvertable { macro_rules! impl_hash { ($from: ident, $size: expr) => { #[derive(Eq)] - pub struct $from (pub [u8; $size]); + pub struct $from ([u8; $size]); impl BytesConvertable for $from { fn bytes(&self) -> &[u8] { diff --git a/src/lib.rs b/src/lib.rs index f94bceb86..acb03afb5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,7 @@ +//! Ethcore-util library +//! +//! TODO: check reexports + extern crate rustc_serialize; extern crate mio; extern crate rand; @@ -20,6 +24,7 @@ pub mod math; //pub mod network; +// reexports pub use std::str::FromStr; pub use hash::*; pub use sha3::*; From 07f3e6d5a5cc5c7a1ae254dac9092ab2602b2ba4 Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 28 Nov 2015 10:50:41 +0100 Subject: [PATCH 4/5] updated tests for rlp and indention in benches --- benches/rlp.rs | 107 +++++++++++++++++++++++++------------------------ src/rlp.rs | 79 ++++++++++++++++++++++++++---------- 2 files changed, 112 insertions(+), 74 deletions(-) diff --git a/benches/rlp.rs b/benches/rlp.rs index 73af76bbe..f6a13f260 100644 --- a/benches/rlp.rs +++ b/benches/rlp.rs @@ -1,7 +1,7 @@ //! benchmarking for rlp //! should be started with: //! ```bash -//! multirust run nightly cargo bench +//! multirust run nightly cargo bench //! ``` #![feature(test)] @@ -16,80 +16,81 @@ use ethcore_util::uint::U256; #[bench] fn bench_stream_u64_value(b: &mut Bencher) { - b.iter( || { - //1029 - let mut stream = RlpStream::new(); - stream.append(&0x1023456789abcdefu64); - let _ = stream.out().unwrap(); - }); + b.iter(|| { + // u64 + let mut stream = RlpStream::new(); + stream.append(&0x1023456789abcdefu64); + let _ = stream.out().unwrap(); + }); } #[bench] fn bench_decode_u64_value(b: &mut Bencher) { - b.iter( || { - // 1029 - let data = vec![0x88, 0x10, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; - let rlp = Rlp::new(&data); - let _ = u64::decode(&rlp).unwrap(); - }); + b.iter(|| { + // u64 + let data = vec![0x88, 0x10, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; + let rlp = Rlp::new(&data); + let _ = u64::decode(&rlp).unwrap(); + }); } #[bench] fn bench_stream_u256_value(b: &mut Bencher) { - b.iter( || { - //u256 - let mut stream = RlpStream::new(); - stream.append(&U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap()); - let _ = stream.out().unwrap(); - }); + b.iter(|| { + // u256 + let mut stream = RlpStream::new(); + stream.append(&U256::from_str("8090a0b0c0d0e0f009102030405060770000000000000001000000000\ + 00012f0") + .unwrap()); + let _ = stream.out().unwrap(); + }); } #[bench] fn bench_decode_u256_value(b: &mut Bencher) { - b.iter( || { - // u256 - let data = 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]; - let rlp = Rlp::new(&data); - let _ = U256::decode(&rlp).unwrap(); - }); + b.iter(|| { + // u256 + let data = 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]; + let rlp = Rlp::new(&data); + let _ = U256::decode(&rlp).unwrap(); + }); } #[bench] fn bench_stream_nested_empty_lists(b: &mut Bencher) { - b.iter( || { - // [ [], [[]], [ [], [[]] ] ] - let mut stream = RlpStream::new_list(3); - stream.append_list(0); - stream.append_list(1).append_list(0); - stream.append_list(2).append_list(0).append_list(1).append_list(0); - let _ = stream.out().unwrap(); - }); + b.iter(|| { + // [ [], [[]], [ [], [[]] ] ] + let mut stream = RlpStream::new_list(3); + stream.append_list(0); + stream.append_list(1).append_list(0); + stream.append_list(2).append_list(0).append_list(1).append_list(0); + let _ = stream.out().unwrap(); + }); } #[bench] fn bench_decode_nested_empty_lists(b: &mut Bencher) { - b.iter( || { - // [ [], [[]], [ [], [[]] ] ] - let data = vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]; - let rlp = Rlp::new(&data); - let _v0: Vec = Decodable::decode(&rlp.at(0).unwrap()).unwrap(); - let _v1: Vec> = Decodable::decode(&rlp.at(1).unwrap()).unwrap(); - let nested_rlp = rlp.at(2).unwrap(); - let _v2a: Vec = Decodable::decode(&nested_rlp.at(0).unwrap()).unwrap(); - let _v2b: Vec> = Decodable::decode(&nested_rlp.at(1).unwrap()).unwrap(); - }); + b.iter(|| { + // [ [], [[]], [ [], [[]] ] ] + let data = vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]; + let rlp = Rlp::new(&data); + let _v0: Vec = Decodable::decode(&rlp.at(0).unwrap()).unwrap(); + let _v1: Vec> = Decodable::decode(&rlp.at(1).unwrap()).unwrap(); + let nested_rlp = rlp.at(2).unwrap(); + let _v2a: Vec = Decodable::decode(&nested_rlp.at(0).unwrap()).unwrap(); + let _v2b: Vec> = Decodable::decode(&nested_rlp.at(1).unwrap()).unwrap(); + }); } #[bench] fn bench_stream_1000_empty_lists(b: &mut Bencher) { - b.iter( || { - let mut stream = RlpStream::new_list(1000); - for _ in 0..1000 { - stream.append_list(0); - } - let _ = stream.out().unwrap(); - }); + b.iter(|| { + let mut stream = RlpStream::new_list(1000); + for _ in 0..1000 { + stream.append_list(0); + } + let _ = stream.out().unwrap(); + }); } diff --git a/src/rlp.rs b/src/rlp.rs index ee74c3a33..8fbe8cf8f 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -7,38 +7,75 @@ //! //! ```rust //! extern crate ethcore_util; -//! use ethcore_util::rlp::{RlpStream}; +//! use ethcore_util::rlp::{Rlp, RlpStream, Decodable}; //! //! fn encode_value() { -//! // 1029 -//! let mut stream = RlpStream::new(); -//! stream.append(&1029u32); -//! let out = stream.out().unwrap(); -//! assert_eq!(out, vec![0x82, 0x04, 0x05]); +//! // 1029 +//! let mut stream = RlpStream::new(); +//! stream.append(&1029u32); +//! let out = stream.out().unwrap(); +//! assert_eq!(out, vec![0x82, 0x04, 0x05]); //! } //! //! fn encode_list() { -//! // [ "cat", "dog" ] -//! let mut stream = RlpStream::new_list(2); -//! stream.append(&"cat").append(&"dog"); -//! let out = stream.out().unwrap(); -//! assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); +//! // [ "cat", "dog" ] +//! let mut stream = RlpStream::new_list(2); +//! stream.append(&"cat").append(&"dog"); +//! let out = stream.out().unwrap(); +//! assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); //! } //! //! fn encode_list2() { -//! // [ [], [[]], [ [], [[]] ] ] -//! let mut stream = RlpStream::new_list(3); -//! stream.append_list(0); -//! stream.append_list(1).append_list(0); -//! stream.append_list(2).append_list(0).append_list(1).append_list(0); -//! let out = stream.out().unwrap(); -//! assert_eq!(out, vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]); +//! // [ [], [[]], [ [], [[]] ] ] +//! let mut stream = RlpStream::new_list(3); +//! stream.append_list(0); +//! stream.append_list(1).append_list(0); +//! stream.append_list(2).append_list(0).append_list(1).append_list(0); +//! let out = stream.out().unwrap(); +//! assert_eq!(out, vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]); +//! } +//! +//! fn decode_value() { +//! // 0x102456789abcdef +//! let data = vec![0x88, 0x10, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; +//! let rlp = Rlp::new(&data); +//! let _ = u64::decode(&rlp).unwrap(); +//! } +//! +//! fn decode_string() { +//! // "cat" +//! let data = vec![0x83, b'c', b'a', b't']; +//! let rlp = Rlp::new(&data); +//! let _ = String::decode(&rlp).unwrap(); +//! } +//! +//! fn decode_list() { +//! // ["cat", "dog"] +//! let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; +//! let rlp = Rlp::new(&data); +//! let _ : Vec = Decodable::decode(&rlp).unwrap(); +//! } +//! +//! fn decode_list2() { +//! // [ [], [[]], [ [], [[]] ] ] +//! let data = vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]; +//! let rlp = Rlp::new(&data); +//! let _v0: Vec = Decodable::decode(&rlp.at(0).unwrap()).unwrap(); +//! let _v1: Vec> = Decodable::decode(&rlp.at(1).unwrap()).unwrap(); +//! let nested_rlp = rlp.at(2).unwrap(); +//! let _v2a: Vec = Decodable::decode(&nested_rlp.at(0).unwrap()).unwrap(); +//! let _v2b: Vec> = Decodable::decode(&nested_rlp.at(1).unwrap()).unwrap(); //! } //! //! fn main() { -//! encode_value(); -//! encode_list(); -//! encode_list2(); +//! encode_value(); +//! encode_list(); +//! encode_list2(); +//! +//! decode_value(); +//! decode_string(); +//! decode_list(); +//! decode_list2(); //! } //! ``` //! From 90c66a8079b553cfd5cbff58e5263eee431087ea Mon Sep 17 00:00:00 2001 From: debris Date: Sat, 28 Nov 2015 11:25:00 +0100 Subject: [PATCH 5/5] rlp encoding and decoding of fixed sized hashes --- src/bytes.rs | 39 ++++++++++++++++++++++++++++++++++++++- src/hash.rs | 5 +++++ src/rlp.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 69 insertions(+), 1 deletion(-) diff --git a/src/bytes.rs b/src/bytes.rs index 0f82748a1..c08c4ee2a 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -35,8 +35,10 @@ //! ``` use std::fmt; +use std::cmp::Ordering; use std::error::Error as StdError; use uint::{U128, U256}; +use hash::FixedHash; /// Vector of bytes pub type Bytes = Vec; @@ -173,10 +175,26 @@ macro_rules! impl_uint_to_bytes { impl_uint_to_bytes!(U256); impl_uint_to_bytes!(U128); +impl ToBytes for T where T: FixedHash { + fn to_bytes(&self) -> Vec { + let mut res: Vec = vec![]; + res.reserve(T::size()); + + unsafe { + use std::ptr; + ptr::copy(self.bytes().as_ptr(), res.as_mut_ptr(), T::size()); + res.set_len(T::size()); + } + + res + } +} + /// Error returned when FromBytes conversation goes wrong #[derive(Debug, PartialEq, Eq)] pub enum FromBytesError { - UnexpectedEnd + DataIsTooShort, + DataIsTooLong } impl StdError for FromBytesError { @@ -256,3 +274,22 @@ macro_rules! impl_uint_from_bytes { impl_uint_from_bytes!(U256); impl_uint_from_bytes!(U128); + +impl FromBytes for T where T: FixedHash { + fn from_bytes(bytes: &[u8]) -> FromBytesResult { + match bytes.len().cmp(&T::size()) { + Ordering::Less => return Err(FromBytesError::DataIsTooShort), + Ordering::Greater => return Err(FromBytesError::DataIsTooLong), + Ordering::Equal => () + }; + + unsafe { + use std::{mem, ptr}; + + let mut res: T = mem::uninitialized(); + ptr::copy(bytes.as_ptr(), res.mut_bytes().as_mut_ptr(), T::size()); + + Ok(res) + } + } +} diff --git a/src/hash.rs b/src/hash.rs index 0dfd4f487..a0493f2bb 100644 --- a/src/hash.rs +++ b/src/hash.rs @@ -14,6 +14,7 @@ pub trait FixedHash: Sized + BytesConvertable { fn new() -> Self; fn random() -> Self; fn randomize(&mut self); + fn size() -> usize; fn mut_bytes(&mut self) -> &mut [u8]; fn shift_bloom<'a, T>(&'a mut self, b: &T) -> &'a mut Self where T: FixedHash; fn bloom_part(&self, m: usize) -> T where T: FixedHash; @@ -47,6 +48,10 @@ macro_rules! impl_hash { rng.fill_bytes(&mut self.0); } + fn size() -> usize { + $size + } + fn mut_bytes(&mut self) -> &mut [u8] { &mut self.0 } diff --git a/src/rlp.rs b/src/rlp.rs index 8fbe8cf8f..4b6df2c6e 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -748,6 +748,19 @@ mod tests { run_encode_tests(tests); } + #[test] + fn encode_address() { + use hash::*; + + 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]) + ]; + run_encode_tests(tests); + } + #[test] fn encode_vector_u8() { let tests = vec![ @@ -891,6 +904,19 @@ mod tests { run_decode_tests(tests); } + #[test] + fn decode_address() { + use hash::*; + + 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]) + ]; + run_decode_tests(tests); + } + #[test] fn decode_vector_u8() { let tests = vec![