From 4fcf044eddde2382ba18ceeac21076cdb37cecb9 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 15:00:17 +0100 Subject: [PATCH 1/2] rlp encoding and decoding u256 --- src/bytes.rs | 35 +++++++++++++++++++++++++++++++++++ src/rlp.rs | 32 ++++++++++++++++++++++++++++++++ src/uint.rs | 18 ++++++++++++++++++ 3 files changed, 85 insertions(+) diff --git a/src/bytes.rs b/src/bytes.rs index 06735995f..52dad3cb9 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -8,6 +8,7 @@ use std::fmt; use std::error::Error as StdError; +use uint::{U128, U256}; /// TODO: optimise some conversations pub trait ToBytes { @@ -82,6 +83,26 @@ impl_map_to_bytes!(usize, u64); impl_map_to_bytes!(u16, u64); impl_map_to_bytes!(u32, u64); +macro_rules! impl_uint_to_bytes { + ($name: ident) => { + impl ToBytes for $name { + fn to_bytes(&self) -> Vec { + let mut res= vec![]; + let count = self.to_bytes_len(); + for i in 0..count { + let j = count - 1 - i; + res.push(self.byte(j)); + } + res + } + fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } + } + } +} + +impl_uint_to_bytes!(U256); +impl_uint_to_bytes!(U128); + #[derive(Debug, PartialEq, Eq)] pub enum FromBytesError { UnexpectedEnd @@ -101,6 +122,7 @@ pub type FromBytesResult = Result; /// implements "Sized", so the compiler can deducate the size /// of the return type +/// TODO: check size of bytes before conversation and return appropriate error pub trait FromBytes: Sized { fn from_bytes(bytes: &[u8]) -> FromBytesResult; } @@ -149,3 +171,16 @@ macro_rules! impl_map_from_bytes { impl_map_from_bytes!(usize, u64); impl_map_from_bytes!(u16, u64); impl_map_from_bytes!(u32, u64); + +macro_rules! impl_uint_from_bytes { + ($name: ident) => { + impl FromBytes for $name { + fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { + Ok($name::from(bytes)) + } + } + } +} + +impl_uint_from_bytes!(U256); +impl_uint_from_bytes!(U128); diff --git a/src/rlp.rs b/src/rlp.rs index cd83a8c7e..03a10348c 100644 --- a/src/rlp.rs +++ b/src/rlp.rs @@ -522,8 +522,10 @@ impl Encoder for BasicEncoder { #[cfg(test)] mod tests { use std::{fmt, cmp}; + use std::str::FromStr; use rlp; use rlp::{Rlp, RlpStream, Decodable}; + use uint::U256; #[test] fn rlp_at() { @@ -643,6 +645,21 @@ mod tests { run_encode_tests(tests); } + #[test] + fn encode_u256() { + let tests = vec![ + ETestPair(U256::from(0u64), vec![0x80u8]), + ETestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + ETestPair(U256::from(0xffffffffu64), vec![0x84, 0xff, 0xff, 0xff, 0xff]), + ETestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap(), + 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]) + ]; + run_encode_tests(tests); + } + #[test] fn encode_str() { let tests = vec![ @@ -769,6 +786,21 @@ mod tests { run_decode_tests(tests); } + #[test] + fn decode_u256() { + let tests = vec![ + DTestPair(U256::from(0u64), vec![0x80u8]), + DTestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + DTestPair(U256::from(0xffffffffu64), vec![0x84, 0xff, 0xff, 0xff, 0xff]), + DTestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").unwrap(), + 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]) + ]; + run_decode_tests(tests); + } + #[test] fn decode_str() { let tests = vec![ diff --git a/src/uint.rs b/src/uint.rs index 149ff5efb..daba98b63 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -180,6 +180,12 @@ macro_rules! construct_uint { arr[index / 64] & (1 << (index % 64)) != 0 } + #[inline] + pub fn byte(&self, index: usize) -> u8 { + let &$name(ref arr) = self; + (arr[index / 8] >> ((index % 8)) * 8) as u8 + } + /// Multiplication by u32 fn mul_u32(self, other: u32) -> $name { let $name(ref arr) = self; @@ -507,6 +513,7 @@ mod tests { #[test] pub fn uint256_bits_test() { + assert_eq!(U256::from(0u64).bits(), 0); assert_eq!(U256::from(255u64).bits(), 8); assert_eq!(U256::from(256u64).bits(), 9); assert_eq!(U256::from(300u64).bits(), 9); @@ -523,11 +530,22 @@ mod tests { assert_eq!(shl.bits(), 0); //// Bit set check + //// 01010 assert!(!U256::from(10u8).bit(0)); assert!(U256::from(10u8).bit(1)); assert!(!U256::from(10u8).bit(2)); assert!(U256::from(10u8).bit(3)); assert!(!U256::from(10u8).bit(4)); + + //// byte check + assert_eq!(U256::from(10u8).byte(0), 10); + assert_eq!(U256::from(0xffu64).byte(0), 0xff); + assert_eq!(U256::from(0xffu64).byte(1), 0); + assert_eq!(U256::from(0x01ffu64).byte(0), 0xff); + assert_eq!(U256::from(0x01ffu64).byte(1), 0x1); + assert_eq!(U256([0u64, 0xfc, 0, 0]).byte(8), 0xfc); + assert_eq!(U256([0u64, 0, 0, u64::max_value()]).byte(31), 0xff); + assert_eq!(U256([0u64, 0, 0, (u64::max_value() >> 8) + 1]).byte(31), 0x01); } #[test] From 21a5d5418bdb9b3b8cc60149a801d300bf08e2e5 Mon Sep 17 00:00:00 2001 From: debris Date: Thu, 26 Nov 2015 15:43:52 +0100 Subject: [PATCH 2/2] added benchmarks and few optimisations for rlp encoding --- benches/rlp.rs | 50 ++++++++++++++++++++++++++++++++++++++++++-------- src/bytes.rs | 2 ++ src/uint.rs | 1 - 3 files changed, 44 insertions(+), 9 deletions(-) diff --git a/benches/rlp.rs b/benches/rlp.rs index 10397db09..8c1fa8d58 100644 --- a/benches/rlp.rs +++ b/benches/rlp.rs @@ -10,19 +10,53 @@ extern crate test; extern crate ethcore_util; use test::Bencher; -use ethcore_util::rlp; +use std::str::FromStr; use ethcore_util::rlp::{RlpStream, Rlp, Decodable}; +use ethcore_util::uint::U256; #[bench] -fn bench_stream_value(b: &mut Bencher) { +fn bench_stream_u64_value(b: &mut Bencher) { b.iter( || { //1029 let mut stream = RlpStream::new(); - stream.append(&1029u32); + stream.append(&1029u64); let _ = stream.out().unwrap(); }); } +#[bench] +fn bench_decode_u64_value(b: &mut Bencher) { + b.iter( || { + // 1029 + let data = vec![0x82, 0x04, 0x05]; + 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(); + }); +} + +#[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(); + }); +} + #[bench] fn bench_stream_nested_empty_lists(b: &mut Bencher) { b.iter( || { @@ -41,17 +75,17 @@ fn bench_decode_nested_empty_lists(b: &mut Bencher) { // [ [], [[]], [ [], [[]] ] ] 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 v2a: Vec = Decodable::decode(&rlp.at(2).unwrap().at(0).unwrap()).unwrap(); - let v2b: Vec> = Decodable::decode(&rlp.at(2).unwrap().at(1).unwrap()).unwrap(); + let _v0: Vec = Decodable::decode(&rlp.at(0).unwrap()).unwrap(); + let _v1: Vec> = Decodable::decode(&rlp.at(1).unwrap()).unwrap(); + let _v2a: Vec = Decodable::decode(&rlp.at(2).unwrap().at(0).unwrap()).unwrap(); + let _v2b: Vec> = Decodable::decode(&rlp.at(2).unwrap().at(1).unwrap()).unwrap(); }); } #[bench] fn bench_stream_1000_empty_lists(b: &mut Bencher) { b.iter( || { - let mut stream = RlpStream::new(); + let mut stream = RlpStream::new_list(1000); for _ in 0..1000 { stream.append_list(0); } diff --git a/src/bytes.rs b/src/bytes.rs index 52dad3cb9..1b331cf15 100644 --- a/src/bytes.rs +++ b/src/bytes.rs @@ -60,6 +60,7 @@ impl ToBytes for u64 { fn to_bytes(&self) -> Vec { let mut res= vec![]; let count = self.to_bytes_len(); + res.reserve(count); for i in 0..count { let j = count - 1 - i; res.push((*self >> (j * 8)) as u8); @@ -89,6 +90,7 @@ macro_rules! impl_uint_to_bytes { fn to_bytes(&self) -> Vec { let mut res= vec![]; let count = self.to_bytes_len(); + res.reserve(count); for i in 0..count { let j = count - 1 - i; res.push(self.byte(j)); diff --git a/src/uint.rs b/src/uint.rs index daba98b63..bc333631b 100644 --- a/src/uint.rs +++ b/src/uint.rs @@ -233,7 +233,6 @@ macro_rules! construct_uint { type Err = FromHexError; fn from_str(value: &str) -> Result<$name, Self::Err> { - println!("{}", value); let bytes: &[u8] = &try!(value.from_hex()); Ok(From::from(bytes)) }