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

This commit is contained in:
Gav Wood 2015-11-28 19:04:31 +01:00
commit 5c57523dd9
7 changed files with 381 additions and 119 deletions

View File

@ -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<u8> = Decodable::decode(&rlp.at(0).unwrap()).unwrap();
let _v1: Vec<Vec<u8>> = Decodable::decode(&rlp.at(1).unwrap()).unwrap();
let nested_rlp = rlp.at(2).unwrap();
let _v2a: Vec<u8> = Decodable::decode(&nested_rlp.at(0).unwrap()).unwrap();
let _v2b: Vec<Vec<u8>> = 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<u8> = Decodable::decode(&rlp.at(0).unwrap()).unwrap();
let _v1: Vec<Vec<u8>> = Decodable::decode(&rlp.at(1).unwrap()).unwrap();
let nested_rlp = rlp.at(2).unwrap();
let _v2a: Vec<u8> = Decodable::decode(&nested_rlp.at(0).unwrap()).unwrap();
let _v2b: Vec<Vec<u8>> = 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();
});
}

View File

@ -1,7 +0,0 @@
use bytes::BytesConvertable;
// use hash::FixedHash;
pub trait Bloomable {
fn shift_bloom<T>(&mut self, bytes: &T) where T: BytesConvertable;
fn contains_bloom<T>(&self, bytes: &T) -> bool where T: BytesConvertable;
}

View File

@ -1,17 +1,49 @@
//! 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<u8> = "hello_world".to_bytes();
//! let b: Vec<u8> = 400u32.to_bytes();
//! let c: Vec<u8> = 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::cmp::Ordering;
use std::error::Error as StdError;
use uint::{U128, U256};
use hash::FixedHash;
/// Vector of bytes
pub type Bytes = Vec<u8>;
/// Slice of bytes to underlying memory
pub trait BytesConvertable {
fn bytes(&self) -> &[u8];
}
@ -46,6 +78,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<u8>;
@ -141,9 +175,26 @@ macro_rules! impl_uint_to_bytes {
impl_uint_to_bytes!(U256);
impl_uint_to_bytes!(U128);
impl <T>ToBytes for T where T: FixedHash {
fn to_bytes(&self) -> Vec<u8> {
let mut res: Vec<u8> = 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 {
@ -156,10 +207,11 @@ impl fmt::Display for FromBytesError {
}
}
/// Alias for the result of FromBytes trait
pub type FromBytesResult<T> = Result<T, FromBytesError>;
/// 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<Self>;
@ -222,3 +274,22 @@ macro_rules! impl_uint_from_bytes {
impl_uint_from_bytes!(U256);
impl_uint_from_bytes!(U128);
impl <T>FromBytes for T where T: FixedHash {
fn from_bytes(bytes: &[u8]) -> FromBytesResult<T> {
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)
}
}
}

View File

@ -1,31 +1,30 @@
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: BytesConvertable {
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<T>(&self, m: usize) -> T where T: FixedHash;
fn contains_bloom<T>(&self, b: &T) -> bool where T: FixedHash;
}
macro_rules! impl_hash {
($from: ident, $size: expr) => {
#[derive(Eq)]
pub struct $from (pub [u8; $size]);
impl $from {
fn new() -> $from {
$from([0; $size])
}
}
pub struct $from ([u8; $size]);
impl BytesConvertable for $from {
fn bytes(&self) -> &[u8] {
@ -34,6 +33,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();
@ -45,9 +48,68 @@ macro_rules! impl_hash {
rng.fill_bytes(&mut self.0);
}
fn size() -> usize {
$size
}
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($size);
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>());
}
self
}
fn bloom_part<T>(&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<T>(&self, b: &T) -> bool where T: FixedHash {
let bp: Self = b.bloom_part($size);
(&bp & self) == bp
}
}
impl FromStr for $from {
@ -120,6 +182,7 @@ macro_rules! impl_hash {
}
}
/// BitOr on references
impl<'a> BitOr for &'a $from {
type Output = $from;
@ -135,6 +198,7 @@ macro_rules! impl_hash {
}
}
/// Moving BitOr
impl BitOr for $from {
type Output = $from;
@ -143,6 +207,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
}
}
}
}
@ -155,26 +244,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);
}

View File

@ -1,3 +1,7 @@
//! Ethcore-util library
//!
//! TODO: check reexports
extern crate rustc_serialize;
extern crate mio;
extern crate rand;
@ -18,9 +22,11 @@ pub mod hashdb;
pub mod memorydb;
pub mod overlaydb;
pub mod bloom;
pub mod math;
//pub mod network;
// reexports
pub use std::str::FromStr;
pub use hash::*;
pub use sha3::*;

10
src/math.rs Normal file
View File

@ -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::<usize>() as u32 * 8 - n
}

View File

@ -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<String> = 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<u8> = Decodable::decode(&rlp.at(0).unwrap()).unwrap();
//! let _v1: Vec<Vec<u8>> = Decodable::decode(&rlp.at(1).unwrap()).unwrap();
//! let nested_rlp = rlp.at(2).unwrap();
//! let _v2a: Vec<u8> = Decodable::decode(&nested_rlp.at(0).unwrap()).unwrap();
//! let _v2b: Vec<Vec<u8>> = 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();
//! }
//! ```
//!
@ -711,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![
@ -854,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![