From 40314614f7063c94dd73eb41c0d3d698362a5f83 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 27 Jan 2016 12:14:57 +0100 Subject: [PATCH 1/9] RLP encoder refactoring --- util/Cargo.toml | 1 + util/src/bytes.rs | 96 ++++++++++++++--------- util/src/journaldb.rs | 4 +- util/src/lib.rs | 1 + util/src/network/host.rs | 9 +-- util/src/network/session.rs | 8 +- util/src/network/tests.rs | 1 + util/src/overlaydb.rs | 1 - util/src/rlp/mod.rs | 30 ++++++-- util/src/rlp/rlpstream.rs | 150 +++++++++++++++--------------------- util/src/rlp/rlptraits.rs | 55 ++++++++++--- util/src/rlp/tests.rs | 36 +++++---- util/src/trie/node.rs | 6 +- util/src/trie/triedbmut.rs | 6 +- util/src/triehash.rs | 8 +- 15 files changed, 234 insertions(+), 178 deletions(-) diff --git a/util/Cargo.toml b/util/Cargo.toml index a91bff962..00f64948a 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -23,6 +23,7 @@ elastic-array = "0.4" heapsize = "0.2" itertools = "0.4" crossbeam = "0.2" +smallvec = "0.1" slab = { git = "https://github.com/arkpar/slab.git" } sha3 = { path = "sha3" } clippy = "*" # Always newest, since we use nightly diff --git a/util/src/bytes.rs b/util/src/bytes.rs index a30581a1f..3f637abaf 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -42,8 +42,37 @@ use std::error::Error as StdError; use std::ops::{Deref, DerefMut}; use uint::{Uint, U128, U256}; use hash::FixedHash; +use elastic_array::*; -/// TODO [Gav Wood] Please document me +/// Vector like object +pub trait VecLike { + /// Add an element to the collection + fn push(&mut self, value: T); + + /// Add a slice to the collection + fn extend(&mut self, slice: &[T]); +} + + +macro_rules! impl_veclike_for_elastic_array { + ($from: ident) => { + impl VecLike for $from where T: Copy { + fn push(&mut self, value: T) { + $from::::push(self, value) + } + fn extend(&mut self, slice: &[T]) { + $from::::append_slice(self, slice) + + } + } + } +} + +impl_veclike_for_elastic_array!(ElasticArray16); +impl_veclike_for_elastic_array!(ElasticArray32); +impl_veclike_for_elastic_array!(ElasticArray1024); + +/// Slie pretty print helper pub struct PrettySlice<'a> (&'a [u8]); impl<'a> fmt::Debug for PrettySlice<'a> { @@ -170,49 +199,47 @@ fn bytes_convertable() { /// /// TODO: optimise some conversations pub trait ToBytes { - /// TODO [Gav Wood] Please document me - fn to_bytes(&self) -> Vec; - /// TODO [Gav Wood] Please document me - fn to_bytes_len(&self) -> usize { self.to_bytes().len() } - /// TODO [debris] Please document me - fn first_byte(&self) -> Option { self.to_bytes().first().map(|&x| { x })} + /// Serialize self to byte array + fn to_bytes>(&self, out: &mut V); + /// Get length of serialized data in bytes + fn to_bytes_len(&self) -> usize; } impl <'a> ToBytes for &'a str { - fn to_bytes(&self) -> Vec { - From::from(*self) + fn to_bytes>(&self, out: &mut V) { + out.extend(self.as_bytes()); } - fn to_bytes_len(&self) -> usize { self.len() } + fn to_bytes_len(&self) -> usize { + self.as_bytes().len() + } } impl ToBytes for String { - fn to_bytes(&self) -> Vec { - let s: &str = self.as_ref(); - From::from(s) + fn to_bytes>(&self, out: &mut V) { + out.extend(self.as_bytes()); } - fn to_bytes_len(&self) -> usize { self.len() } + fn to_bytes_len(&self) -> usize { + self.len() + } } impl ToBytes for u64 { - fn to_bytes(&self) -> Vec { - let mut res= vec![]; + fn to_bytes>(&self, out: &mut V) { 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); + out.push((*self >> (j * 8)) as u8); } - res } fn to_bytes_len(&self) -> usize { 8 - self.leading_zeros() as usize / 8 } } impl ToBytes for bool { - fn to_bytes(&self) -> Vec { - vec![ if *self { 1u8 } else { 0u8 } ] + fn to_bytes>(&self, out: &mut V) { + out.push(if *self { 1u8 } else { 0u8 }) } fn to_bytes_len(&self) -> usize { 1 } @@ -221,28 +248,29 @@ impl ToBytes for bool { macro_rules! impl_map_to_bytes { ($from: ident, $to: ty) => { impl ToBytes for $from { - fn to_bytes(&self) -> Vec { (*self as $to).to_bytes() } + fn to_bytes>(&self, out: &mut V) { + (*self as $to).to_bytes(out) + } + fn to_bytes_len(&self) -> usize { (*self as $to).to_bytes_len() } } } } impl_map_to_bytes!(usize, u64); +impl_map_to_bytes!(u8, 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![]; + fn to_bytes>(&self, out: &mut V) { let count = self.to_bytes_len(); - res.reserve(count); for i in 0..count { let j = count - 1 - i; - res.push(self.byte(j)); + out.push(self.byte(j)); } - res } fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } } @@ -253,18 +281,10 @@ 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 + fn to_bytes>(&self, out: &mut V) { + out.extend(self.bytes()); } + fn to_bytes_len(&self) -> usize { self.bytes().len() } } /// Error returned when FromBytes conversation goes wrong diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index ba31efafb..6c904ca5f 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -86,8 +86,8 @@ impl JournalDB { let mut r = RlpStream::new_list(3); r.append(id); - r.append(&self.inserts); - r.append(&self.removes); + r.append_list(&self.inserts); + r.append_list(&self.removes); try!(self.backing.put(&last, r.as_raw())); self.inserts.clear(); self.removes.clear(); diff --git a/util/src/lib.rs b/util/src/lib.rs index 970c0713c..09f92429a 100644 --- a/util/src/lib.rs +++ b/util/src/lib.rs @@ -55,6 +55,7 @@ extern crate secp256k1; extern crate arrayvec; extern crate elastic_array; extern crate crossbeam; +extern crate smallvec; /// TODO [Gav Wood] Please document me pub mod standard; diff --git a/util/src/network/host.rs b/util/src/network/host.rs index 6f306ecb0..95b1e3668 100644 --- a/util/src/network/host.rs +++ b/util/src/network/host.rs @@ -124,11 +124,10 @@ pub struct CapabilityInfo { } impl Encodable for CapabilityInfo { - fn encode(&self, encoder: &mut E) -> () where E: Encoder { - encoder.emit_list(|e| { - self.protocol.encode(e); - (self.version as u32).encode(e); - }); + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(2); + s.append(&self.protocol); + s.append(&self.version); } } diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 2817f008d..380da3e9b 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -199,10 +199,10 @@ impl Session { fn write_hello(&mut self, host: &HostInfo) -> Result<(), UtilError> { let mut rlp = RlpStream::new(); rlp.append_raw(&[PACKET_HELLO as u8], 0); - rlp.append_list(5) + rlp.begin_list(5) .append(&host.protocol_version) .append(&host.client_version) - .append(&host.capabilities) + .append_list(&host.capabilities) .append(&host.listen_port) .append(host.id()); self.connection.send_packet(&rlp.out()) @@ -267,7 +267,7 @@ impl Session { fn disconnect(&mut self, reason: DisconnectReason) -> NetworkError { let mut rlp = RlpStream::new(); rlp.append(&(PACKET_DISCONNECT as u32)); - rlp.append_list(1); + rlp.begin_list(1); rlp.append(&(reason.clone() as u32)); self.connection.send_packet(&rlp.out()).ok(); NetworkError::Disconnect(reason) @@ -276,7 +276,7 @@ impl Session { fn prepare(packet_id: u8) -> Result { let mut rlp = RlpStream::new(); rlp.append(&(packet_id as u32)); - rlp.append_list(0); + rlp.begin_list(0); Ok(rlp) } diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index 06966abb5..0dd1aed12 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -75,6 +75,7 @@ fn test_net_service() { #[test] fn test_net_connect() { + ::env_logger::init().ok(); let key1 = KeyPair::create().unwrap(); let mut config1 = NetworkConfiguration::new_with_port(30344); config1.use_secret = Some(key1.secret().clone()); diff --git a/util/src/overlaydb.rs b/util/src/overlaydb.rs index d2f56a520..7ef0c3309 100644 --- a/util/src/overlaydb.rs +++ b/util/src/overlaydb.rs @@ -143,7 +143,6 @@ impl OverlayDB { self.backing.delete(&key.bytes()).expect("Low-level database error. Some issue with your hard disk?"); true } - } } diff --git a/util/src/rlp/mod.rs b/util/src/rlp/mod.rs index f6acdf180..8b7814e5a 100644 --- a/util/src/rlp/mod.rs +++ b/util/src/rlp/mod.rs @@ -30,6 +30,7 @@ //! * You want to get view onto rlp-slice. //! * You don't want to decode whole rlp at once. +use std::ops::Deref; /// TODO [Gav Wood] Please document me pub mod rlptraits; /// TODO [Gav Wood] Please document me @@ -48,7 +49,8 @@ pub use self::rlperrors::DecoderError; pub use self::rlptraits::{Decoder, Decodable, View, Stream, Encodable, Encoder}; pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype}; pub use self::rlpin::{Rlp, RlpIterator}; -pub use self::rlpstream::{RlpStream,RlpStandard}; +pub use self::rlpstream::{RlpStream}; +pub use elastic_array::ElasticArray1024; use super::hash::H256; /// TODO [arkpar] Please document me @@ -84,13 +86,31 @@ pub fn decode(bytes: &[u8]) -> T where T: Decodable { /// use util::rlp::*; /// /// fn main () { +/// let animal = "cat"; +/// let out = encode(&animal); +/// assert_eq!(out, vec![0x83, b'c', b'a', b't']); +/// } +/// ``` +pub fn encode(object: &E) -> ElasticArray1024 where E: Encodable { + let mut stream = RlpStream::new(); + stream.append(object); + stream.drain() +} + +/// Shortcut function to encode a list to rlp. +/// +/// ```rust +/// extern crate ethcore_util as util; +/// use util::rlp::*; +/// +/// fn main () { /// let animals = vec!["cat", "dog"]; -/// let out = encode(&animals); +/// let out = encode_list(&animals); /// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); /// } /// ``` -pub fn encode(object: &E) -> Vec where E: Encodable { +pub fn encode_list(list: &I) -> ElasticArray1024 where I: Deref, E: Encodable { let mut stream = RlpStream::new(); - stream.append(object); - stream.out() + stream.append_list(list); + stream.drain() } diff --git a/util/src/rlp/rlpstream.rs b/util/src/rlp/rlpstream.rs index ac22736fc..b5e9d2152 100644 --- a/util/src/rlp/rlpstream.rs +++ b/util/src/rlp/rlpstream.rs @@ -1,8 +1,8 @@ +use std::ops::Deref; use elastic_array::*; -use bytes::{Bytes, ToBytes}; +use bytes::{ToBytes, VecLike}; use rlp::{Stream, Encoder, Encodable}; -use hash::H256; -use sha3::*; +use rlp::rlptraits::ByteEncodable; #[derive(Debug, Copy, Clone)] struct ListInfo { @@ -37,22 +37,18 @@ impl Stream for RlpStream { fn new_list(len: usize) -> Self { let mut stream = RlpStream::new(); - stream.append_list(len); + stream.begin_list(len); stream } - fn append(&mut self, object: &E) -> &mut RlpStream where E: Encodable { - // encode given value and add it at the end of the stream - object.encode(&mut self.encoder); - + fn append<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable { + value.rlp_append(self); // if list is finished, prepend the length self.note_appended(1); - - // return chainable self self } - fn append_list(&mut self, len: usize) -> &mut RlpStream { + fn begin_list(&mut self, len: usize) -> &mut RlpStream { match len { 0 => { // we may finish, if the appended list len is equal 0 @@ -69,6 +65,15 @@ impl Stream for RlpStream { self } + fn append_list(&mut self, list: &I) -> &mut Self where I: Deref, E: Encodable { + let items = list.deref(); + self.begin_list(items.len()); + for el in items.iter() { + self.append(el); + } + self + } + fn append_empty_data(&mut self) -> &mut RlpStream { // self push raw item self.encoder.bytes.push(0x80); @@ -117,6 +122,12 @@ impl Stream for RlpStream { impl RlpStream { + /// Appends primitive value to the end of stream + fn append_value(&mut self, object: &E) where E: ByteEncodable { + // encode given value and add it at the end of the stream + self.encoder.emit_value(object); + } + /// Try to finish lists fn note_appended(&mut self, inserted_items: usize) -> () { if self.unfinished_lists.len() == 0 { @@ -164,12 +175,12 @@ impl BasicEncoder { /// inserts list prefix at given position /// TODO: optimise it further? fn insert_list_len_at_pos(&mut self, len: usize, pos: usize) -> () { - let mut res = vec![]; + let mut res = ElasticArray16::new(); match len { 0...55 => res.push(0xc0u8 + len as u8), _ => { res.push(0xf7u8 + len.to_bytes_len() as u8); - res.extend(len.to_bytes()); + ToBytes::to_bytes(&len, &mut res); } }; @@ -183,22 +194,30 @@ impl BasicEncoder { } impl Encoder for BasicEncoder { - fn emit_value(&mut self, bytes: &[u8]) -> () { - match bytes.len() { + fn emit_value(&mut self, value: &E) { + match value.bytes_len() { // just 0 0 => self.bytes.push(0x80u8), - // byte is its own encoding - 1 if bytes[0] < 0x80 => self.bytes.append_slice(bytes), + // byte is its own encoding if < 0x80 + 1 => { + value.to_bytes(&mut self.bytes); + let len = self.bytes.len(); + let last_byte = self.bytes[len - 1]; + if last_byte >= 0x80 { + self.bytes.push(last_byte); + self.bytes[len - 1] = 0x81; + } + } // (prefix + length), followed by the string - len @ 1 ... 55 => { + len @ 2 ... 55 => { self.bytes.push(0x80u8 + len as u8); - self.bytes.append_slice(bytes); + value.to_bytes(&mut self.bytes); } // (prefix + length of length), followed by the length, followd by the string len => { self.bytes.push(0xb7 + len.to_bytes_len() as u8); - self.bytes.append_slice(&len.to_bytes()); - self.bytes.append_slice(bytes); + ToBytes::to_bytes(&len, &mut self.bytes); + value.to_bytes(&mut self.bytes); } } } @@ -206,86 +225,41 @@ impl Encoder for BasicEncoder { fn emit_raw(&mut self, bytes: &[u8]) -> () { self.bytes.append_slice(bytes); } +} - fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> () { - // get len before inserting a list - let before_len = self.bytes.len(); - // insert all list elements - f(self); +impl ByteEncodable for T where T: ToBytes { + fn to_bytes>(&self, out: &mut V) { + ToBytes::to_bytes(self, out) + } - // get len after inserting a list - let after_len = self.bytes.len(); - - // diff is list len - let list_len = after_len - before_len; - self.insert_list_len_at_pos(list_len, before_len); + fn bytes_len(&self) -> usize { + ToBytes::to_bytes_len(self) } } -/// TODO [Gav Wood] Please document me -pub trait RlpStandard { - /// TODO [Gav Wood] Please document me - fn rlp_append(&self, s: &mut RlpStream); - - /// TODO [Gav Wood] Please document me - fn rlp_bytes(&self) -> Bytes { - let mut s = RlpStream::new(); - self.rlp_append(&mut s); - s.out() +impl<'a> ByteEncodable for &'a[u8] { + fn to_bytes>(&self, out: &mut V) { + out.extend(self) } - /// TODO [Gav Wood] Please document me - fn rlp_sha3(&self) -> H256 { self.rlp_bytes().sha3() } -} - -// @debris TODO: implement Encoder for RlpStandard. - -impl Encodable for T where T: ToBytes { - fn encode(&self, encoder: &mut E) where E: Encoder { - encoder.emit_value(&self.to_bytes()) + fn bytes_len(&self) -> usize { + self.len() } } -impl<'a, T> Encodable for &'a [T] where T: Encodable + 'a { - fn encode(&self, encoder: &mut E) where E: Encoder { - encoder.emit_list(|e| { - // insert all list elements - for el in self.iter() { - el.encode(e); - } - }) +impl ByteEncodable for Vec { + fn to_bytes>(&self, out: &mut V) { + out.extend(self.deref()) + } + + fn bytes_len(&self) -> usize { + self.len() } } -impl Encodable for Vec where T: Encodable { - fn encode(&self, encoder: &mut E) where E: Encoder { - let r: &[T] = self.as_ref(); - r.encode(encoder) - } -} - -/// lets treat bytes differently than other lists -/// they are a single value -impl<'a> Encodable for &'a [u8] { - fn encode(&self, encoder: &mut E) where E: Encoder { - encoder.emit_value(self) - } -} - -/// lets treat bytes differently than other lists -/// they are a single value -impl Encodable for Vec { - fn encode(&self, encoder: &mut E) where E: Encoder { - encoder.emit_value(self) - } -} - -impl Encodable for Option where T: Encodable { - fn encode(&self, encoder: &mut E) where E: Encoder { - match *self { - Some(ref x) => x.encode(encoder), - None => encoder.emit_value(&[]) - } +impl Encodable for T where T: ByteEncodable { + fn rlp_append(&self, s: &mut RlpStream) { + s.append_value(self) } } diff --git a/util/src/rlp/rlptraits.rs b/util/src/rlp/rlptraits.rs index d6ef16932..aa964c26c 100644 --- a/util/src/rlp/rlptraits.rs +++ b/util/src/rlp/rlptraits.rs @@ -1,4 +1,10 @@ +use std::ops::Deref; +use bytes::VecLike; use rlp::{DecoderError, UntrustedRlp}; +use rlpstream::RlpStream; +use elastic_array::ElasticArray1024; +use hash::H256; +use sha3::*; /// TODO [debris] Please document me pub trait Decoder: Sized { @@ -204,17 +210,33 @@ pub trait View<'a, 'view>: Sized { /// TODO [debris] Please document me pub trait Encoder { /// TODO [debris] Please document me - fn emit_value(&mut self, bytes: &[u8]) -> (); - /// TODO [Gav Wood] Please document me - fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> (); + fn emit_value(&mut self, value: &E); /// TODO [debris] Please document me fn emit_raw(&mut self, bytes: &[u8]) -> (); } -/// TODO [debris] Please document me +/// Primitive data type encodable to RLP +pub trait ByteEncodable { + /// Serialize this object to given byte container + fn to_bytes>(&self, out: &mut V); + /// Get size of serialised data in bytes + fn bytes_len(&self) -> usize; +} + +/// Structure encodable to RLP pub trait Encodable { - /// TODO [debris] Please document me - fn encode(&self, encoder: &mut E) -> () where E: Encoder; + /// Append a value to the stream + fn rlp_append(&self, s: &mut RlpStream); + + /// Get rlp-encoded bytes for this instance + fn rlp_bytes(&self) -> ElasticArray1024 { + let mut s = RlpStream::new(); + self.rlp_append(&mut s); + s.drain() + } + + /// Get the hash or RLP encoded representation + fn rlp_sha3(&self) -> H256 { self.rlp_bytes().deref().sha3() } } /// TODO [debris] Please document me @@ -239,7 +261,7 @@ pub trait Stream: Sized { /// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); /// } /// ``` - fn append<'a, E>(&'a mut self, object: &E) -> &'a mut Self where E: Encodable; + fn append<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable; /// Declare appending the list of given size, chainable. /// @@ -249,13 +271,28 @@ pub trait Stream: Sized { /// /// fn main () { /// let mut stream = RlpStream::new_list(2); - /// stream.append_list(2).append(&"cat").append(&"dog"); + /// stream.begin_list(2).append(&"cat").append(&"dog"); /// stream.append(&""); /// let out = stream.out(); /// assert_eq!(out, vec![0xca, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g', 0x80]); /// } /// ``` - fn append_list(&mut self, len: usize) -> &mut Self; + fn begin_list(&mut self, len: usize) -> &mut Self; + + /// Append the given list, chainable. + /// + /// ```rust + /// extern crate ethcore_util as util; + /// use util::rlp::*; + /// + /// fn main () { + /// let mut stream = RlpStream::new_list(2); + /// stream.begin_list([&"cat", &"dog"]); + /// let out = stream.out(); + /// assert_eq!(out, vec![0xca, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g', 0x80]); + /// } + /// ``` + fn append_list(&mut self, list: &I) -> &mut Self where I: Deref, E: Encodable; /// Apends null to the end of stream, chainable. /// diff --git a/util/src/rlp/tests.rs b/util/src/rlp/tests.rs index f33cec177..df61ad127 100644 --- a/util/src/rlp/tests.rs +++ b/util/src/rlp/tests.rs @@ -77,13 +77,23 @@ fn rlp_iter() { } struct ETestPair(T, Vec) where T: rlp::Encodable; +struct ETestVecPair(Vec, Vec) where T: rlp::Encodable; fn run_encode_tests(tests: Vec>) where T: rlp::Encodable { for t in &tests { let res = rlp::encode(&t.0); - assert_eq!(res, &t.1[..]); + assert_eq!(&res[..], &t.1[..]); + } +} + +fn run_encode_list_tests(tests: Vec>) + where T: rlp::Encodable +{ + for t in &tests { + let res = rlp::encode_list(&t.0); + assert_eq!(&res[..], &t.1[..]); } } @@ -178,25 +188,19 @@ fn encode_vector_u8() { #[test] fn encode_vector_u64() { let tests = vec![ - ETestPair(vec![], vec![0xc0]), - ETestPair(vec![15u64], vec![0xc1, 0x0f]), - ETestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), - ETestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), + ETestVecPair(vec![], vec![0xc0]), + ETestVecPair(vec![15u64], vec![0xc1, 0x0f]), + ETestVecPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), + ETestVecPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), ]; - run_encode_tests(tests); + run_encode_list_tests(tests); } #[test] fn encode_vector_str() { - let tests = vec![ETestPair(vec!["cat", "dog"], + let tests = vec![ETestVecPair(vec!["cat", "dog"], vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; - run_encode_tests(tests); -} - -#[test] -fn encode_vector_of_vectors_str() { - let tests = vec![ETestPair(vec![vec!["cat"]], vec![0xc5, 0xc4, 0x83, b'c', b'a', b't'])]; - run_encode_tests(tests); + run_encode_list_tests(tests); } struct DTestPair(T, Vec) where T: rlp::Decodable + fmt::Debug + cmp::Eq; @@ -333,7 +337,7 @@ fn test_rlp_json() { for operation in input.into_iter() { match operation { rlptest::Operation::Append(ref v) => stream.append(v), - rlptest::Operation::AppendList(len) => stream.append_list(len), + rlptest::Operation::AppendList(len) => stream.begin_list(len), rlptest::Operation::AppendRaw(ref raw, len) => stream.append_raw(raw, len), rlptest::Operation::AppendEmpty => stream.append_empty_data() }; @@ -346,7 +350,7 @@ fn test_rlp_json() { #[test] fn test_decoding_array() { let v = vec![5u16, 2u16]; - let res = rlp::encode(&v); + let res = rlp::encode_list(&v); let arr: [u16; 2] = rlp::decode(&res); assert_eq!(arr[0], 5); assert_eq!(arr[1], 2); diff --git a/util/src/trie/node.rs b/util/src/trie/node.rs index dad5830b2..c47a0d25f 100644 --- a/util/src/trie/node.rs +++ b/util/src/trie/node.rs @@ -89,17 +89,17 @@ impl<'a> Node<'a> { let mut stream = RlpStream::new(); match *self { Node::Leaf(ref slice, ref value) => { - stream.append_list(2); + stream.begin_list(2); stream.append(&slice.encoded(true)); stream.append(value); }, Node::Extension(ref slice, ref raw_rlp) => { - stream.append_list(2); + stream.begin_list(2); stream.append(&slice.encoded(false)); stream.append_raw(raw_rlp, 1); }, Node::Branch(ref nodes, ref value) => { - stream.append_list(17); + stream.begin_list(17); for i in 0..16 { stream.append_raw(nodes[i], 1); } diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index 48749bf0d..5baffee8e 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -684,11 +684,11 @@ mod tests { fn random_value_indexed(j: usize) -> Bytes { match random::() % 2 { - 0 => encode(&j), + 0 => encode(&j).to_vec(), _ => { let mut h = H256::new(); h.as_slice_mut()[31] = j as u8; - encode(&h) + encode(&h).to_vec() }, } } @@ -1035,7 +1035,7 @@ mod tests { let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_"; for j in 0..4u32 { let key = random_key(alphabet, 5, 1); - x.push((key, encode(&j))); + x.push((key, encode(&j).to_vec())); } let real = trie_root(x.clone()); let mut memdb = MemoryDB::new(); diff --git a/util/src/triehash.rs b/util/src/triehash.rs index 66f9072b8..6ff6b790d 100644 --- a/util/src/triehash.rs +++ b/util/src/triehash.rs @@ -30,7 +30,7 @@ pub fn ordered_trie_root(input: Vec>) -> H256 { // optimize it later .into_iter() .enumerate() - .fold(BTreeMap::new(), | mut acc, (i, vec) | { acc.insert(rlp::encode(&i), vec); acc }) + .fold(BTreeMap::new(), | mut acc, (i, vec) | { acc.insert(rlp::encode(&i).to_vec(), vec); acc }) // then move them to a vector .into_iter() .map(|(k, v)| (as_nibbles(&k), v) ) @@ -189,7 +189,7 @@ fn hash256rlp(input: &[(Vec, Vec)], pre_len: usize, stream: &mut RlpStre // if the slice contains just one item, append the suffix of the key // and then append value if inlen == 1 { - stream.append_list(2); + stream.begin_list(2); stream.append(&hex_prefix_encode(&key[pre_len..], true)); stream.append(&value); return; @@ -208,7 +208,7 @@ fn hash256rlp(input: &[(Vec, Vec)], pre_len: usize, stream: &mut RlpStre // new part of the key to the stream // then recursively append suffixes of all items who had this key if shared_prefix > pre_len { - stream.append_list(2); + stream.begin_list(2); stream.append(&hex_prefix_encode(&key[pre_len..shared_prefix], false)); hash256aux(input, shared_prefix, stream); return; @@ -216,7 +216,7 @@ fn hash256rlp(input: &[(Vec, Vec)], pre_len: usize, stream: &mut RlpStre // an item for every possible nibble/suffix // + 1 for data - stream.append_list(17); + stream.begin_list(17); // if first key len is equal to prefix_len, move to next element let mut begin = match pre_len == key.len() { From 60e2b53a1ddbb6f13cb9ecaeb628f615e7fe8c3d Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 27 Jan 2016 16:58:22 +0100 Subject: [PATCH 2/9] Fixed tests --- util/src/bytes.rs | 36 +++++++++++++++++++++++------------- util/src/rlp/mod.rs | 4 ++-- util/src/rlp/rlpstream.rs | 7 ++++--- util/src/rlp/rlptraits.rs | 8 ++++---- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 3f637abaf..6db5a8cf2 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -14,9 +14,10 @@ //! 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(); +//! let mut out: Vec = Vec::new(); +//! "hello_world".to_bytes(&mut out); +//! 400u32.to_bytes(&mut out); +//! 0xffffffffffffffffu64.to_bytes(&mut out); //! } //! //! fn from_bytes() { @@ -47,20 +48,29 @@ use elastic_array::*; /// Vector like object pub trait VecLike { /// Add an element to the collection - fn push(&mut self, value: T); + fn vec_push(&mut self, value: T); /// Add a slice to the collection - fn extend(&mut self, slice: &[T]); + fn vec_extend(&mut self, slice: &[T]); } +impl VecLike for Vec where T: Copy { + fn vec_push(&mut self, value: T) { + Vec::::push(self, value) + } + + fn vec_extend(&mut self, slice: &[T]) { + Vec::::extend_from_slice(self, slice) + } +} macro_rules! impl_veclike_for_elastic_array { ($from: ident) => { impl VecLike for $from where T: Copy { - fn push(&mut self, value: T) { + fn vec_push(&mut self, value: T) { $from::::push(self, value) } - fn extend(&mut self, slice: &[T]) { + fn vec_extend(&mut self, slice: &[T]) { $from::::append_slice(self, slice) } @@ -207,7 +217,7 @@ pub trait ToBytes { impl <'a> ToBytes for &'a str { fn to_bytes>(&self, out: &mut V) { - out.extend(self.as_bytes()); + out.vec_extend(self.as_bytes()); } fn to_bytes_len(&self) -> usize { @@ -217,7 +227,7 @@ impl <'a> ToBytes for &'a str { impl ToBytes for String { fn to_bytes>(&self, out: &mut V) { - out.extend(self.as_bytes()); + out.vec_extend(self.as_bytes()); } fn to_bytes_len(&self) -> usize { @@ -230,7 +240,7 @@ impl ToBytes for u64 { let count = self.to_bytes_len(); for i in 0..count { let j = count - 1 - i; - out.push((*self >> (j * 8)) as u8); + out.vec_push((*self >> (j * 8)) as u8); } } @@ -239,7 +249,7 @@ impl ToBytes for u64 { impl ToBytes for bool { fn to_bytes>(&self, out: &mut V) { - out.push(if *self { 1u8 } else { 0u8 }) + out.vec_push(if *self { 1u8 } else { 0u8 }) } fn to_bytes_len(&self) -> usize { 1 } @@ -269,7 +279,7 @@ macro_rules! impl_uint_to_bytes { let count = self.to_bytes_len(); for i in 0..count { let j = count - 1 - i; - out.push(self.byte(j)); + out.vec_push(self.byte(j)); } } fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } @@ -282,7 +292,7 @@ impl_uint_to_bytes!(U128); impl ToBytes for T where T: FixedHash { fn to_bytes>(&self, out: &mut V) { - out.extend(self.bytes()); + out.vec_extend(self.bytes()); } fn to_bytes_len(&self) -> usize { self.bytes().len() } } diff --git a/util/src/rlp/mod.rs b/util/src/rlp/mod.rs index 8b7814e5a..8dddf3acc 100644 --- a/util/src/rlp/mod.rs +++ b/util/src/rlp/mod.rs @@ -87,7 +87,7 @@ pub fn decode(bytes: &[u8]) -> T where T: Decodable { /// /// fn main () { /// let animal = "cat"; -/// let out = encode(&animal); +/// let out = encode(&animal).to_vec(); /// assert_eq!(out, vec![0x83, b'c', b'a', b't']); /// } /// ``` @@ -105,7 +105,7 @@ pub fn encode(object: &E) -> ElasticArray1024 where E: Encodable { /// /// fn main () { /// let animals = vec!["cat", "dog"]; -/// let out = encode_list(&animals); +/// let out = encode_list(&animals).to_vec(); /// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); /// } /// ``` diff --git a/util/src/rlp/rlpstream.rs b/util/src/rlp/rlpstream.rs index b5e9d2152..7a0223d23 100644 --- a/util/src/rlp/rlpstream.rs +++ b/util/src/rlp/rlpstream.rs @@ -69,8 +69,9 @@ impl Stream for RlpStream { let items = list.deref(); self.begin_list(items.len()); for el in items.iter() { - self.append(el); + el.rlp_append(self); } + self.note_appended(items.len()); self } @@ -240,7 +241,7 @@ impl ByteEncodable for T where T: ToBytes { impl<'a> ByteEncodable for &'a[u8] { fn to_bytes>(&self, out: &mut V) { - out.extend(self) + out.vec_extend(self) } fn bytes_len(&self) -> usize { @@ -250,7 +251,7 @@ impl<'a> ByteEncodable for &'a[u8] { impl ByteEncodable for Vec { fn to_bytes>(&self, out: &mut V) { - out.extend(self.deref()) + out.vec_extend(self.deref()) } fn bytes_len(&self) -> usize { diff --git a/util/src/rlp/rlptraits.rs b/util/src/rlp/rlptraits.rs index aa964c26c..437d86dc6 100644 --- a/util/src/rlp/rlptraits.rs +++ b/util/src/rlp/rlptraits.rs @@ -286,10 +286,10 @@ pub trait Stream: Sized { /// use util::rlp::*; /// /// fn main () { - /// let mut stream = RlpStream::new_list(2); - /// stream.begin_list([&"cat", &"dog"]); - /// let out = stream.out(); - /// assert_eq!(out, vec![0xca, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g', 0x80]); + /// let mut stream = RlpStream::new_list(1); + /// stream.append_list(&vec!["cat", "dog"]); + /// let out = stream.out().to_vec(); + /// assert_eq!(out, vec![0xc9, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); /// } /// ``` fn append_list(&mut self, list: &I) -> &mut Self where I: Deref, E: Encodable; From 6e33c2494b50d889a39b9bacc8b1fb9c077cebd5 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 27 Jan 2016 17:22:01 +0100 Subject: [PATCH 3/9] New RLP decoding interface used --- src/block.rs | 6 +++--- src/ethereum/ethash.rs | 2 +- src/extras.rs | 30 ++++++++++++++---------------- src/header.rs | 24 +++--------------------- src/log_entry.rs | 6 +++--- src/pod_account.rs | 2 +- src/receipt.rs | 11 +++-------- src/spec.rs | 10 +++++----- src/transaction.rs | 4 ++-- src/verification.rs | 11 ++++------- 10 files changed, 39 insertions(+), 67 deletions(-) diff --git a/src/block.rs b/src/block.rs index 1ff326430..6e12b663d 100644 --- a/src/block.rs +++ b/src/block.rs @@ -200,11 +200,11 @@ impl<'x, 'y> OpenBlock<'x, 'y> { pub fn close(self) -> ClosedBlock<'x, 'y> { let mut s = self; s.engine.on_close_block(&mut s.block); - s.block.header.transactions_root = ordered_trie_root(s.block.archive.iter().map(|ref e| e.transaction.rlp_bytes()).collect()); + s.block.header.transactions_root = ordered_trie_root(s.block.archive.iter().map(|ref e| e.transaction.rlp_bytes().to_vec()).collect()); let uncle_bytes = s.block.uncles.iter().fold(RlpStream::new_list(s.block.uncles.len()), |mut s, u| {s.append(&u.rlp(Seal::With)); s} ).out(); s.block.header.uncles_hash = uncle_bytes.sha3(); s.block.header.state_root = s.block.state.root().clone(); - s.block.header.receipts_root = ordered_trie_root(s.block.archive.iter().map(|ref e| e.receipt.rlp_bytes()).collect()); + s.block.header.receipts_root = ordered_trie_root(s.block.archive.iter().map(|ref e| e.receipt.rlp_bytes().to_vec()).collect()); s.block.header.log_bloom = s.block.archive.iter().fold(LogBloom::zero(), |mut b, e| {b |= &e.receipt.log_bloom; b}); s.block.header.gas_used = s.block.archive.last().map_or(U256::zero(), |t| t.receipt.gas_used); s.block.header.note_dirty(); @@ -256,7 +256,7 @@ impl SealedBlock { pub fn rlp_bytes(&self) -> Bytes { let mut block_rlp = RlpStream::new_list(3); self.block.header.stream_rlp(&mut block_rlp, Seal::With); - block_rlp.append_list(self.block.archive.len()); + block_rlp.begin_list(self.block.archive.len()); for e in &self.block.archive { e.transaction.rlp_append(&mut block_rlp); } block_rlp.append_raw(&self.uncle_bytes, 1); block_rlp.out() diff --git a/src/ethereum/ethash.rs b/src/ethereum/ethash.rs index aebee1e92..06d09f000 100644 --- a/src/ethereum/ethash.rs +++ b/src/ethereum/ethash.rs @@ -48,7 +48,7 @@ impl Engine for Ethash { // Two fields - mix fn seal_fields(&self) -> usize { 2 } // Two empty data items in RLP. - fn seal_rlp(&self) -> Bytes { encode(&H64::new()) } + fn seal_rlp(&self) -> Bytes { encode(&H64::new()).to_vec() } /// Additional engine-specific information for the user/developer concerning `header`. fn extra_info(&self, _header: &Header) -> HashMap { HashMap::new() } diff --git a/src/extras.rs b/src/extras.rs index fb4748447..54ab23b58 100644 --- a/src/extras.rs +++ b/src/extras.rs @@ -145,13 +145,12 @@ impl Decodable for BlockDetails { } impl Encodable for BlockDetails { - fn encode(&self, encoder: &mut E) where E: Encoder { - encoder.emit_list(| e | { - self.number.encode(e); - self.total_difficulty.encode(e); - self.parent.encode(e); - self.children.encode(e); - }) + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(4); + s.append(&self.number); + s.append(&self.total_difficulty); + s.append(&self.parent); + s.append_list(&self.children); } } @@ -185,8 +184,8 @@ impl Decodable for BlockLogBlooms { } impl Encodable for BlockLogBlooms { - fn encode(&self, encoder: &mut E) where E: Encoder { - self.blooms.encode(encoder); + fn rlp_append(&self, s: &mut RlpStream) { + s.append_list(&self.blooms); } } @@ -231,9 +230,9 @@ impl Decodable for BlocksBlooms { } impl Encodable for BlocksBlooms { - fn encode(&self, encoder: &mut E) where E: Encoder { + fn rlp_append(&self, s: &mut RlpStream) { let blooms_ref: &[H2048] = &self.blooms; - blooms_ref.encode(encoder); + s.append_list(&blooms_ref); } } @@ -269,10 +268,9 @@ impl Decodable for TransactionAddress { } impl Encodable for TransactionAddress { - fn encode(&self, encoder: &mut E) where E: Encoder { - encoder.emit_list(| e | { - self.block_hash.encode(e); - self.index.encode(e); - }) + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(2); + s.append(&self.block_hash); + s.append(&self.index); } } diff --git a/src/header.rs b/src/header.rs index 68526d8c6..4f79c20f0 100644 --- a/src/header.rs +++ b/src/header.rs @@ -157,7 +157,7 @@ impl Header { // TODO: make these functions traity /// TODO [Gav Wood] Please document me pub fn stream_rlp(&self, s: &mut RlpStream, with_seal: Seal) { - s.append_list(13 + match with_seal { Seal::With => self.seal.len(), _ => 0 }); + s.begin_list(13 + match with_seal { Seal::With => self.seal.len(), _ => 0 }); s.append(&self.parent_hash); s.append(&self.uncles_hash); s.append(&self.author); @@ -221,26 +221,8 @@ impl Decodable for Header { } impl Encodable for Header { - fn encode(&self, encoder: &mut E) where E: Encoder { - encoder.emit_list(| e | { - self.parent_hash.encode(e); - self.uncles_hash.encode(e); - self.author.encode(e); - self.state_root.encode(e); - self.transactions_root.encode(e); - self.receipts_root.encode(e); - self.log_bloom.encode(e); - self.difficulty.encode(e); - self.number.encode(e); - self.gas_limit.encode(e); - self.gas_used.encode(e); - self.timestamp.encode(e); - self.extra_data.encode(e); - - for b in &self.seal { - e.emit_raw(&b); - } - }) + fn rlp_append(&self, s: &mut RlpStream) { + self.stream_rlp(s, Seal::With); } } diff --git a/src/log_entry.rs b/src/log_entry.rs index a791b38a6..8b4173673 100644 --- a/src/log_entry.rs +++ b/src/log_entry.rs @@ -12,11 +12,11 @@ pub struct LogEntry { pub data: Bytes, } -impl RlpStandard for LogEntry { +impl Encodable for LogEntry { fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(3); + s.begin_list(3); s.append(&self.address); - s.append(&self.topics); + s.append_list(&self.topics); s.append(&self.data); } } diff --git a/src/pod_account.rs b/src/pod_account.rs index 81b8b1c44..338e7336c 100644 --- a/src/pod_account.rs +++ b/src/pod_account.rs @@ -36,7 +36,7 @@ impl PodAccount { let mut stream = RlpStream::new_list(4); stream.append(&self.nonce); stream.append(&self.balance); - stream.append(&sec_trie_root(self.storage.iter().map(|(k, v)| (k.to_vec(), encode(&U256::from(v.as_slice())))).collect())); + stream.append(&sec_trie_root(self.storage.iter().map(|(k, v)| (k.to_vec(), encode(&U256::from(v.as_slice())).to_vec())).collect())); stream.append(&self.code.sha3()); stream.out() } diff --git a/src/receipt.rs b/src/receipt.rs index 403915fdc..3242dd444 100644 --- a/src/receipt.rs +++ b/src/receipt.rs @@ -27,17 +27,12 @@ impl Receipt { } } -impl RlpStandard for Receipt { +impl Encodable for Receipt { fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(4); + s.begin_list(4); s.append(&self.state_root); s.append(&self.gas_used); s.append(&self.log_bloom); - // TODO: make work: - //s.append(&self.logs); - s.append_list(self.logs.len()); - for l in &self.logs { - l.rlp_append(s); - } + s.append_list(&self.logs); } } diff --git a/src/spec.rs b/src/spec.rs index 9f98d5e2a..2c74bc532 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -19,14 +19,14 @@ pub fn gzip64res_to_json(source: &[u8]) -> Json { // TODO: handle container types. fn json_to_rlp(json: &Json) -> Bytes { match *json { - Json::Boolean(o) => encode(&(if o {1u64} else {0})), - Json::I64(o) => encode(&(o as u64)), - Json::U64(o) => encode(&o), + Json::Boolean(o) => encode(&(if o {1u64} else {0})).to_vec(), + Json::I64(o) => encode(&(o as u64)).to_vec(), + Json::U64(o) => encode(&o).to_vec(), Json::String(ref s) if s.len() >= 2 && &s[0..2] == "0x" && U256::from_str(&s[2..]).is_ok() => { - encode(&U256::from_str(&s[2..]).unwrap()) + encode(&U256::from_str(&s[2..]).unwrap()).to_vec() }, Json::String(ref s) => { - encode(s) + encode(s).to_vec() }, _ => panic!() } diff --git a/src/transaction.rs b/src/transaction.rs index 47b8fa91f..d8422bff4 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -107,7 +107,7 @@ impl Transaction { /// Append object into RLP stream, optionally with or without the signature. pub fn rlp_append_opt(&self, s: &mut RlpStream, with_seal: Seal) { - s.append_list(6 + match with_seal { Seal::With => 3, _ => 0 }); + s.begin_list(6 + match with_seal { Seal::With => 3, _ => 0 }); s.append(&self.nonce); s.append(&self.gas_price); s.append(&self.gas); @@ -158,7 +158,7 @@ impl FromJson for Transaction { } } -impl RlpStandard for Transaction { +impl Encodable for Transaction { fn rlp_append(&self, s: &mut RlpStream) { self.rlp_append_opt(s, Seal::With) } } diff --git a/src/verification.rs b/src/verification.rs index 064c0b7d7..44b654f50 100644 --- a/src/verification.rs +++ b/src/verification.rs @@ -233,15 +233,12 @@ mod tests { fn create_test_block_with_data(header: &Header, transactions: &[&Transaction], uncles: &[Header]) -> Bytes { let mut rlp = RlpStream::new_list(3); rlp.append(header); - rlp.append_list(transactions.len()); + rlp.begin_list(transactions.len()); for t in transactions { rlp.append_raw(&t.rlp_bytes_opt(Seal::With), 1); } - rlp.append_list(uncles.len()); - for h in uncles { - rlp.append(h); - } - rlp.out() + rlp.append_list(&uncles); + rlp.out().to_vec() } fn check_ok(result: Result<(), Error>) { @@ -365,7 +362,7 @@ mod tests { let good_uncles = vec![ good_uncle1.clone(), good_uncle2.clone() ]; let mut uncles_rlp = RlpStream::new(); - uncles_rlp.append(&good_uncles); + uncles_rlp.append_list(&good_uncles); let good_uncles_hash = uncles_rlp.as_raw().sha3(); let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| t.rlp_bytes_opt(Seal::With)).collect()); From 698fa11e76b798028ed0025bcddbf894a14a88a3 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 27 Jan 2016 18:58:41 +0100 Subject: [PATCH 4/9] Fixed depth tracking --- util/src/rlp/rlpstream.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/util/src/rlp/rlpstream.rs b/util/src/rlp/rlpstream.rs index 7a0223d23..0c7418a8b 100644 --- a/util/src/rlp/rlpstream.rs +++ b/util/src/rlp/rlpstream.rs @@ -42,9 +42,11 @@ impl Stream for RlpStream { } fn append<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable { + let depth = self.unfinished_lists.len(); value.rlp_append(self); - // if list is finished, prepend the length - self.note_appended(1); + if depth == self.unfinished_lists.len() { + self.note_appended(1); + } self } From 7f187674fc802c17b5035ef89ea99142a678fa27 Mon Sep 17 00:00:00 2001 From: arkpar Date: Wed, 27 Jan 2016 19:27:11 +0100 Subject: [PATCH 5/9] Fixed depth tracking --- util/src/rlp/rlpstream.rs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/util/src/rlp/rlpstream.rs b/util/src/rlp/rlpstream.rs index 0c7418a8b..0b600b567 100644 --- a/util/src/rlp/rlpstream.rs +++ b/util/src/rlp/rlpstream.rs @@ -25,6 +25,7 @@ impl ListInfo { pub struct RlpStream { unfinished_lists: ElasticArray16, encoder: BasicEncoder, + finished_list: bool, } impl Stream for RlpStream { @@ -32,6 +33,7 @@ impl Stream for RlpStream { RlpStream { unfinished_lists: ElasticArray16::new(), encoder: BasicEncoder::new(), + finished_list: false, } } @@ -42,15 +44,16 @@ impl Stream for RlpStream { } fn append<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable { - let depth = self.unfinished_lists.len(); + self.finished_list = false; value.rlp_append(self); - if depth == self.unfinished_lists.len() { + if !self.finished_list { self.note_appended(1); } self } fn begin_list(&mut self, len: usize) -> &mut RlpStream { + self.finished_list = false; match len { 0 => { // we may finish, if the appended list len is equal 0 @@ -155,6 +158,7 @@ impl RlpStream { self.encoder.insert_list_len_at_pos(len, x.position); self.note_appended(1); } + self.finished_list = should_finish; } /// Drain the object and return the underlying ElasticArray. From 3f281754f2a9f4eb849705ff35338e507abc5f71 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 28 Jan 2016 12:35:50 +0100 Subject: [PATCH 6/9] removed smallvec --- util/Cargo.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/util/Cargo.toml b/util/Cargo.toml index 731247912..d0e2e0ab7 100644 --- a/util/Cargo.toml +++ b/util/Cargo.toml @@ -23,7 +23,6 @@ elastic-array = "0.4" heapsize = "0.2" itertools = "0.4" crossbeam = "0.2" -smallvec = "0.1" slab = { git = "https://github.com/arkpar/slab.git" } sha3 = { path = "sha3" } serde = "0.6.7" From 626fcdfffc239a2e973a1024e75624444af7fdb0 Mon Sep 17 00:00:00 2001 From: arkpar Date: Thu, 28 Jan 2016 20:13:05 +0100 Subject: [PATCH 7/9] append Now accepts lists again --- src/block.rs | 3 +- src/extras.rs | 6 +-- src/log_entry.rs | 2 +- src/receipt.rs | 2 +- src/verification.rs | 4 +- util/src/bytes.rs | 1 - util/src/journaldb.rs | 4 +- util/src/network/session.rs | 2 +- util/src/rlp/mod.rs | 23 +---------- util/src/rlp/rlpstream.rs | 82 +++++++++++++++++++++++++++---------- util/src/rlp/rlptraits.rs | 25 ++++------- util/src/rlp/tests.rs | 41 +++++++------------ 12 files changed, 96 insertions(+), 99 deletions(-) diff --git a/src/block.rs b/src/block.rs index ca99063d8..b1db20fd7 100644 --- a/src/block.rs +++ b/src/block.rs @@ -301,8 +301,7 @@ impl SealedBlock { pub fn rlp_bytes(&self) -> Bytes { let mut block_rlp = RlpStream::new_list(3); self.block.base.header.stream_rlp(&mut block_rlp, Seal::With); - block_rlp.begin_list(self.block.receipts.len()); - for t in &self.block.base.transactions { t.rlp_append(&mut block_rlp); } + block_rlp.append(&self.block.base.transactions); block_rlp.append_raw(&self.uncle_bytes, 1); block_rlp.out() } diff --git a/src/extras.rs b/src/extras.rs index 54ab23b58..d571e7c36 100644 --- a/src/extras.rs +++ b/src/extras.rs @@ -150,7 +150,7 @@ impl Encodable for BlockDetails { s.append(&self.number); s.append(&self.total_difficulty); s.append(&self.parent); - s.append_list(&self.children); + s.append(&self.children); } } @@ -185,7 +185,7 @@ impl Decodable for BlockLogBlooms { impl Encodable for BlockLogBlooms { fn rlp_append(&self, s: &mut RlpStream) { - s.append_list(&self.blooms); + s.append(&self.blooms); } } @@ -232,7 +232,7 @@ impl Decodable for BlocksBlooms { impl Encodable for BlocksBlooms { fn rlp_append(&self, s: &mut RlpStream) { let blooms_ref: &[H2048] = &self.blooms; - s.append_list(&blooms_ref); + s.append(&blooms_ref); } } diff --git a/src/log_entry.rs b/src/log_entry.rs index cb2b20e6c..8141549a3 100644 --- a/src/log_entry.rs +++ b/src/log_entry.rs @@ -16,7 +16,7 @@ impl Encodable for LogEntry { fn rlp_append(&self, s: &mut RlpStream) { s.begin_list(3); s.append(&self.address); - s.append_list(&self.topics); + s.append(&self.topics); s.append(&self.data); } } diff --git a/src/receipt.rs b/src/receipt.rs index 3ca9a76ee..d320373d6 100644 --- a/src/receipt.rs +++ b/src/receipt.rs @@ -33,6 +33,6 @@ impl Encodable for Receipt { s.append(&self.state_root); s.append(&self.gas_used); s.append(&self.log_bloom); - s.append_list(&self.logs); + s.append(&self.logs); } } diff --git a/src/verification.rs b/src/verification.rs index 0316ec7e7..567540c66 100644 --- a/src/verification.rs +++ b/src/verification.rs @@ -237,7 +237,7 @@ mod tests { for t in transactions { rlp.append_raw(&t.rlp_bytes_opt(Seal::With), 1); } - rlp.append_list(&uncles); + rlp.append(&uncles); rlp.out().to_vec() } @@ -362,7 +362,7 @@ mod tests { let good_uncles = vec![ good_uncle1.clone(), good_uncle2.clone() ]; let mut uncles_rlp = RlpStream::new(); - uncles_rlp.append_list(&good_uncles); + uncles_rlp.append(&good_uncles); let good_uncles_hash = uncles_rlp.as_raw().sha3(); let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| t.rlp_bytes_opt(Seal::With)).collect()); diff --git a/util/src/bytes.rs b/util/src/bytes.rs index f40771438..102206f6c 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -268,7 +268,6 @@ macro_rules! impl_map_to_bytes { } impl_map_to_bytes!(usize, u64); -impl_map_to_bytes!(u8, u64); impl_map_to_bytes!(u16, u64); impl_map_to_bytes!(u32, u64); diff --git a/util/src/journaldb.rs b/util/src/journaldb.rs index 6c904ca5f..ba31efafb 100644 --- a/util/src/journaldb.rs +++ b/util/src/journaldb.rs @@ -86,8 +86,8 @@ impl JournalDB { let mut r = RlpStream::new_list(3); r.append(id); - r.append_list(&self.inserts); - r.append_list(&self.removes); + r.append(&self.inserts); + r.append(&self.removes); try!(self.backing.put(&last, r.as_raw())); self.inserts.clear(); self.removes.clear(); diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 380da3e9b..09b7af5d3 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -202,7 +202,7 @@ impl Session { rlp.begin_list(5) .append(&host.protocol_version) .append(&host.client_version) - .append_list(&host.capabilities) + .append(&host.capabilities) .append(&host.listen_port) .append(host.id()); self.connection.send_packet(&rlp.out()) diff --git a/util/src/rlp/mod.rs b/util/src/rlp/mod.rs index 8dddf3acc..88872c2d1 100644 --- a/util/src/rlp/mod.rs +++ b/util/src/rlp/mod.rs @@ -30,7 +30,6 @@ //! * You want to get view onto rlp-slice. //! * You don't want to decode whole rlp at once. -use std::ops::Deref; /// TODO [Gav Wood] Please document me pub mod rlptraits; /// TODO [Gav Wood] Please document me @@ -46,7 +45,7 @@ pub mod rlpstream; mod tests; pub use self::rlperrors::DecoderError; -pub use self::rlptraits::{Decoder, Decodable, View, Stream, Encodable, Encoder}; +pub use self::rlptraits::{Decoder, Decodable, View, Stream, Encodable, Encoder, RlpEncodable}; pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype}; pub use self::rlpin::{Rlp, RlpIterator}; pub use self::rlpstream::{RlpStream}; @@ -91,26 +90,8 @@ pub fn decode(bytes: &[u8]) -> T where T: Decodable { /// assert_eq!(out, vec![0x83, b'c', b'a', b't']); /// } /// ``` -pub fn encode(object: &E) -> ElasticArray1024 where E: Encodable { +pub fn encode(object: &E) -> ElasticArray1024 where E: RlpEncodable { let mut stream = RlpStream::new(); stream.append(object); stream.drain() } - -/// Shortcut function to encode a list to rlp. -/// -/// ```rust -/// extern crate ethcore_util as util; -/// use util::rlp::*; -/// -/// fn main () { -/// let animals = vec!["cat", "dog"]; -/// let out = encode_list(&animals).to_vec(); -/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); -/// } -/// ``` -pub fn encode_list(list: &I) -> ElasticArray1024 where I: Deref, E: Encodable { - let mut stream = RlpStream::new(); - stream.append_list(list); - stream.drain() -} diff --git a/util/src/rlp/rlpstream.rs b/util/src/rlp/rlpstream.rs index 0b600b567..5eb071389 100644 --- a/util/src/rlp/rlpstream.rs +++ b/util/src/rlp/rlpstream.rs @@ -2,7 +2,7 @@ use std::ops::Deref; use elastic_array::*; use bytes::{ToBytes, VecLike}; use rlp::{Stream, Encoder, Encodable}; -use rlp::rlptraits::ByteEncodable; +use rlp::rlptraits::{ByteEncodable, RlpEncodable}; #[derive(Debug, Copy, Clone)] struct ListInfo { @@ -43,7 +43,7 @@ impl Stream for RlpStream { stream } - fn append<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable { + fn append<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: RlpEncodable { self.finished_list = false; value.rlp_append(self); if !self.finished_list { @@ -70,16 +70,6 @@ impl Stream for RlpStream { self } - fn append_list(&mut self, list: &I) -> &mut Self where I: Deref, E: Encodable { - let items = list.deref(); - self.begin_list(items.len()); - for el in items.iter() { - el.rlp_append(self); - } - self.note_appended(items.len()); - self - } - fn append_empty_data(&mut self) -> &mut RlpStream { // self push raw item self.encoder.bytes.push(0x80); @@ -134,6 +124,15 @@ impl RlpStream { self.encoder.emit_value(object); } + fn append_internal<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable { + self.finished_list = false; + value.rlp_append(self); + if !self.finished_list { + self.note_appended(1); + } + self + } + /// Try to finish lists fn note_appended(&mut self, inserted_items: usize) -> () { if self.unfinished_lists.len() == 0 { @@ -234,7 +233,6 @@ impl Encoder for BasicEncoder { } } - impl ByteEncodable for T where T: ToBytes { fn to_bytes>(&self, out: &mut V) { ToBytes::to_bytes(self, out) @@ -245,23 +243,27 @@ impl ByteEncodable for T where T: ToBytes { } } -impl<'a> ByteEncodable for &'a[u8] { +struct U8Slice<'a>(&'a [u8]); + +impl<'a> ByteEncodable for U8Slice<'a> { fn to_bytes>(&self, out: &mut V) { - out.vec_extend(self) + out.vec_extend(self.0) } fn bytes_len(&self) -> usize { - self.len() + self.0.len() } } -impl ByteEncodable for Vec { - fn to_bytes>(&self, out: &mut V) { - out.vec_extend(self.deref()) +impl<'a> Encodable for &'a[u8] { + fn rlp_append(&self, s: &mut RlpStream) { + s.append_value(&U8Slice(self)) } +} - fn bytes_len(&self) -> usize { - self.len() +impl Encodable for Vec { + fn rlp_append(&self, s: &mut RlpStream) { + s.append_value(&U8Slice(self.deref())) } } @@ -270,3 +272,41 @@ impl Encodable for T where T: ByteEncodable { s.append_value(self) } } + +struct EncodableU8 (u8); + +impl ByteEncodable for EncodableU8 { + fn to_bytes>(&self, out: &mut V) { + out.vec_push(self.0) + } + + fn bytes_len(&self) -> usize { 1 } +} + +impl RlpEncodable for u8 { + fn rlp_append(&self, s: &mut RlpStream) { + s.append_value(&EncodableU8(*self)) + } +} + +impl<'a, T> Encodable for &'a[T] where T: Encodable { + fn rlp_append(&self, s: &mut RlpStream) { + s.begin_list(self.len()); + for el in self.iter() { + s.append_internal(el); + } + } +} + +impl Encodable for Vec where T: Encodable { + fn rlp_append(&self, s: &mut RlpStream) { + Encodable::rlp_append(&self.deref(), s); + } +} + +impl RlpEncodable for T where T: Encodable { + fn rlp_append(&self, s: &mut RlpStream) { + Encodable::rlp_append(self, s) + } +} + diff --git a/util/src/rlp/rlptraits.rs b/util/src/rlp/rlptraits.rs index 437d86dc6..f79c7848c 100644 --- a/util/src/rlp/rlptraits.rs +++ b/util/src/rlp/rlptraits.rs @@ -223,7 +223,7 @@ pub trait ByteEncodable { fn bytes_len(&self) -> usize; } -/// Structure encodable to RLP +/// Structure encodable to RLP. Implement this trait for pub trait Encodable { /// Append a value to the stream fn rlp_append(&self, s: &mut RlpStream); @@ -239,6 +239,12 @@ pub trait Encodable { fn rlp_sha3(&self) -> H256 { self.rlp_bytes().deref().sha3() } } +/// Encodable wrapper trait required to handle special case of encoding a &[u8] as string and not as list +pub trait RlpEncodable { + /// Append a value to the stream + fn rlp_append(&self, s: &mut RlpStream); +} + /// TODO [debris] Please document me pub trait Stream: Sized { @@ -261,7 +267,7 @@ pub trait Stream: Sized { /// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); /// } /// ``` - fn append<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable; + fn append<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: RlpEncodable; /// Declare appending the list of given size, chainable. /// @@ -279,21 +285,6 @@ pub trait Stream: Sized { /// ``` fn begin_list(&mut self, len: usize) -> &mut Self; - /// Append the given list, chainable. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let mut stream = RlpStream::new_list(1); - /// stream.append_list(&vec!["cat", "dog"]); - /// let out = stream.out().to_vec(); - /// assert_eq!(out, vec![0xc9, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); - /// } - /// ``` - fn append_list(&mut self, list: &I) -> &mut Self where I: Deref, E: Encodable; - /// Apends null to the end of stream, chainable. /// /// ```rust diff --git a/util/src/rlp/tests.rs b/util/src/rlp/tests.rs index b83e851cc..912709b5e 100644 --- a/util/src/rlp/tests.rs +++ b/util/src/rlp/tests.rs @@ -77,7 +77,6 @@ fn rlp_iter() { } struct ETestPair(T, Vec) where T: rlp::Encodable; -struct ETestVecPair(Vec, Vec) where T: rlp::Encodable; fn run_encode_tests(tests: Vec>) where T: rlp::Encodable @@ -88,15 +87,6 @@ fn run_encode_tests(tests: Vec>) } } -fn run_encode_list_tests(tests: Vec>) - where T: rlp::Encodable -{ - for t in &tests { - let res = rlp::encode_list(&t.0); - assert_eq!(&res[..], &t.1[..]); - } -} - #[test] fn encode_u16() { let tests = vec![ @@ -188,19 +178,19 @@ fn encode_vector_u8() { #[test] fn encode_vector_u64() { let tests = vec![ - ETestVecPair(vec![], vec![0xc0]), - ETestVecPair(vec![15u64], vec![0xc1, 0x0f]), - ETestVecPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), - ETestVecPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), + ETestPair(vec![], vec![0xc0]), + ETestPair(vec![15u64], vec![0xc1, 0x0f]), + ETestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), + ETestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), ]; - run_encode_list_tests(tests); + run_encode_tests(tests); } #[test] fn encode_vector_str() { - let tests = vec![ETestVecPair(vec!["cat", "dog"], + let tests = vec![ETestPair(vec!["cat", "dog"], vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; - run_encode_list_tests(tests); + run_encode_tests(tests); } struct DTestPair(T, Vec) where T: rlp::Decodable + fmt::Debug + cmp::Eq; @@ -227,9 +217,8 @@ fn decode_vector_u8() { #[test] fn decode_untrusted_u16() { let tests = vec![ - DTestPair(0u16, vec![0u8]), - DTestPair(0x100, vec![0x82, 0x01, 0x00]), - DTestPair(0xffff, vec![0x82, 0xff, 0xff]), + DTestPair(0x100u16, vec![0x82, 0x01, 0x00]), + DTestPair(0xffffu16, vec![0x82, 0xff, 0xff]), ]; run_decode_tests(tests); } @@ -237,9 +226,8 @@ fn decode_untrusted_u16() { #[test] fn decode_untrusted_u32() { let tests = vec![ - DTestPair(0u32, vec![0u8]), - DTestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]), - DTestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]), + DTestPair(0x10000u32, vec![0x83, 0x01, 0x00, 0x00]), + DTestPair(0xffffffu32, vec![0x83, 0xff, 0xff, 0xff]), ]; run_decode_tests(tests); } @@ -247,9 +235,8 @@ fn decode_untrusted_u32() { #[test] fn decode_untrusted_u64() { let tests = vec![ - DTestPair(0u64, vec![0u8]), - DTestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]), - DTestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]), + DTestPair(0x1000000u64, vec![0x84, 0x01, 0x00, 0x00, 0x00]), + DTestPair(0xFFFFFFFFu64, vec![0x84, 0xff, 0xff, 0xff, 0xff]), ]; run_decode_tests(tests); } @@ -350,7 +337,7 @@ fn test_rlp_json() { #[test] fn test_decoding_array() { let v = vec![5u16, 2u16]; - let res = rlp::encode_list(&v); + let res = rlp::encode(&v); let arr: [u16; 2] = rlp::decode(&res); assert_eq!(arr[0], 5); assert_eq!(arr[1], 2); From cfa2776e75983a00101b4745ea62e38b77d79761 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 29 Jan 2016 12:27:50 +0100 Subject: [PATCH 8/9] Removed test log initializations --- src/sync/tests.rs | 3 --- util/src/network/tests.rs | 1 - util/src/trie/triedbmut.rs | 2 -- 3 files changed, 6 deletions(-) diff --git a/src/sync/tests.rs b/src/sync/tests.rs index eca8a07a6..1ac0d548f 100644 --- a/src/sync/tests.rs +++ b/src/sync/tests.rs @@ -306,7 +306,6 @@ impl TestNet { #[test] fn full_sync_two_peers() { - ::env_logger::init().ok(); let mut net = TestNet::new(3); net.peer_mut(1).chain.add_blocks(1000, false); net.peer_mut(2).chain.add_blocks(1000, false); @@ -317,7 +316,6 @@ fn full_sync_two_peers() { #[test] fn full_sync_empty_blocks() { - ::env_logger::init().ok(); let mut net = TestNet::new(3); for n in 0..200 { net.peer_mut(1).chain.add_blocks(5, n % 2 == 0); @@ -330,7 +328,6 @@ fn full_sync_empty_blocks() { #[test] fn forked_sync() { - ::env_logger::init().ok(); let mut net = TestNet::new(3); net.peer_mut(0).chain.add_blocks(300, false); net.peer_mut(1).chain.add_blocks(300, false); diff --git a/util/src/network/tests.rs b/util/src/network/tests.rs index 0dd1aed12..06966abb5 100644 --- a/util/src/network/tests.rs +++ b/util/src/network/tests.rs @@ -75,7 +75,6 @@ fn test_net_service() { #[test] fn test_net_connect() { - ::env_logger::init().ok(); let key1 = KeyPair::create().unwrap(); let mut config1 = NetworkConfiguration::new_with_port(30344); config1.use_secret = Some(key1.secret().clone()); diff --git a/util/src/trie/triedbmut.rs b/util/src/trie/triedbmut.rs index 5a5899ddb..4c3d36646 100644 --- a/util/src/trie/triedbmut.rs +++ b/util/src/trie/triedbmut.rs @@ -671,7 +671,6 @@ mod tests { use super::*; use nibbleslice::*; use rlp::*; - use env_logger; use rand::random; use std::collections::HashSet; use bytes::{ToPretty,Bytes,Populatable}; @@ -727,7 +726,6 @@ mod tests { #[test] fn playpen() { - env_logger::init().ok(); /*let maps = map!{ "six-low" => StandardMap{alphabet: Alphabet::Low, min_key: 6, journal_key: 0, count: 1000}, From 772de24cae5c6441fe5f9b121dc0e23b745fbbd0 Mon Sep 17 00:00:00 2001 From: arkpar Date: Fri, 29 Jan 2016 13:59:29 +0100 Subject: [PATCH 9/9] RLP decoder refactoring --- src/block.rs | 10 +- src/extras.rs | 16 +-- src/transaction.rs | 22 +-- util/src/bytes.rs | 230 ------------------------------ util/src/network/session.rs | 7 +- util/src/rlp/bytes.rs | 255 ++++++++++++++++++++++++++++++++++ util/src/rlp/mod.rs | 18 +-- util/src/rlp/rlperrors.rs | 2 +- util/src/rlp/rlpin.rs | 12 +- util/src/rlp/rlpstream.rs | 2 +- util/src/rlp/rlptraits.rs | 21 +-- util/src/rlp/tests.rs | 16 ++- util/src/rlp/untrusted_rlp.rs | 56 +++++--- 13 files changed, 362 insertions(+), 305 deletions(-) create mode 100644 util/src/rlp/bytes.rs diff --git a/src/block.rs b/src/block.rs index b1db20fd7..963124be0 100644 --- a/src/block.rs +++ b/src/block.rs @@ -45,14 +45,14 @@ impl Decodable for Block { if decoder.as_raw().len() != try!(decoder.as_rlp().payload_info()).total() { return Err(DecoderError::RlpIsTooBig); } - let d = try!(decoder.as_list()); - if d.len() != 3 { + let d = decoder.as_rlp(); + if d.item_count() != 3 { return Err(DecoderError::RlpIncorrectListLen); } Ok(Block { - header: try!(Decodable::decode(&d[0])), - transactions: try!(Decodable::decode(&d[1])), - uncles: try!(Decodable::decode(&d[2])), + header: try!(d.val_at(0)), + transactions: try!(d.val_at(1)), + uncles: try!(d.val_at(2)), }) } } diff --git a/src/extras.rs b/src/extras.rs index d571e7c36..4459826cc 100644 --- a/src/extras.rs +++ b/src/extras.rs @@ -133,12 +133,12 @@ impl HeapSizeOf for BlockDetails { impl Decodable for BlockDetails { fn decode(decoder: &D) -> Result where D: Decoder { - let d = try!(decoder.as_list()); + let d = decoder.as_rlp(); let details = BlockDetails { - number: try!(Decodable::decode(&d[0])), - total_difficulty: try!(Decodable::decode(&d[1])), - parent: try!(Decodable::decode(&d[2])), - children: try!(Decodable::decode(&d[3])) + number: try!(d.val_at(0)), + total_difficulty: try!(d.val_at(1)), + parent: try!(d.val_at(2)), + children: try!(d.val_at(3)), }; Ok(details) } @@ -257,10 +257,10 @@ impl HeapSizeOf for TransactionAddress { impl Decodable for TransactionAddress { fn decode(decoder: &D) -> Result where D: Decoder { - let d = try!(decoder.as_list()); + let d = decoder.as_rlp(); let tx_address = TransactionAddress { - block_hash: try!(Decodable::decode(&d[0])), - index: try!(Decodable::decode(&d[1])) + block_hash: try!(d.val_at(0)), + index: try!(d.val_at(1)), }; Ok(tx_address) diff --git a/src/transaction.rs b/src/transaction.rs index 3085bc461..24b617f67 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -267,20 +267,20 @@ impl Decodable for Action { impl Decodable for Transaction { fn decode(decoder: &D) -> Result where D: Decoder { - let d = try!(decoder.as_list()); - if d.len() != 9 { + let d = decoder.as_rlp(); + if d.item_count() != 9 { return Err(DecoderError::RlpIncorrectListLen); } Ok(Transaction { - nonce: try!(Decodable::decode(&d[0])), - gas_price: try!(Decodable::decode(&d[1])), - gas: try!(Decodable::decode(&d[2])), - action: try!(Decodable::decode(&d[3])), - value: try!(Decodable::decode(&d[4])), - data: try!(Decodable::decode(&d[5])), - v: try!(u16::decode(&d[6])) as u8, - r: try!(Decodable::decode(&d[7])), - s: try!(Decodable::decode(&d[8])), + nonce: try!(d.val_at(0)), + gas_price: try!(d.val_at(1)), + gas: try!(d.val_at(2)), + action: try!(d.val_at(3)), + value: try!(d.val_at(4)), + data: try!(d.val_at(5)), + v: try!(d.val_at(6)), + r: try!(d.val_at(7)), + s: try!(d.val_at(8)), hash: RefCell::new(None), sender: RefCell::new(None), }) diff --git a/util/src/bytes.rs b/util/src/bytes.rs index 102206f6c..050c07a66 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -11,37 +11,14 @@ //! let slice: &[u8] = arr.bytes(); //! } //! -//! fn to_bytes() { -//! use util::bytes::ToBytes; -//! -//! let mut out: Vec = Vec::new(); -//! "hello_world".to_bytes(&mut out); -//! 400u32.to_bytes(&mut out); -//! 0xffffffffffffffffu64.to_bytes(&mut out); -//! } -//! -//! fn from_bytes() { -//! use util::bytes::FromBytes; -//! -//! let a = String::from_bytes(&[b'd', b'o', b'g']); -//! let b = u16::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::mem; use std::fmt; use std::slice; -use std::cmp::Ordering; -use std::error::Error as StdError; use std::ops::{Deref, DerefMut}; -use uint::{Uint, U128, U256}; use hash::FixedHash; use elastic_array::*; @@ -205,213 +182,6 @@ fn bytes_convertable() { assert_eq!([0u8; 0].bytes(), &[]); } -/// Converts given type to its shortest representation in bytes -/// -/// TODO: optimise some conversations -pub trait ToBytes { - /// Serialize self to byte array - fn to_bytes>(&self, out: &mut V); - /// Get length of serialized data in bytes - fn to_bytes_len(&self) -> usize; -} - -impl <'a> ToBytes for &'a str { - fn to_bytes>(&self, out: &mut V) { - out.vec_extend(self.as_bytes()); - } - - fn to_bytes_len(&self) -> usize { - self.as_bytes().len() - } -} - -impl ToBytes for String { - fn to_bytes>(&self, out: &mut V) { - out.vec_extend(self.as_bytes()); - } - - fn to_bytes_len(&self) -> usize { - self.len() - } -} - -impl ToBytes for u64 { - fn to_bytes>(&self, out: &mut V) { - let count = self.to_bytes_len(); - for i in 0..count { - let j = count - 1 - i; - out.vec_push((*self >> (j * 8)) as u8); - } - } - - fn to_bytes_len(&self) -> usize { 8 - self.leading_zeros() as usize / 8 } -} - -impl ToBytes for bool { - fn to_bytes>(&self, out: &mut V) { - out.vec_push(if *self { 1u8 } else { 0u8 }) - } - - fn to_bytes_len(&self) -> usize { 1 } -} - -macro_rules! impl_map_to_bytes { - ($from: ident, $to: ty) => { - impl ToBytes for $from { - fn to_bytes>(&self, out: &mut V) { - (*self as $to).to_bytes(out) - } - - fn to_bytes_len(&self) -> usize { (*self as $to).to_bytes_len() } - } - } -} - -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, out: &mut V) { - let count = self.to_bytes_len(); - for i in 0..count { - let j = count - 1 - i; - out.vec_push(self.byte(j)); - } - } - fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } - } - } -} - -impl_uint_to_bytes!(U256); -impl_uint_to_bytes!(U128); - -impl ToBytes for T where T: FixedHash { - fn to_bytes>(&self, out: &mut V) { - out.vec_extend(self.bytes()); - } - fn to_bytes_len(&self) -> usize { self.bytes().len() } -} - -/// Error returned when FromBytes conversation goes wrong -#[derive(Debug, PartialEq, Eq)] -pub enum FromBytesError { - /// TODO [debris] Please document me - DataIsTooShort, - /// TODO [debris] Please document me - DataIsTooLong, - /// Integer-representation is non-canonically prefixed with zero byte(s). - ZeroPrefixedInt, -} - -impl StdError for FromBytesError { - fn description(&self) -> &str { "from_bytes error" } -} - -impl fmt::Display for FromBytesError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self, f) - } -} - -/// Alias for the result of FromBytes trait -pub type FromBytesResult = Result; - -/// Converts to given type from its bytes representation -/// -/// TODO: check size of bytes before conversation and return appropriate error -pub trait FromBytes: Sized { - /// TODO [debris] Please document me - fn from_bytes(bytes: &[u8]) -> FromBytesResult; -} - -impl FromBytes for String { - fn from_bytes(bytes: &[u8]) -> FromBytesResult { - Ok(::std::str::from_utf8(bytes).unwrap().to_owned()) - } -} - -macro_rules! impl_uint_from_bytes { - ($to: ident) => { - impl FromBytes for $to { - fn from_bytes(bytes: &[u8]) -> FromBytesResult<$to> { - match bytes.len() { - 0 => Ok(0), - l if l <= mem::size_of::<$to>() => { - if bytes[0] == 0 { - return Err(FromBytesError::ZeroPrefixedInt) - } - let mut res = 0 as $to; - for i in 0..l { - let shift = (l - 1 - i) * 8; - res = res + ((bytes[i] as $to) << shift); - } - Ok(res) - } - _ => Err(FromBytesError::DataIsTooLong) - } - } - } - } -} - -impl FromBytes for bool { - fn from_bytes(bytes: &[u8]) -> FromBytesResult { - match bytes.len() { - 0 => Ok(false), - 1 => Ok(bytes[0] != 0), - _ => Err(FromBytesError::DataIsTooLong), - } - } -} - -//impl_uint_from_bytes!(u8); -impl_uint_from_bytes!(u16); -impl_uint_from_bytes!(u32); -impl_uint_from_bytes!(u64); -impl_uint_from_bytes!(usize); - -macro_rules! impl_uint_from_bytes { - ($name: ident) => { - impl FromBytes for $name { - fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { - if !bytes.is_empty() && bytes[0] == 0 { - Err(FromBytesError::ZeroPrefixedInt) - } else if bytes.len() <= $name::SIZE { - Ok($name::from(bytes)) - } else { - Err(FromBytesError::DataIsTooLong) - } - } - } - } -} - -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.as_slice_mut().as_mut_ptr(), T::size()); - - Ok(res) - } - } -} - /// Simple trait to allow for raw population of a Sized object from a byte slice. pub trait Populatable { /// Copies a bunch of bytes `d` to `self`, overwriting as necessary. diff --git a/util/src/network/session.rs b/util/src/network/session.rs index 09b7af5d3..fb385b487 100644 --- a/util/src/network/session.rs +++ b/util/src/network/session.rs @@ -57,11 +57,10 @@ pub struct PeerCapabilityInfo { impl Decodable for PeerCapabilityInfo { fn decode(decoder: &D) -> Result where D: Decoder { - let c = try!(decoder.as_list()); - let v: u32 = try!(Decodable::decode(&c[1])); + let c = decoder.as_rlp(); Ok(PeerCapabilityInfo { - protocol: try!(Decodable::decode(&c[0])), - version: v as u8, + protocol: try!(c.val_at(0)), + version: try!(c.val_at(1)) }) } } diff --git a/util/src/rlp/bytes.rs b/util/src/rlp/bytes.rs new file mode 100644 index 000000000..69562764c --- /dev/null +++ b/util/src/rlp/bytes.rs @@ -0,0 +1,255 @@ +//! Unified interfaces for RLP bytes operations on basic types +//! + +use std::mem; +use std::fmt; +use std::cmp::Ordering; +use std::error::Error as StdError; +use uint::{Uint, U128, U256}; +use hash::FixedHash; +use elastic_array::*; + +/// Vector like object +pub trait VecLike { + /// Add an element to the collection + fn vec_push(&mut self, value: T); + + /// Add a slice to the collection + fn vec_extend(&mut self, slice: &[T]); +} + +impl VecLike for Vec where T: Copy { + fn vec_push(&mut self, value: T) { + Vec::::push(self, value) + } + + fn vec_extend(&mut self, slice: &[T]) { + Vec::::extend_from_slice(self, slice) + } +} + +macro_rules! impl_veclike_for_elastic_array { + ($from: ident) => { + impl VecLike for $from where T: Copy { + fn vec_push(&mut self, value: T) { + $from::::push(self, value) + } + fn vec_extend(&mut self, slice: &[T]) { + $from::::append_slice(self, slice) + + } + } + } +} + +impl_veclike_for_elastic_array!(ElasticArray16); +impl_veclike_for_elastic_array!(ElasticArray32); +impl_veclike_for_elastic_array!(ElasticArray1024); + +/// Converts given type to its shortest representation in bytes +/// +/// TODO: optimise some conversations +pub trait ToBytes { + /// Serialize self to byte array + fn to_bytes>(&self, out: &mut V); + /// Get length of serialized data in bytes + fn to_bytes_len(&self) -> usize; +} + +impl <'a> ToBytes for &'a str { + fn to_bytes>(&self, out: &mut V) { + out.vec_extend(self.as_bytes()); + } + + fn to_bytes_len(&self) -> usize { + self.as_bytes().len() + } +} + +impl ToBytes for String { + fn to_bytes>(&self, out: &mut V) { + out.vec_extend(self.as_bytes()); + } + + fn to_bytes_len(&self) -> usize { + self.len() + } +} + +impl ToBytes for u64 { + fn to_bytes>(&self, out: &mut V) { + let count = self.to_bytes_len(); + for i in 0..count { + let j = count - 1 - i; + out.vec_push((*self >> (j * 8)) as u8); + } + } + + fn to_bytes_len(&self) -> usize { 8 - self.leading_zeros() as usize / 8 } +} + +impl ToBytes for bool { + fn to_bytes>(&self, out: &mut V) { + out.vec_push(if *self { 1u8 } else { 0u8 }) + } + + fn to_bytes_len(&self) -> usize { 1 } +} + +macro_rules! impl_map_to_bytes { + ($from: ident, $to: ty) => { + impl ToBytes for $from { + fn to_bytes>(&self, out: &mut V) { + (*self as $to).to_bytes(out) + } + + fn to_bytes_len(&self) -> usize { (*self as $to).to_bytes_len() } + } + } +} + +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, out: &mut V) { + let count = self.to_bytes_len(); + for i in 0..count { + let j = count - 1 - i; + out.vec_push(self.byte(j)); + } + } + fn to_bytes_len(&self) -> usize { (self.bits() + 7) / 8 } + } + } +} + +impl_uint_to_bytes!(U256); +impl_uint_to_bytes!(U128); + +impl ToBytes for T where T: FixedHash { + fn to_bytes>(&self, out: &mut V) { + out.vec_extend(self.bytes()); + } + fn to_bytes_len(&self) -> usize { self.bytes().len() } +} + +/// Error returned when FromBytes conversation goes wrong +#[derive(Debug, PartialEq, Eq)] +pub enum FromBytesError { + /// TODO [debris] Please document me + DataIsTooShort, + /// TODO [debris] Please document me + DataIsTooLong, + /// Integer-representation is non-canonically prefixed with zero byte(s). + ZeroPrefixedInt, +} + +impl StdError for FromBytesError { + fn description(&self) -> &str { "from_bytes error" } +} + +impl fmt::Display for FromBytesError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self, f) + } +} + +/// Alias for the result of FromBytes trait +pub type FromBytesResult = Result; + +/// Converts to given type from its bytes representation +/// +/// TODO: check size of bytes before conversation and return appropriate error +pub trait FromBytes: Sized { + /// TODO [debris] Please document me + fn from_bytes(bytes: &[u8]) -> FromBytesResult; +} + +impl FromBytes for String { + fn from_bytes(bytes: &[u8]) -> FromBytesResult { + Ok(::std::str::from_utf8(bytes).unwrap().to_owned()) + } +} + +macro_rules! impl_uint_from_bytes { + ($to: ident) => { + impl FromBytes for $to { + fn from_bytes(bytes: &[u8]) -> FromBytesResult<$to> { + match bytes.len() { + 0 => Ok(0), + l if l <= mem::size_of::<$to>() => { + if bytes[0] == 0 { + return Err(FromBytesError::ZeroPrefixedInt) + } + let mut res = 0 as $to; + for i in 0..l { + let shift = (l - 1 - i) * 8; + res = res + ((bytes[i] as $to) << shift); + } + Ok(res) + } + _ => Err(FromBytesError::DataIsTooLong) + } + } + } + } +} + +impl FromBytes for bool { + fn from_bytes(bytes: &[u8]) -> FromBytesResult { + match bytes.len() { + 0 => Ok(false), + 1 => Ok(bytes[0] != 0), + _ => Err(FromBytesError::DataIsTooLong), + } + } +} + +//impl_uint_from_bytes!(u8); +impl_uint_from_bytes!(u16); +impl_uint_from_bytes!(u32); +impl_uint_from_bytes!(u64); +impl_uint_from_bytes!(usize); + +macro_rules! impl_uint_from_bytes { + ($name: ident) => { + impl FromBytes for $name { + fn from_bytes(bytes: &[u8]) -> FromBytesResult<$name> { + if !bytes.is_empty() && bytes[0] == 0 { + Err(FromBytesError::ZeroPrefixedInt) + } else if bytes.len() <= $name::SIZE { + Ok($name::from(bytes)) + } else { + Err(FromBytesError::DataIsTooLong) + } + } + } + } +} + +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.as_slice_mut().as_mut_ptr(), T::size()); + + Ok(res) + } + } +} + diff --git a/util/src/rlp/mod.rs b/util/src/rlp/mod.rs index 88872c2d1..f6101abc6 100644 --- a/util/src/rlp/mod.rs +++ b/util/src/rlp/mod.rs @@ -30,22 +30,18 @@ //! * You want to get view onto rlp-slice. //! * You don't want to decode whole rlp at once. -/// TODO [Gav Wood] Please document me pub mod rlptraits; -/// TODO [Gav Wood] Please document me -pub mod rlperrors; -/// TODO [debris] Please document me -pub mod rlpin; -/// TODO [debris] Please document me -pub mod untrusted_rlp; -/// TODO [debris] Please document me -pub mod rlpstream; +mod rlperrors; +mod rlpin; +mod untrusted_rlp; +mod rlpstream; +mod bytes; #[cfg(test)] mod tests; pub use self::rlperrors::DecoderError; -pub use self::rlptraits::{Decoder, Decodable, View, Stream, Encodable, Encoder, RlpEncodable}; +pub use self::rlptraits::{Decoder, Decodable, View, Stream, Encodable, Encoder, RlpEncodable, RlpDecodable}; pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype}; pub use self::rlpin::{Rlp, RlpIterator}; pub use self::rlpstream::{RlpStream}; @@ -73,7 +69,7 @@ pub const SHA3_EMPTY_LIST_RLP: H256 = H256( [0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, /// assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]); /// } /// ``` -pub fn decode(bytes: &[u8]) -> T where T: Decodable { +pub fn decode(bytes: &[u8]) -> T where T: RlpDecodable { let rlp = Rlp::new(bytes); rlp.as_val() } diff --git a/util/src/rlp/rlperrors.rs b/util/src/rlp/rlperrors.rs index 6ac162236..f5d4629ad 100644 --- a/util/src/rlp/rlperrors.rs +++ b/util/src/rlp/rlperrors.rs @@ -1,6 +1,6 @@ use std::fmt; use std::error::Error as StdError; -use bytes::FromBytesError; +use rlp::bytes::FromBytesError; #[derive(Debug, PartialEq, Eq)] /// TODO [debris] Please document me diff --git a/util/src/rlp/rlpin.rs b/util/src/rlp/rlpin.rs index 5cecce44f..cfcaee014 100644 --- a/util/src/rlp/rlpin.rs +++ b/util/src/rlp/rlpin.rs @@ -1,5 +1,5 @@ use std::fmt; -use rlp::{View, Decodable, DecoderError, UntrustedRlp, PayloadInfo, Prototype}; +use rlp::{View, DecoderError, UntrustedRlp, PayloadInfo, Prototype, RlpDecodable}; impl<'a> From> for Rlp<'a> { fn from(rlp: UntrustedRlp<'a>) -> Rlp<'a> { @@ -88,28 +88,28 @@ impl<'a, 'view> View<'a, 'view> for Rlp<'a> where 'a: 'view { self.into_iter() } - fn as_val(&self) -> Result where T: Decodable { + fn as_val(&self) -> Result where T: RlpDecodable { self.rlp.as_val() } - fn val_at(&self, index: usize) -> Result where T: Decodable { + fn val_at(&self, index: usize) -> Result where T: RlpDecodable { self.at(index).rlp.as_val() } } impl <'a, 'view> Rlp<'a> where 'a: 'view { - fn view_as_val(r: &R) -> T where R: View<'a, 'view>, T: Decodable { + fn view_as_val(r: &R) -> T where R: View<'a, 'view>, T: RlpDecodable { let res: Result = r.as_val(); res.unwrap_or_else(|_| panic!()) } /// TODO [debris] Please document me - pub fn as_val(&self) -> T where T: Decodable { + pub fn as_val(&self) -> T where T: RlpDecodable { Self::view_as_val(self) } /// TODO [debris] Please document me - pub fn val_at(&self, index: usize) -> T where T: Decodable { + pub fn val_at(&self, index: usize) -> T where T: RlpDecodable { Self::view_as_val(&self.at(index)) } } diff --git a/util/src/rlp/rlpstream.rs b/util/src/rlp/rlpstream.rs index 5eb071389..b6b500a74 100644 --- a/util/src/rlp/rlpstream.rs +++ b/util/src/rlp/rlpstream.rs @@ -1,6 +1,6 @@ use std::ops::Deref; use elastic_array::*; -use bytes::{ToBytes, VecLike}; +use rlp::bytes::{ToBytes, VecLike}; use rlp::{Stream, Encoder, Encodable}; use rlp::rlptraits::{ByteEncodable, RlpEncodable}; diff --git a/util/src/rlp/rlptraits.rs b/util/src/rlp/rlptraits.rs index f79c7848c..17acbb40b 100644 --- a/util/src/rlp/rlptraits.rs +++ b/util/src/rlp/rlptraits.rs @@ -1,7 +1,8 @@ +//! Common RLP traits use std::ops::Deref; -use bytes::VecLike; +use rlp::bytes::VecLike; use rlp::{DecoderError, UntrustedRlp}; -use rlpstream::RlpStream; +use rlp::rlpstream::RlpStream; use elastic_array::ElasticArray1024; use hash::H256; use sha3::*; @@ -12,17 +13,21 @@ pub trait Decoder: Sized { fn read_value(&self, f: F) -> Result where F: FnOnce(&[u8]) -> Result; - /// TODO [arkpar] Please document me - fn as_list(&self) -> Result, DecoderError>; /// TODO [Gav Wood] Please document me fn as_rlp(&self) -> &UntrustedRlp; /// TODO [debris] Please document me fn as_raw(&self) -> &[u8]; } -/// TODO [debris] Please document me +/// RLP decodable trait pub trait Decodable: Sized { - /// TODO [debris] Please document me + /// Decode a value from RLP bytes + fn decode(decoder: &D) -> Result where D: Decoder; +} + +/// Internal helper trait. Implement `Decodable` for custom types. +pub trait RlpDecodable: Sized { + /// Decode a value from RLP bytes fn decode(decoder: &D) -> Result where D: Decoder; } @@ -201,10 +206,10 @@ pub trait View<'a, 'view>: Sized { fn iter(&'view self) -> Self::Iter; /// TODO [debris] Please document me - fn as_val(&self) -> Result where T: Decodable; + fn as_val(&self) -> Result where T: RlpDecodable; /// TODO [debris] Please document me - fn val_at(&self, index: usize) -> Result where T: Decodable; + fn val_at(&self, index: usize) -> Result where T: RlpDecodable; } /// TODO [debris] Please document me diff --git a/util/src/rlp/tests.rs b/util/src/rlp/tests.rs index 912709b5e..3b00676f8 100644 --- a/util/src/rlp/tests.rs +++ b/util/src/rlp/tests.rs @@ -13,7 +13,7 @@ fn rlp_at() { { let rlp = UntrustedRlp::new(&data); assert!(rlp.is_list()); - //let animals = as rlp::Decodable>::decode_untrusted(&rlp).unwrap(); + //let animals = as rlp::RlpDecodable>::decode_untrusted(&rlp).unwrap(); let animals: Vec = rlp.as_val().unwrap(); assert_eq!(animals, vec!["cat".to_owned(), "dog".to_owned()]); @@ -193,9 +193,9 @@ fn encode_vector_str() { run_encode_tests(tests); } -struct DTestPair(T, Vec) where T: rlp::Decodable + fmt::Debug + cmp::Eq; +struct DTestPair(T, Vec) where T: rlp::RlpDecodable + fmt::Debug + cmp::Eq; -fn run_decode_tests(tests: Vec>) where T: rlp::Decodable + fmt::Debug + cmp::Eq { +fn run_decode_tests(tests: Vec>) where T: rlp::RlpDecodable + fmt::Debug + cmp::Eq { for t in &tests { let res: T = rlp::decode(&t.1); assert_eq!(res, t.0); @@ -214,6 +214,16 @@ fn decode_vector_u8() { run_decode_tests(tests); } +#[test] +fn decode_untrusted_u8() { + let tests = vec![ + DTestPair(0x0u8, vec![0x80]), + DTestPair(0x77u8, vec![0x77]), + DTestPair(0xccu8, vec![0x81, 0xcc]), + ]; + run_decode_tests(tests); +} + #[test] fn decode_untrusted_u16() { let tests = vec![ diff --git a/util/src/rlp/untrusted_rlp.rs b/util/src/rlp/untrusted_rlp.rs index 07a9a4cde..604273b20 100644 --- a/util/src/rlp/untrusted_rlp.rs +++ b/util/src/rlp/untrusted_rlp.rs @@ -1,8 +1,8 @@ use std::cell::Cell; use std::fmt; use rustc_serialize::hex::ToHex; -use bytes::{FromBytes}; -use rlp::{View, Decoder, Decodable, DecoderError}; +use rlp::bytes::{FromBytes, FromBytesResult, FromBytesError}; +use rlp::{View, Decoder, Decodable, DecoderError, RlpDecodable}; /// rlp offset #[derive(Copy, Clone, Debug)] @@ -211,12 +211,12 @@ impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view { self.into_iter() } - fn as_val(&self) -> Result where T: Decodable { + fn as_val(&self) -> Result where T: RlpDecodable { // optimize, so it doesn't use clone (although This clone is cheap) T::decode(&BasicDecoder::new(self.clone())) } - fn val_at(&self, index: usize) -> Result where T: Decodable { + fn val_at(&self, index: usize) -> Result where T: RlpDecodable { try!(self.at(index)).as_val() } } @@ -369,13 +369,6 @@ impl<'a> Decoder for BasicDecoder<'a> { self.rlp.as_raw() } - fn as_list(&self) -> Result, DecoderError> { - let v: Vec> = self.rlp.iter() - .map(BasicDecoder::new) - .collect(); - Ok(v) - } - fn as_rlp(&self) -> &UntrustedRlp { &self.rlp } @@ -391,8 +384,7 @@ impl Decodable for T where T: FromBytes { impl Decodable for Vec where T: Decodable { fn decode(decoder: &D) -> Result where D: Decoder { - let decoders = try!(decoder.as_list()); - decoders.iter().map(|d| T::decode(d)).collect() + decoder.as_rlp().iter().map(|d| T::decode(&BasicDecoder::new(d))).collect() } } @@ -423,15 +415,15 @@ macro_rules! impl_array_decodable { impl Decodable for [T; $len] where T: Decodable { #[allow(len_zero)] fn decode(decoder: &D) -> Result where D: Decoder { - let decoders = try!(decoder.as_list()); + let decoders = decoder.as_rlp(); let mut result: [T; $len] = unsafe { ::std::mem::uninitialized() }; - if decoders.len() != $len { + if decoders.item_count() != $len { return Err(DecoderError::RlpIncorrectListLen); } - for i in 0..decoders.len() { - result[i] = try!(T::decode(&decoders[i])); + for i in 0..decoders.item_count() { + result[i] = try!(T::decode(&BasicDecoder::new(try!(decoders.at(i))))); } Ok(result) @@ -454,6 +446,36 @@ impl_array_decodable_recursive!( 32, 40, 48, 56, 64, 72, 96, 128, 160, 192, 224, ); +impl RlpDecodable for T where T: Decodable { + fn decode(decoder: &D) -> Result where D: Decoder { + Decodable::decode(decoder) + } +} + +struct DecodableU8 (u8); + +impl FromBytes for DecodableU8 { + fn from_bytes(bytes: &[u8]) -> FromBytesResult { + match bytes.len() { + 0 => Ok(DecodableU8(0u8)), + 1 => { + if bytes[0] == 0 { + return Err(FromBytesError::ZeroPrefixedInt) + } + Ok(DecodableU8(bytes[0])) + } + _ => Err(FromBytesError::DataIsTooLong) + } + } +} + +impl RlpDecodable for u8 { + fn decode(decoder: &D) -> Result where D: Decoder { + let u: DecodableU8 = try!(Decodable::decode(decoder)); + Ok(u.0) + } +} + #[test] fn test_rlp_display() { use rustc_serialize::hex::FromHex;