diff --git a/src/block.rs b/src/block.rs index 83780ab43..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)), }) } } @@ -245,11 +245,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.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|ref e| e.rlp_bytes()).collect()); + s.block.base.header.transactions_root = ordered_trie_root(s.block.base.transactions.iter().map(|ref e| e.rlp_bytes().to_vec()).collect()); let uncle_bytes = s.block.base.uncles.iter().fold(RlpStream::new_list(s.block.base.uncles.len()), |mut s, u| {s.append(&u.rlp(Seal::With)); s} ).out(); s.block.base.header.uncles_hash = uncle_bytes.sha3(); s.block.base.header.state_root = s.block.state.root().clone(); - s.block.base.header.receipts_root = ordered_trie_root(s.block.receipts.iter().map(|ref r| r.rlp_bytes()).collect()); + s.block.base.header.receipts_root = ordered_trie_root(s.block.receipts.iter().map(|ref r| r.rlp_bytes().to_vec()).collect()); s.block.base.header.log_bloom = s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b |= &r.log_bloom; b}); s.block.base.header.gas_used = s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used); s.block.base.header.note_dirty(); @@ -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.append_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/ethereum/ethash.rs b/src/ethereum/ethash.rs index 4736beb92..f28ea31c6 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..4459826cc 100644 --- a/src/extras.rs +++ b/src/extras.rs @@ -133,25 +133,24 @@ 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) } } 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(&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(&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(&blooms_ref); } } @@ -258,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) @@ -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 a57d4166d..c6c18bf4b 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 be39a72f2..8141549a3 100644 --- a/src/log_entry.rs +++ b/src/log_entry.rs @@ -12,9 +12,9 @@ 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(&self.data); diff --git a/src/pod_account.rs b/src/pod_account.rs index 979658202..97cfcb6fd 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 4389de962..d320373d6 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(&self.logs); } } diff --git a/src/spec.rs b/src/spec.rs index 4d342f713..d51246b23 100644 --- a/src/spec.rs +++ b/src/spec.rs @@ -20,14 +20,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/sync/tests.rs b/src/sync/tests.rs index 7f19c3781..eb09b467a 100644 --- a/src/sync/tests.rs +++ b/src/sync/tests.rs @@ -325,7 +325,6 @@ impl TestNet { #[test] fn chain_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); @@ -336,7 +335,6 @@ fn chain_two_peers() { #[test] fn chain_status_after_sync() { - ::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); @@ -356,7 +354,6 @@ fn chain_takes_few_steps() { #[test] fn chain_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); @@ -368,8 +365,7 @@ fn chain_empty_blocks() { } #[test] -fn chain_forged() { - ::env_logger::init().ok(); +fn chain_forked() { 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/src/tests/helpers.rs b/src/tests/helpers.rs index 523b3f73f..de73224fd 100644 --- a/src/tests/helpers.rs +++ b/src/tests/helpers.rs @@ -89,14 +89,11 @@ fn create_unverifiable_block(order: u32, parent_hash: H256) -> Bytes { pub 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.append(&uncles); rlp.out() } diff --git a/src/transaction.rs b/src/transaction.rs index cacdf2a25..24b617f67 100644 --- a/src/transaction.rs +++ b/src/transaction.rs @@ -111,7 +111,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); @@ -162,7 +162,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) } } @@ -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 3144dd482..050c07a66 100644 --- a/util/src/bytes.rs +++ b/util/src/bytes.rs @@ -11,39 +11,55 @@ //! let slice: &[u8] = arr.bytes(); //! } //! -//! fn to_bytes() { -//! use util::bytes::ToBytes; -//! -//! let a: Vec = "hello_world".to_bytes(); -//! let b: Vec = 400u32.to_bytes(); -//! let c: Vec = 0xffffffffffffffffu64.to_bytes(); -//! } -//! -//! fn from_bytes() { -//! use util::bytes::FromBytes; -//! -//! let a = String::from_bytes(&[b'd', b'o', b'g']); -//! let b = 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::*; -/// TODO [Gav Wood] Please document me +/// 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); + +/// Slie pretty print helper pub struct PrettySlice<'a> (&'a [u8]); impl<'a> fmt::Debug for PrettySlice<'a> { @@ -166,223 +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 { - /// 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 })} -} - -impl <'a> ToBytes for &'a str { - fn to_bytes(&self) -> Vec { - From::from(*self) - } - - fn to_bytes_len(&self) -> usize { self.len() } -} - -impl ToBytes for String { - fn to_bytes(&self) -> Vec { - let s: &str = self.as_ref(); - From::from(s) - } - - fn to_bytes_len(&self) -> usize { self.len() } -} - -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); - } - 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_len(&self) -> usize { 1 } -} - -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_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) -> 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)); - } - res - } - 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) -> Vec { - let mut res: Vec = vec![]; - res.reserve(T::size()); - - unsafe { - use std::ptr; - ptr::copy(self.bytes().as_ptr(), res.as_mut_ptr(), T::size()); - res.set_len(T::size()); - } - - res - } -} - -/// Error returned when FromBytes conversation goes wrong -#[derive(Debug, PartialEq, Eq)] -pub enum FromBytesError { - /// 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/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..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)) }) } } @@ -199,7 +198,7 @@ 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) @@ -267,7 +266,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 +275,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/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/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 f6acdf180..f6101abc6 100644 --- a/util/src/rlp/mod.rs +++ b/util/src/rlp/mod.rs @@ -30,25 +30,22 @@ //! * 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}; +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,RlpStandard}; +pub use self::rlpstream::{RlpStream}; +pub use elastic_array::ElasticArray1024; use super::hash::H256; /// TODO [arkpar] Please document me @@ -72,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() } @@ -84,13 +81,13 @@ pub fn decode(bytes: &[u8]) -> T where T: Decodable { /// use util::rlp::*; /// /// fn main () { -/// let animals = vec!["cat", "dog"]; -/// let out = encode(&animals); -/// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); +/// let animal = "cat"; +/// let out = encode(&animal).to_vec(); +/// assert_eq!(out, vec![0x83, b'c', b'a', b't']); /// } /// ``` -pub fn encode(object: &E) -> Vec where E: Encodable { +pub fn encode(object: &E) -> ElasticArray1024 where E: RlpEncodable { let mut stream = RlpStream::new(); stream.append(object); - stream.out() + stream.drain() } 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 ac22736fc..b6b500a74 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 rlp::bytes::{ToBytes, VecLike}; use rlp::{Stream, Encoder, Encodable}; -use hash::H256; -use sha3::*; +use rlp::rlptraits::{ByteEncodable, RlpEncodable}; #[derive(Debug, Copy, Clone)] struct ListInfo { @@ -25,6 +25,7 @@ impl ListInfo { pub struct RlpStream { unfinished_lists: ElasticArray16, encoder: BasicEncoder, + finished_list: bool, } impl Stream for RlpStream { @@ -32,27 +33,27 @@ impl Stream for RlpStream { RlpStream { unfinished_lists: ElasticArray16::new(), encoder: BasicEncoder::new(), + finished_list: false, } } 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); - - // if list is finished, prepend the length - self.note_appended(1); - - // return chainable self + 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 { + self.note_appended(1); + } self } - fn append_list(&mut self, len: usize) -> &mut RlpStream { + 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 @@ -117,6 +118,21 @@ 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); + } + + 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 { @@ -141,6 +157,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. @@ -164,12 +181,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 +200,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 +231,82 @@ 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(); +impl ByteEncodable for T where T: ToBytes { + fn to_bytes>(&self, out: &mut V) { + ToBytes::to_bytes(self, out) + } - // insert all list elements - f(self); - - // 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); +struct U8Slice<'a>(&'a [u8]); - /// 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 U8Slice<'a> { + fn to_bytes>(&self, out: &mut V) { + out.vec_extend(self.0) } - /// 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.0.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<'a> Encodable for &'a[u8] { + fn rlp_append(&self, s: &mut RlpStream) { + s.append_value(&U8Slice(self)) } } -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) + fn rlp_append(&self, s: &mut RlpStream) { + s.append_value(&U8Slice(self.deref())) } } -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) + } +} + +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 d6ef16932..17acbb40b 100644 --- a/util/src/rlp/rlptraits.rs +++ b/util/src/rlp/rlptraits.rs @@ -1,4 +1,11 @@ +//! Common RLP traits +use std::ops::Deref; +use rlp::bytes::VecLike; use rlp::{DecoderError, UntrustedRlp}; +use rlp::rlpstream::RlpStream; +use elastic_array::ElasticArray1024; +use hash::H256; +use sha3::*; /// TODO [debris] Please document me pub trait Decoder: Sized { @@ -6,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; } @@ -195,26 +206,48 @@ 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 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. Implement this trait for 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() } +} + +/// 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 @@ -239,7 +272,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: RlpEncodable; /// Declare appending the list of given size, chainable. /// @@ -249,13 +282,13 @@ 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; /// Apends null to the end of stream, chainable. /// diff --git a/util/src/rlp/tests.rs b/util/src/rlp/tests.rs index 84c00e633..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()]); @@ -83,7 +83,7 @@ fn run_encode_tests(tests: Vec>) { for t in &tests { let res = rlp::encode(&t.0); - assert_eq!(res, &t.1[..]); + assert_eq!(&res[..], &t.1[..]); } } @@ -193,15 +193,9 @@ fn encode_vector_str() { 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); -} +struct DTestPair(T, Vec) where T: rlp::RlpDecodable + fmt::Debug + cmp::Eq; -struct DTestPair(T, Vec) where T: rlp::Decodable + 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); @@ -220,12 +214,21 @@ 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![ - 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); } @@ -233,9 +236,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); } @@ -243,9 +245,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); } @@ -333,7 +334,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() }; 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; 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 17d3f5866..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}; @@ -689,11 +688,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() }, } } @@ -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}, @@ -1040,7 +1038,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() {