From 36c586eb217f36dd77524c2ebd18da8742e86b15 Mon Sep 17 00:00:00 2001 From: debris Date: Tue, 8 Dec 2015 12:59:19 +0100 Subject: [PATCH] final changes in rlp refactor --- src/rlp/errors.rs | 29 + src/rlp/mod.rs | 13 +- src/rlp/old.rs | 1461 ------------------------------- src/rlp/rlp.rs | 3 +- src/rlp/rlpstream.rs | 2 +- src/rlp/tests.rs | 345 ++++++++ src/rlp/{faces.rs => traits.rs} | 30 +- src/rlp/untrusted_rlp.rs | 2 +- 8 files changed, 385 insertions(+), 1500 deletions(-) create mode 100644 src/rlp/errors.rs delete mode 100644 src/rlp/old.rs create mode 100644 src/rlp/tests.rs rename src/rlp/{faces.rs => traits.rs} (92%) diff --git a/src/rlp/errors.rs b/src/rlp/errors.rs new file mode 100644 index 000000000..ada3c2a47 --- /dev/null +++ b/src/rlp/errors.rs @@ -0,0 +1,29 @@ +use std::fmt; +use std::error::Error as StdError; +use bytes::FromBytesError; + +#[derive(Debug, PartialEq, Eq)] +pub enum DecoderError { + FromBytesError(FromBytesError), + RlpIsTooShort, + RlpExpectedToBeList, + RlpExpectedToBeData, +} + +impl StdError for DecoderError { + fn description(&self) -> &str { + "builder error" + } +} + +impl fmt::Display for DecoderError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self, f) + } +} + +impl From for DecoderError { + fn from(err: FromBytesError) -> DecoderError { + DecoderError::FromBytesError(err) + } +} diff --git a/src/rlp/mod.rs b/src/rlp/mod.rs index c7d657fa0..49043d65f 100644 --- a/src/rlp/mod.rs +++ b/src/rlp/mod.rs @@ -30,20 +30,21 @@ //! * You want to get view onto rlp-slice. //! * You don't want to decode whole rlp at once. -pub mod old; - -pub mod faces; +pub mod errors; +pub mod traits; pub mod rlp; pub mod untrusted_rlp; pub mod rlpstream; -pub use self::faces::{DecoderError, Decoder, Decodable, View, Stream, Encodable, Encoder}; +#[cfg(test)] +mod tests; + +pub use self::errors::DecoderError; +pub use self::traits::{Decoder, Decodable, View, Stream, Encodable, Encoder}; pub use self::rlp::{Rlp, RlpIterator}; pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, Prototype, PayloadInfo}; pub use self::rlpstream::{RlpStream}; -//pub use self::old::{encode, RlpStream, Encodable}; - /// Shortcut function to decode trusted rlp /// /// ```rust diff --git a/src/rlp/old.rs b/src/rlp/old.rs deleted file mode 100644 index 1c4147463..000000000 --- a/src/rlp/old.rs +++ /dev/null @@ -1,1461 +0,0 @@ -//! Rlp serialization module -//! -//! Allows encoding, decoding, and view onto rlp-slice -//! -//!# What should you use when? -//! -//!### Use `encode` function when: -//! * You want to encode something inline. -//! * You do not work on big set of data. -//! * You want to encode whole data structure at once. -//! -//!### Use `decode` function when: -//! * You want to decode something inline. -//! * You do not work on big set of data. -//! * You want to decode whole rlp at once. -//! -//!### Use `RlpStream` when: -//! * You want to encode something in portions. -//! * You encode a big set of data. -//! -//!### Use `Rlp` when: -//! * You are working on trusted data (not corrupted). -//! * You want to get view onto rlp-slice. -//! * You don't want to decode whole rlp at once. -//! -//!### Use `UntrustedRlp` when: -//! * You are working on untrusted data (~corrupted). -//! * You need to handle data corruption errors. -//! * You are working on input data. -//! * You want to get view onto rlp-slice. -//! * You don't want to decode whole rlp at once. - -use std::fmt; -use std::cell::Cell; -use std::ops::Deref; -use std::error::Error as StdError; -use elastic_array::*; -use bytes::{ToBytes, FromBytes, FromBytesError}; - -/// Data-oriented view onto rlp-slice. -/// -/// This is immutable structere. No operations change it. -/// -/// Should be used in places where, error handling is required, -/// eg. on input -#[derive(Debug)] -pub struct UntrustedRlp<'a> { - bytes: &'a [u8], - cache: Cell, -} - -/// rlp offset -#[derive(Copy, Clone, Debug)] -struct OffsetCache { - index: usize, - offset: usize, -} - -impl OffsetCache { - fn new(index: usize, offset: usize) -> OffsetCache { - OffsetCache { - index: index, - offset: offset, - } - } -} - -/// Stores basic information about item -pub struct PayloadInfo { - pub header_len: usize, - pub value_len: usize, -} - -impl PayloadInfo { - fn new(header_len: usize, value_len: usize) -> PayloadInfo { - PayloadInfo { - header_len: header_len, - value_len: value_len, - } - } -} - -#[derive(Debug, PartialEq, Eq)] -pub enum DecoderError { - FromBytesError(FromBytesError), - RlpIsTooShort, - RlpExpectedToBeList, - RlpExpectedToBeData, -} -impl StdError for DecoderError { - fn description(&self) -> &str { - "builder error" - } -} - -impl fmt::Display for DecoderError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self, f) - } -} - -impl From for DecoderError { - fn from(err: FromBytesError) -> DecoderError { - DecoderError::FromBytesError(err) - } -} - -/// Data-oriented view onto trusted rlp-slice. -/// -/// Unlikely to `UntrustedRlp` doesn't bother you with error -/// handling. It assumes that you know what you are doing. -pub struct Rlp<'a> { - rlp: UntrustedRlp<'a> -} - -//impl<'a> Deref for Rlp<'a> { - //type Target = UntrustedRlp<'a>; - - //fn deref(&self) -> &Self::Target { - //&self.rlp - //} -//} - -impl<'a> From> for Rlp<'a> { - fn from(rlp: UntrustedRlp<'a>) -> Rlp<'a> { - Rlp { rlp: rlp } - } -} - -impl<'a> From> for UntrustedRlp<'a> { - fn from(unsafe_rlp: Rlp<'a>) -> UntrustedRlp<'a> { - unsafe_rlp.rlp - } -} - -#[derive(Debug)] -pub enum Prototype { - Null, - Data(usize), - List(usize), -} - -impl<'a, 'view> Rlp<'a> where 'a: 'view { - /// Create a new instance of `Rlp` - pub fn new(bytes: &'a [u8]) -> Rlp<'a> { - Rlp { - rlp: UntrustedRlp::new(bytes) - } - } - - /// Get the prototype of the RLP. - pub fn prototype(&self) -> Prototype { - if self.is_data() { - Prototype::Data(self.size()) - } - else if self.is_list() { - Prototype::List(self.item_count()) - } - else { - Prototype::Null - } - } - - /// The raw data of the RLP. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let dog = rlp.at(1).raw(); - /// assert_eq!(dog, &[0x83, b'd', b'o', b'g']); - /// } - /// ``` - pub fn raw(&'view self) -> &'a [u8] { - self.rlp.raw() - } - - pub fn payload_info(&self) -> PayloadInfo { - self.rlp.payload_info().unwrap() - } - - pub fn data(&'view self) -> &'a [u8] { - self.rlp.data() - } - - /// Returns number of RLP items. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.item_count(), 2); - /// let view = rlp.at(1); - /// assert_eq!(view.item_count(), 0); - /// } - /// ``` - pub fn item_count(&self) -> usize { - self.rlp.item_count() - } - - /// Returns the number of bytes in the data, or zero if it isn't data. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.size(), 0); - /// let view = rlp.at(1); - /// assert_eq!(view.size(), 3); - /// } - /// ``` - pub fn size(&self) -> usize { - self.rlp.size() - } - - /// Get view onto RLP-slice at index. - /// - /// Caches offset to given index, so access to successive - /// slices is faster. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let dog = String::decode(&rlp.at(1)); - /// assert_eq!(dog, "dog".to_string()); - /// } - /// ``` - pub fn at(&'view self, index: usize) -> Rlp<'a> { - From::from(self.rlp.at(index).unwrap()) - } - - /// No value - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![]; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_null()); - /// } - /// ``` - pub fn is_null(&self) -> bool { - self.rlp.is_null() - } - - /// Contains a zero-length string or zero-length list. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc0]; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_empty()); - /// } - /// ``` - pub fn is_empty(&self) -> bool { - self.rlp.is_empty() - } - - /// List value - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.is_list()); - /// } - /// ``` - pub fn is_list(&self) -> bool { - self.rlp.is_list() - } - - /// String value - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// assert!(rlp.at(1).is_data()); - /// } - /// ``` - pub fn is_data(&self) -> bool { - self.rlp.is_data() - } - - /// Int value - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc1, 0x10]; - /// let rlp = Rlp::new(&data); - /// assert_eq!(rlp.is_int(), false); - /// assert_eq!(rlp.at(0).is_int(), true); - /// } - /// ``` - pub fn is_int(&self) -> bool { - self.rlp.is_int() - } - - /// Get iterator over rlp-slices - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = Rlp::new(&data); - /// let strings: Vec = rlp.iter().map(| i | String::decode(&i)).collect(); - /// } - /// ``` - pub fn iter(&'a self) -> RlpIterator<'a> { - self.into_iter() - } -} - -impl<'a, 'view> UntrustedRlp<'a> where 'a: 'view { - /// returns new instance of `UntrustedRlp` - pub fn new(bytes: &'a [u8]) -> UntrustedRlp<'a> { - UntrustedRlp { - bytes: bytes, - cache: Cell::new(OffsetCache::new(usize::max_value(), 0)), - } - } - - /// The bare data of the RLP. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = UntrustedRlp::new(&data); - /// let dog = rlp.at(1).unwrap().raw(); - /// assert_eq!(dog, &[0x83, b'd', b'o', b'g']); - /// } - /// ``` - pub fn raw(&'view self) -> &'a [u8] { - self.bytes - } - - pub fn payload_info(&self) -> Result { - BasicDecoder::payload_info(self.bytes) - } - - pub fn data(&'view self) -> &'a [u8] { - let ii = BasicDecoder::payload_info(self.bytes).unwrap(); - &self.bytes[ii.header_len..(ii.header_len + ii.value_len)] - } - - /// Returns number of rlp items. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = UntrustedRlp::new(&data); - /// assert_eq!(rlp.item_count(), 2); - /// let view = rlp.at(1).unwrap(); - /// assert_eq!(view.item_count(), 0); - /// } - /// ``` - pub fn item_count(&self) -> usize { - match self.is_list() { - true => self.iter().count(), - false => 0 - } - } - - /// Returns the number of bytes in the data, or zero if it isn't data. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = UntrustedRlp::new(&data); - /// assert_eq!(rlp.size(), 0); - /// let view = rlp.at(1).unwrap(); - /// assert_eq!(view.size(), 3); - /// } - /// ``` - pub fn size(&self) -> usize { - match self.is_data() { - true => BasicDecoder::payload_info(self.bytes).unwrap().value_len, - false => 0 - } - } - - /// Get view onto rlp-slice at index - /// - /// Caches offset to given index, so access to successive - /// slices is faster. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = UntrustedRlp::new(&data); - /// let dog = String::decode_untrusted(&rlp.at(1).unwrap()).unwrap(); - /// assert_eq!(dog, "dog".to_string()); - /// } - /// ``` - pub fn at(&'view self, index: usize) -> Result, DecoderError> { - if !self.is_list() { - return Err(DecoderError::RlpExpectedToBeList); - } - - // move to cached position if it's index is less or equal to - // current search index, otherwise move to beginning of list - let c = self.cache.get(); - let (mut bytes, to_skip) = match c.index <= index { - true => (try!(UntrustedRlp::consume(self.bytes, c.offset)), index - c.index), - false => (try!(self.consume_list_prefix()), index), - }; - - // skip up to x items - bytes = try!(UntrustedRlp::consume_items(bytes, to_skip)); - - // update the cache - self.cache.set(OffsetCache::new(index, self.bytes.len() - bytes.len())); - - // construct new rlp - let found = try!(BasicDecoder::payload_info(bytes)); - Ok(UntrustedRlp::new(&bytes[0..found.header_len + found.value_len])) - } - - /// No value - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![]; - /// let rlp = UntrustedRlp::new(&data); - /// assert!(rlp.is_null()); - /// } - /// ``` - pub fn is_null(&self) -> bool { - self.bytes.len() == 0 - } - - /// Contains a zero-length string or zero-length list. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc0]; - /// let rlp = UntrustedRlp::new(&data); - /// assert!(rlp.is_empty()); - /// } - /// ``` - pub fn is_empty(&self) -> bool { - !self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80) - } - - /// List value - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = UntrustedRlp::new(&data); - /// assert!(rlp.is_list()); - /// } - /// ``` - pub fn is_list(&self) -> bool { - !self.is_null() && self.bytes[0] >= 0xc0 - } - - /// String value - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = UntrustedRlp::new(&data); - /// assert!(rlp.at(1).unwrap().is_data()); - /// } - /// ``` - pub fn is_data(&self) -> bool { - !self.is_null() && self.bytes[0] < 0xc0 - } - - /// Int value - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc1, 0x10]; - /// let rlp = UntrustedRlp::new(&data); - /// assert_eq!(rlp.is_int(), false); - /// assert_eq!(rlp.at(0).unwrap().is_int(), true); - /// } - /// ``` - pub fn is_int(&self) -> bool { - if self.is_null() { - return false; - } - - match self.bytes[0] { - 0...0x80 => true, - 0x81...0xb7 => self.bytes[1] != 0, - b @ 0xb8...0xbf => self.bytes[1 + b as usize - 0xb7] != 0, - _ => false - } - } - - /// Get iterator over rlp-slices - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - /// let rlp = UntrustedRlp::new(&data); - /// let strings: Vec = rlp.iter() - /// .map(| i | String::decode_untrusted(&i)) - /// .map(| s | s.unwrap()) - /// .collect(); - /// } - /// ``` - pub fn iter(&'a self) -> UntrustedRlpIterator<'a> { - self.into_iter() - } - - /// consumes first found prefix - fn consume_list_prefix(&self) -> Result<&'a [u8], DecoderError> { - let item = try!(BasicDecoder::payload_info(self.bytes)); - let bytes = try!(UntrustedRlp::consume(self.bytes, item.header_len)); - Ok(bytes) - } - - /// consumes fixed number of items - fn consume_items(bytes: &'a [u8], items: usize) -> Result<&'a [u8], DecoderError> { - let mut result = bytes; - for _ in 0..items { - let i = try!(BasicDecoder::payload_info(result)); - result = try!(UntrustedRlp::consume(result, (i.header_len + i.value_len))); - } - Ok(result) - } - - - /// consumes slice prefix of length `len` - fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> { - match bytes.len() >= len { - true => Ok(&bytes[len..]), - false => Err(DecoderError::RlpIsTooShort), - } - } -} - -/// Iterator over rlp-slice list elements. -pub struct UntrustedRlpIterator<'a> { - rlp: &'a UntrustedRlp<'a>, - index: usize, -} - -impl<'a> IntoIterator for &'a UntrustedRlp<'a> { - type Item = UntrustedRlp<'a>; - type IntoIter = UntrustedRlpIterator<'a>; - - fn into_iter(self) -> Self::IntoIter { - UntrustedRlpIterator { - rlp: self, - index: 0, - } - } -} - -impl<'a> Iterator for UntrustedRlpIterator<'a> { - type Item = UntrustedRlp<'a>; - - fn next(&mut self) -> Option> { - let index = self.index; - let result = self.rlp.at(index).ok(); - self.index += 1; - result - } -} - -/// Iterator over trusted rlp-slice list elements. -pub struct RlpIterator<'a> { - rlp: &'a Rlp<'a>, - index: usize -} - -impl<'a> IntoIterator for &'a Rlp<'a> { - type Item = Rlp<'a>; - type IntoIter = RlpIterator<'a>; - - fn into_iter(self) -> Self::IntoIter { - RlpIterator { - rlp: self, - index: 0, - } - } -} - -impl<'a> Iterator for RlpIterator<'a> { - type Item = Rlp<'a>; - - fn next(&mut self) -> Option> { - let index = self.index; - let result = self.rlp.rlp.at(index).ok().map(| iter | { From::from(iter) }); - self.index += 1; - result - } -} - -/// Shortcut function to decode trusted rlp -/// -/// ```rust -/// extern crate ethcore_util as util; -/// use util::rlp::*; -/// -/// fn main () { -/// let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; -/// let animals: Vec = decode(&data); -/// assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]); -/// } -/// ``` -pub fn decode(bytes: &[u8]) -> T where T: Decodable { - let rlp = Rlp::new(bytes); - T::decode(&rlp) -} - -pub trait Decodable: Sized { - fn decode_untrusted(rlp: &UntrustedRlp) -> Result; - fn decode(rlp: &Rlp) -> Self { - Self::decode_untrusted(&rlp.rlp).unwrap() - } -} - -impl Decodable for T where T: FromBytes { - fn decode_untrusted(rlp: &UntrustedRlp) -> Result { - match rlp.is_data() { - true => BasicDecoder::read_value(rlp.bytes, | bytes | { - Ok(try!(T::from_bytes(bytes))) - }), - false => Err(DecoderError::RlpExpectedToBeData), - } - } -} - -impl Decodable for Vec where T: Decodable { - fn decode_untrusted(rlp: &UntrustedRlp) -> Result { - match rlp.is_list() { - true => rlp.iter().map(|rlp| T::decode_untrusted(&rlp)).collect(), - false => Err(DecoderError::RlpExpectedToBeList), - } - } -} - -impl Decodable for Vec { - fn decode_untrusted(rlp: &UntrustedRlp) -> Result { - match rlp.is_data() { - true => BasicDecoder::read_value(rlp.bytes, | bytes | { - let mut res = vec![]; - res.extend(bytes); - Ok(res) - }), - false => Err(DecoderError::RlpExpectedToBeData), - } - } -} - -pub trait Decoder { - fn read_value(bytes: &[u8], f: F) -> Result where F: FnOnce(&[u8]) -> Result; -} - -struct BasicDecoder; - -impl BasicDecoder { - /// Return first item info - fn payload_info(bytes: &[u8]) -> Result { - let item = match bytes.first().map(|&x| x) { - None => return Err(DecoderError::RlpIsTooShort), - Some(0...0x7f) => PayloadInfo::new(0, 1), - Some(l @ 0x80...0xb7) => PayloadInfo::new(1, l as usize - 0x80), - Some(l @ 0xb8...0xbf) => { - let len_of_len = l as usize - 0xb7; - let header_len = 1 + len_of_len; - let value_len = try!(usize::from_bytes(&bytes[1..header_len])); - PayloadInfo::new(header_len, value_len) - } - Some(l @ 0xc0...0xf7) => PayloadInfo::new(1, l as usize - 0xc0), - Some(l @ 0xf8...0xff) => { - let len_of_len = l as usize - 0xf7; - let header_len = 1 + len_of_len; - let value_len = try!(usize::from_bytes(&bytes[1..header_len])); - PayloadInfo::new(header_len, value_len) - }, - // we cant reach this place, but rust requires _ to be implemented - _ => { panic!(); } - }; - - match item.header_len + item.value_len <= bytes.len() { - true => Ok(item), - false => Err(DecoderError::RlpIsTooShort), - } - } -} - -impl Decoder for BasicDecoder { - fn read_value(bytes: &[u8], f: F) -> Result where F: FnOnce(&[u8]) -> Result { - match bytes.first().map(|&x| x) { - // rlp is too short - None => Err(DecoderError::RlpIsTooShort), - // single byt value - Some(l @ 0...0x7f) => Ok(try!(f(&[l]))), - // 0-55 bytes - Some(l @ 0x80...0xb7) => Ok(try!(f(&bytes[1..(1 + l as usize - 0x80)]))), - // longer than 55 bytes - Some(l @ 0xb8...0xbf) => { - let len_of_len = l as usize - 0xb7; - let begin_of_value = 1 as usize + len_of_len; - let len = try!(usize::from_bytes(&bytes[1..begin_of_value])); - Ok(try!(f(&bytes[begin_of_value..begin_of_value + len]))) - } - // we are reading value, not a list! - _ => { panic!(); } - } - } -} - -#[derive(Debug, Copy, Clone)] -struct ListInfo { - position: usize, - current: usize, - max: usize, -} - -impl ListInfo { - fn new(position: usize, max: usize) -> ListInfo { - ListInfo { - position: position, - current: 0, - max: max, - } - } -} - -/// Appendable rlp encoder. -pub struct RlpStream { - unfinished_lists: ElasticArray16, - encoder: BasicEncoder, -} - -impl RlpStream { - /// Initializes instance of empty `RlpStream`. - pub fn new() -> RlpStream { - RlpStream { - unfinished_lists: ElasticArray16::new(), - encoder: BasicEncoder::new(), - } - } - - /// Initializes the `RLPStream` as a list. - pub fn new_list(len: usize) -> RlpStream { - let mut stream = RlpStream::new(); - stream.append_list(len); - stream - } - - /// Apends value to the end of stream, chainable. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let mut stream = RlpStream::new_list(2); - /// stream.append(&"cat").append(&"dog"); - /// let out = stream.out(); - /// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); - /// } - /// ``` - pub fn append<'a, E>(&'a mut self, object: &E) -> &'a 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 - self - } - - /// Declare appending the list of given size, chainable. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let mut stream = RlpStream::new_list(2); - /// stream.append_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]); - /// } - /// ``` - pub fn append_list<'a>(&'a mut self, len: usize) -> &'a mut RlpStream { - match len { - 0 => { - // we may finish, if the appended list len is equal 0 - self.encoder.bytes.push(0xc0u8); - self.note_appended(1); - }, - _ => { - let position = self.encoder.bytes.len(); - self.unfinished_lists.push(ListInfo::new(position, len)); - }, - } - - // return chainable self - self - } - - /// Apends null to the end of stream, chainable. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let mut stream = RlpStream::new_list(2); - /// stream.append_empty_data().append_empty_data(); - /// let out = stream.out(); - /// assert_eq!(out, vec![0xc2, 0x80, 0x80]); - /// } - /// ``` - pub fn append_empty_data<'a>(&'a mut self) -> &'a mut RlpStream { - // self push raw item - self.encoder.bytes.push(0x80); - - // try to finish and prepend the length - self.note_appended(1); - - // return chainable self - self - } - - /// Appends raw (pre-serialised) RLP data. Use with caution. Chainable. - pub fn append_raw<'a>(&'a mut self, bytes: &[u8], item_count: usize) -> &'a mut RlpStream { - // push raw items - self.encoder.bytes.append_slice(bytes); - - // try to finish and prepend the length - self.note_appended(item_count); - - // return chainable self - self - } - - /// Clear the output stream so far. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let mut stream = RlpStream::new_list(3); - /// stream.append(&"cat"); - /// stream.clear(); - /// stream.append(&"dog"); - /// let out = stream.out(); - /// assert_eq!(out, vec![0x83, b'd', b'o', b'g']); - /// } - pub fn clear(&mut self) { - // clear bytes - self.encoder.bytes.clear(); - - // clear lists - self.unfinished_lists.clear(); - } - - /// Returns true if stream doesnt expect any more items. - /// - /// ```rust - /// extern crate ethcore_util as util; - /// use util::rlp::*; - /// - /// fn main () { - /// let mut stream = RlpStream::new_list(2); - /// stream.append(&"cat"); - /// assert_eq!(stream.is_finished(), false); - /// stream.append(&"dog"); - /// assert_eq!(stream.is_finished(), true); - /// let out = stream.out(); - /// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); - /// } - pub fn is_finished(&self) -> bool { - self.unfinished_lists.len() == 0 - } - - /// Streams out encoded bytes. - /// - /// panic! if stream is not finished. - pub fn out(self) -> Vec { - match self.is_finished() { - true => self.encoder.out().to_vec(), - false => panic!() - } - } - - /// Try to finish lists - fn note_appended(&mut self, inserted_items: usize) -> () { - if self.unfinished_lists.len() == 0 { - return; - } - - let back = self.unfinished_lists.len() - 1; - let should_finish = match self.unfinished_lists.get_mut(back) { - None => false, - Some(ref mut x) => { - x.current += inserted_items; - if x.current > x.max { - panic!("You cannot append more items then you expect!"); - } - x.current == x.max - } - }; - - if should_finish { - let x = self.unfinished_lists.pop().unwrap(); - let len = self.encoder.bytes.len() - x.position; - self.encoder.insert_list_len_at_pos(len, x.position); - self.note_appended(1); - } - } -} - -/// Shortcut function to encode structure into rlp. -/// -/// ```rust -/// extern crate ethcore_util as util; -/// 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']); -/// } -/// ``` -pub fn encode(object: &E) -> Vec where E: Encodable -{ - let mut encoder = BasicEncoder::new(); - object.encode(&mut encoder); - encoder.out().to_vec() -} - -pub trait Encodable { - fn encode(&self, encoder: &mut E) -> () where E: Encoder; -} - -pub trait Encoder { - fn emit_value(&mut self, bytes: &[u8]) -> (); - fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> (); -} - -impl Encodable for T where T: ToBytes { - fn encode(&self, encoder: &mut E) -> () where E: Encoder { - encoder.emit_value(&self.to_bytes()) - } -} - -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 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) - } -} - -struct BasicEncoder { - bytes: ElasticArray1024, -} - -impl BasicEncoder { - fn new() -> BasicEncoder { - BasicEncoder { bytes: ElasticArray1024::new() } - } - - /// 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![]; - match len { - 0...55 => res.push(0xc0u8 + len as u8), - _ => { - res.push(0xf7u8 + len.to_bytes_len() as u8); - res.extend(len.to_bytes()); - } - }; - - self.bytes.insert_slice(pos, &res); - } - - /// get encoded value - fn out(self) -> ElasticArray1024 { - self.bytes - } -} - -impl Encoder for BasicEncoder { - fn emit_value(&mut self, bytes: &[u8]) -> () { - match bytes.len() { - // just 0 - 0 => self.bytes.push(0x80u8), - // byte is its own encoding - 1 if bytes[0] < 0x80 => self.bytes.append_slice(bytes), - // (prefix + length), followed by the string - len @ 1 ... 55 => { - self.bytes.push(0x80u8 + len as u8); - self.bytes.append_slice(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); - } - } - } - - 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); - - // 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); - } -} - -#[cfg(test)] -mod tests { - extern crate json_tests; - use self::json_tests::execute_tests_from_directory; - use self::json_tests::rlp as rlptest; - use std::{fmt, cmp}; - use std::str::FromStr; - use rlp; - use rlp::{UntrustedRlp, RlpStream, Decodable, View, Stream, Encodable}; - use uint::U256; - - #[test] - fn rlp_at() { - let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - { - let rlp = UntrustedRlp::new(&data); - assert!(rlp.is_list()); - //let animals = as rlp::Decodable>::decode_untrusted(&rlp).unwrap(); - let animals: Vec = rlp.as_val().unwrap(); - assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]); - - let cat = rlp.at(0).unwrap(); - assert!(cat.is_data()); - assert_eq!(cat.raw(), &[0x83, b'c', b'a', b't']); - //assert_eq!(String::decode_untrusted(&cat).unwrap(), "cat".to_string()); - assert_eq!(cat.as_val::().unwrap(), "cat".to_string()); - - let dog = rlp.at(1).unwrap(); - assert!(dog.is_data()); - assert_eq!(dog.raw(), &[0x83, b'd', b'o', b'g']); - //assert_eq!(String::decode_untrusted(&dog).unwrap(), "dog".to_string()); - assert_eq!(dog.as_val::().unwrap(), "dog".to_string()); - - let cat_again = rlp.at(0).unwrap(); - assert!(cat_again.is_data()); - assert_eq!(cat_again.raw(), &[0x83, b'c', b'a', b't']); - //assert_eq!(String::decode_untrusted(&cat_again).unwrap(), "cat".to_string()); - assert_eq!(cat_again.as_val::().unwrap(), "cat".to_string()); - } - } - - #[test] - fn rlp_at_err() { - let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o']; - { - let rlp = UntrustedRlp::new(&data); - assert!(rlp.is_list()); - - let cat_err = rlp.at(0).unwrap_err(); - assert_eq!(cat_err, rlp::DecoderError::RlpIsTooShort); - - let dog_err = rlp.at(1).unwrap_err(); - assert_eq!(dog_err, rlp::DecoderError::RlpIsTooShort); - } - } - - #[test] - fn rlp_iter() { - let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; - { - let rlp = UntrustedRlp::new(&data); - let mut iter = rlp.iter(); - - let cat = iter.next().unwrap(); - assert!(cat.is_data()); - assert_eq!(cat.raw(), &[0x83, b'c', b'a', b't']); - - let dog = iter.next().unwrap(); - assert!(dog.is_data()); - assert_eq!(dog.raw(), &[0x83, b'd', b'o', b'g']); - - let none = iter.next(); - assert!(none.is_none()); - - let cat_again = rlp.at(0).unwrap(); - assert!(cat_again.is_data()); - assert_eq!(cat_again.raw(), &[0x83, b'c', b'a', b't']); - } - } - - struct ETestPair(T, 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[..]); - } - } - - #[test] - fn encode_u16() { - let tests = vec![ - ETestPair(0u16, vec![0x80u8]), - ETestPair(0x100, vec![0x82, 0x01, 0x00]), - ETestPair(0xffff, vec![0x82, 0xff, 0xff]), - ]; - run_encode_tests(tests); - } - - #[test] - fn encode_u32() { - let tests = vec![ - ETestPair(0u32, vec![0x80u8]), - ETestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]), - ETestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]), - ]; - run_encode_tests(tests); - } - - #[test] - fn encode_u64() { - let tests = vec![ - ETestPair(0u64, vec![0x80u8]), - ETestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]), - ETestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]), - ]; - run_encode_tests(tests); - } - - #[test] - fn encode_u256() { - let tests = vec![ETestPair(U256::from(0u64), vec![0x80u8]), - ETestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), - ETestPair(U256::from(0xffffffffu64), - vec![0x84, 0xff, 0xff, 0xff, 0xff]), - ETestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000\ - 000100000000000012f0") - .unwrap(), - vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, - 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])]; - run_encode_tests(tests); - } - - #[test] - fn encode_str() { - let tests = vec![ETestPair("cat", vec![0x83, b'c', b'a', b't']), - ETestPair("dog", vec![0x83, b'd', b'o', b'g']), - ETestPair("Marek", vec![0x85, b'M', b'a', b'r', b'e', b'k']), - ETestPair("", vec![0x80]), - ETestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit", - vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', - b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', - b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', - b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c', - b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i', - b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ', - b'e', b'l', b'i', b't'])]; - run_encode_tests(tests); - } - - #[test] - fn encode_address() { - use hash::*; - - let tests = vec![ - ETestPair(Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(), - vec![0x94, 0xef, 0x2d, 0x6d, 0x19, 0x40, 0x84, 0xc2, 0xde, - 0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46, - 0xb3, 0x7d, 0x11, 0x06]) - ]; - run_encode_tests(tests); - } - - /// Vec (Bytes) is treated as a single value - #[test] - fn encode_vector_u8() { - let tests = vec![ - ETestPair(vec![], vec![0x80]), - ETestPair(vec![0u8], vec![0]), - ETestPair(vec![0x15], vec![0x15]), - ETestPair(vec![0x40, 0x00], vec![0x82, 0x40, 0x00]), - ]; - run_encode_tests(tests); - } - - #[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]), - ]; - run_encode_tests(tests); - } - - #[test] - fn encode_vector_str() { - 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_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::Decodable + fmt::Debug + cmp::Eq; - - fn run_decode_tests(tests: Vec>) where T: rlp::Decodable + fmt::Debug + cmp::Eq { - for t in &tests { - let res: T = rlp::decode(&t.1); - assert_eq!(res, t.0); - } - } - - /// Vec (Bytes) is treated as a single value - #[test] - fn decode_vector_u8() { - let tests = vec![ - DTestPair(vec![], vec![0x80]), - DTestPair(vec![0u8], vec![0]), - DTestPair(vec![0x15], vec![0x15]), - DTestPair(vec![0x40, 0x00], vec![0x82, 0x40, 0x00]), - ]; - 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]), - ]; - run_decode_tests(tests); - } - - #[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]), - ]; - run_decode_tests(tests); - } - - #[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]), - ]; - run_decode_tests(tests); - } - - #[test] - fn decode_untrusted_u256() { - let tests = vec![DTestPair(U256::from(0u64), vec![0x80u8]), - DTestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), - DTestPair(U256::from(0xffffffffu64), - vec![0x84, 0xff, 0xff, 0xff, 0xff]), - DTestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000\ - 000100000000000012f0") - .unwrap(), - vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, - 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])]; - run_decode_tests(tests); - } - - #[test] - fn decode_untrusted_str() { - let tests = vec![DTestPair("cat".to_string(), vec![0x83, b'c', b'a', b't']), - DTestPair("dog".to_string(), vec![0x83, b'd', b'o', b'g']), - DTestPair("Marek".to_string(), - vec![0x85, b'M', b'a', b'r', b'e', b'k']), - DTestPair("".to_string(), vec![0x80]), - DTestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit" - .to_string(), - vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', - b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', - b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', - b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c', - b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i', - b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ', - b'e', b'l', b'i', b't'])]; - run_decode_tests(tests); - } - - #[test] - fn decode_untrusted_address() { - use hash::*; - - let tests = vec![ - DTestPair(Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(), - vec![0x94, 0xef, 0x2d, 0x6d, 0x19, 0x40, 0x84, 0xc2, 0xde, - 0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46, - 0xb3, 0x7d, 0x11, 0x06]) - ]; - run_decode_tests(tests); - } - - #[test] - fn decode_untrusted_vector_u64() { - let tests = vec![ - DTestPair(vec![], vec![0xc0]), - DTestPair(vec![15u64], vec![0xc1, 0x0f]), - DTestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), - DTestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), - ]; - run_decode_tests(tests); - } - - #[test] - fn decode_untrusted_vector_str() { - let tests = vec![DTestPair(vec!["cat".to_string(), "dog".to_string()], - vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; - run_decode_tests(tests); - } - - #[test] - fn decode_untrusted_vector_of_vectors_str() { - let tests = vec![DTestPair(vec![vec!["cat".to_string()]], - vec![0xc5, 0xc4, 0x83, b'c', b'a', b't'])]; - run_decode_tests(tests); - } - - #[test] - fn test_rlp_json() { - println!("Json rlp test: "); - execute_tests_from_directory::("json-tests/json/rlp/stream/*.json", &mut | file, input, output | { - println!("file: {}", file); - - let mut stream = RlpStream::new(); - 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::AppendRaw(ref raw, len) => stream.append_raw(raw, len), - rlptest::Operation::AppendEmpty => stream.append_empty_data() - }; - } - - assert_eq!(stream.out(), output); - }); - } - -} diff --git a/src/rlp/rlp.rs b/src/rlp/rlp.rs index 2effb7297..ce43c10a5 100644 --- a/src/rlp/rlp.rs +++ b/src/rlp/rlp.rs @@ -1,5 +1,4 @@ -use super::faces::{View, Decodable, DecoderError}; -use super::untrusted_rlp::*; +use rlp::{View, Decodable, DecoderError, UntrustedRlp, PayloadInfo, Prototype}; impl<'a> From> for Rlp<'a> { fn from(rlp: UntrustedRlp<'a>) -> Rlp<'a> { diff --git a/src/rlp/rlpstream.rs b/src/rlp/rlpstream.rs index 379852083..557c4af25 100644 --- a/src/rlp/rlpstream.rs +++ b/src/rlp/rlpstream.rs @@ -1,6 +1,6 @@ use elastic_array::*; use bytes::ToBytes; -use super::faces::{Stream, Encoder, Encodable}; +use rlp::{Stream, Encoder, Encodable}; #[derive(Debug, Copy, Clone)] struct ListInfo { diff --git a/src/rlp/tests.rs b/src/rlp/tests.rs new file mode 100644 index 000000000..e44953e07 --- /dev/null +++ b/src/rlp/tests.rs @@ -0,0 +1,345 @@ +extern crate json_tests; +use self::json_tests::execute_tests_from_directory; +use self::json_tests::rlp as rlptest; +use std::{fmt, cmp}; +use std::str::FromStr; +use rlp; +use rlp::{UntrustedRlp, RlpStream, Decodable, View, Stream, Encodable}; +use uint::U256; + +#[test] +fn rlp_at() { + let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; + { + let rlp = UntrustedRlp::new(&data); + assert!(rlp.is_list()); + //let animals = as rlp::Decodable>::decode_untrusted(&rlp).unwrap(); + let animals: Vec = rlp.as_val().unwrap(); + assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]); + + let cat = rlp.at(0).unwrap(); + assert!(cat.is_data()); + assert_eq!(cat.raw(), &[0x83, b'c', b'a', b't']); + //assert_eq!(String::decode_untrusted(&cat).unwrap(), "cat".to_string()); + assert_eq!(cat.as_val::().unwrap(), "cat".to_string()); + + let dog = rlp.at(1).unwrap(); + assert!(dog.is_data()); + assert_eq!(dog.raw(), &[0x83, b'd', b'o', b'g']); + //assert_eq!(String::decode_untrusted(&dog).unwrap(), "dog".to_string()); + assert_eq!(dog.as_val::().unwrap(), "dog".to_string()); + + let cat_again = rlp.at(0).unwrap(); + assert!(cat_again.is_data()); + assert_eq!(cat_again.raw(), &[0x83, b'c', b'a', b't']); + //assert_eq!(String::decode_untrusted(&cat_again).unwrap(), "cat".to_string()); + assert_eq!(cat_again.as_val::().unwrap(), "cat".to_string()); + } +} + +#[test] +fn rlp_at_err() { + let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o']; + { + let rlp = UntrustedRlp::new(&data); + assert!(rlp.is_list()); + + let cat_err = rlp.at(0).unwrap_err(); + assert_eq!(cat_err, rlp::DecoderError::RlpIsTooShort); + + let dog_err = rlp.at(1).unwrap_err(); + assert_eq!(dog_err, rlp::DecoderError::RlpIsTooShort); + } +} + +#[test] +fn rlp_iter() { + let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']; + { + let rlp = UntrustedRlp::new(&data); + let mut iter = rlp.iter(); + + let cat = iter.next().unwrap(); + assert!(cat.is_data()); + assert_eq!(cat.raw(), &[0x83, b'c', b'a', b't']); + + let dog = iter.next().unwrap(); + assert!(dog.is_data()); + assert_eq!(dog.raw(), &[0x83, b'd', b'o', b'g']); + + let none = iter.next(); + assert!(none.is_none()); + + let cat_again = rlp.at(0).unwrap(); + assert!(cat_again.is_data()); + assert_eq!(cat_again.raw(), &[0x83, b'c', b'a', b't']); + } +} + +struct ETestPair(T, 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[..]); + } +} + +#[test] +fn encode_u16() { + let tests = vec![ + ETestPair(0u16, vec![0x80u8]), + ETestPair(0x100, vec![0x82, 0x01, 0x00]), + ETestPair(0xffff, vec![0x82, 0xff, 0xff]), + ]; + run_encode_tests(tests); +} + +#[test] +fn encode_u32() { + let tests = vec![ + ETestPair(0u32, vec![0x80u8]), + ETestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]), + ETestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]), + ]; + run_encode_tests(tests); +} + +#[test] +fn encode_u64() { + let tests = vec![ + ETestPair(0u64, vec![0x80u8]), + ETestPair(0x1000000, vec![0x84, 0x01, 0x00, 0x00, 0x00]), + ETestPair(0xFFFFFFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]), + ]; + run_encode_tests(tests); +} + +#[test] +fn encode_u256() { + let tests = vec![ETestPair(U256::from(0u64), vec![0x80u8]), + ETestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + ETestPair(U256::from(0xffffffffu64), + vec![0x84, 0xff, 0xff, 0xff, 0xff]), + ETestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000\ + 000100000000000012f0") + .unwrap(), + vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])]; + run_encode_tests(tests); +} + +#[test] +fn encode_str() { + let tests = vec![ETestPair("cat", vec![0x83, b'c', b'a', b't']), + ETestPair("dog", vec![0x83, b'd', b'o', b'g']), + ETestPair("Marek", vec![0x85, b'M', b'a', b'r', b'e', b'k']), + ETestPair("", vec![0x80]), + ETestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit", + vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', + b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', + b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', + b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c', + b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i', + b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ', + b'e', b'l', b'i', b't'])]; + run_encode_tests(tests); +} + +#[test] +fn encode_address() { + use hash::*; + + let tests = vec![ + ETestPair(Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(), + vec![0x94, 0xef, 0x2d, 0x6d, 0x19, 0x40, 0x84, 0xc2, 0xde, + 0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46, + 0xb3, 0x7d, 0x11, 0x06]) + ]; + run_encode_tests(tests); +} + +/// Vec (Bytes) is treated as a single value +#[test] +fn encode_vector_u8() { + let tests = vec![ + ETestPair(vec![], vec![0x80]), + ETestPair(vec![0u8], vec![0]), + ETestPair(vec![0x15], vec![0x15]), + ETestPair(vec![0x40, 0x00], vec![0x82, 0x40, 0x00]), + ]; + run_encode_tests(tests); +} + +#[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]), + ]; + run_encode_tests(tests); +} + +#[test] +fn encode_vector_str() { + 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_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::Decodable + fmt::Debug + cmp::Eq; + +fn run_decode_tests(tests: Vec>) where T: rlp::Decodable + fmt::Debug + cmp::Eq { + for t in &tests { + let res: T = rlp::decode(&t.1); + assert_eq!(res, t.0); + } +} + +/// Vec (Bytes) is treated as a single value +#[test] +fn decode_vector_u8() { + let tests = vec![ + DTestPair(vec![], vec![0x80]), + DTestPair(vec![0u8], vec![0]), + DTestPair(vec![0x15], vec![0x15]), + DTestPair(vec![0x40, 0x00], vec![0x82, 0x40, 0x00]), + ]; + 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]), + ]; + run_decode_tests(tests); +} + +#[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]), + ]; + run_decode_tests(tests); +} + +#[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]), + ]; + run_decode_tests(tests); +} + +#[test] +fn decode_untrusted_u256() { + let tests = vec![DTestPair(U256::from(0u64), vec![0x80u8]), + DTestPair(U256::from(0x1000000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + DTestPair(U256::from(0xffffffffu64), + vec![0x84, 0xff, 0xff, 0xff, 0xff]), + DTestPair(U256::from_str("8090a0b0c0d0e0f00910203040506077000000000000\ + 000100000000000012f0") + .unwrap(), + vec![0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, + 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0])]; + run_decode_tests(tests); +} + +#[test] +fn decode_untrusted_str() { + let tests = vec![DTestPair("cat".to_string(), vec![0x83, b'c', b'a', b't']), + DTestPair("dog".to_string(), vec![0x83, b'd', b'o', b'g']), + DTestPair("Marek".to_string(), + vec![0x85, b'M', b'a', b'r', b'e', b'k']), + DTestPair("".to_string(), vec![0x80]), + DTestPair("Lorem ipsum dolor sit amet, consectetur adipisicing elit" + .to_string(), + vec![0xb8, 0x38, b'L', b'o', b'r', b'e', b'm', b' ', b'i', + b'p', b's', b'u', b'm', b' ', b'd', b'o', b'l', b'o', + b'r', b' ', b's', b'i', b't', b' ', b'a', b'm', b'e', + b't', b',', b' ', b'c', b'o', b'n', b's', b'e', b'c', + b't', b'e', b't', b'u', b'r', b' ', b'a', b'd', b'i', + b'p', b'i', b's', b'i', b'c', b'i', b'n', b'g', b' ', + b'e', b'l', b'i', b't'])]; + run_decode_tests(tests); +} + +#[test] +fn decode_untrusted_address() { + use hash::*; + + let tests = vec![ + DTestPair(Address::from_str("ef2d6d194084c2de36e0dabfce45d046b37d1106").unwrap(), + vec![0x94, 0xef, 0x2d, 0x6d, 0x19, 0x40, 0x84, 0xc2, 0xde, + 0x36, 0xe0, 0xda, 0xbf, 0xce, 0x45, 0xd0, 0x46, + 0xb3, 0x7d, 0x11, 0x06]) + ]; + run_decode_tests(tests); +} + +#[test] +fn decode_untrusted_vector_u64() { + let tests = vec![ + DTestPair(vec![], vec![0xc0]), + DTestPair(vec![15u64], vec![0xc1, 0x0f]), + DTestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), + DTestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), + ]; + run_decode_tests(tests); +} + +#[test] +fn decode_untrusted_vector_str() { + let tests = vec![DTestPair(vec!["cat".to_string(), "dog".to_string()], + vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; + run_decode_tests(tests); +} + +#[test] +fn decode_untrusted_vector_of_vectors_str() { + let tests = vec![DTestPair(vec![vec!["cat".to_string()]], + vec![0xc5, 0xc4, 0x83, b'c', b'a', b't'])]; + run_decode_tests(tests); +} + +#[test] +fn test_rlp_json() { + println!("Json rlp test: "); + execute_tests_from_directory::("json-tests/json/rlp/stream/*.json", &mut | file, input, output | { + println!("file: {}", file); + + let mut stream = RlpStream::new(); + 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::AppendRaw(ref raw, len) => stream.append_raw(raw, len), + rlptest::Operation::AppendEmpty => stream.append_empty_data() + }; + } + + assert_eq!(stream.out(), output); + }); +} + diff --git a/src/rlp/faces.rs b/src/rlp/traits.rs similarity index 92% rename from src/rlp/faces.rs rename to src/rlp/traits.rs index 078620de2..966078b08 100644 --- a/src/rlp/faces.rs +++ b/src/rlp/traits.rs @@ -1,32 +1,4 @@ -use std::fmt; -use std::error::Error as StdError; -use bytes::FromBytesError; - -#[derive(Debug, PartialEq, Eq)] -pub enum DecoderError { - FromBytesError(FromBytesError), - RlpIsTooShort, - RlpExpectedToBeList, - RlpExpectedToBeData, -} - -impl StdError for DecoderError { - fn description(&self) -> &str { - "builder error" - } -} - -impl fmt::Display for DecoderError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - fmt::Debug::fmt(&self, f) - } -} - -impl From for DecoderError { - fn from(err: FromBytesError) -> DecoderError { - DecoderError::FromBytesError(err) - } -} +use rlp::DecoderError; pub trait Decoder { fn read_value(&self, f: F) -> Result diff --git a/src/rlp/untrusted_rlp.rs b/src/rlp/untrusted_rlp.rs index 9e2e2f522..19dd5e99c 100644 --- a/src/rlp/untrusted_rlp.rs +++ b/src/rlp/untrusted_rlp.rs @@ -1,6 +1,6 @@ use std::cell::Cell; use bytes::{FromBytes}; -use super::faces::{View, Decoder, Decodable, DecoderError}; +use rlp::{View, Decoder, Decodable, DecoderError}; /// rlp offset #[derive(Copy, Clone, Debug)]