diff --git a/src/overlaydb.rs b/src/overlaydb.rs index c13acfd6a..b5bbf4299 100644 --- a/src/overlaydb.rs +++ b/src/overlaydb.rs @@ -122,7 +122,7 @@ impl OverlayDB { .expect("Low-level database error. Some issue with your hard disk?") .map(|d| { let r = Rlp::new(d.deref()); - (Bytes::decode(&r.at(1)), u32::decode(&r.at(0))) + (r.at(1).as_val(), r.at(0).as_val()) }) } diff --git a/src/rlp.rs b/src/rlp.rs deleted file mode 100644 index d0dece3ba..000000000 --- a/src/rlp.rs +++ /dev/null @@ -1,1452 +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::error::Error as StdError; -use elastic_array::*; -use bytes::{ToBytes, FromBytes, FromBytesError}; -use vector::InsertSlice; - -/// 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> 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 { - // push new list - let position = self.encoder.bytes.len(); - match len { - 0 => { - // we may finish, if the appended list len is equal 0 - self.encoder.bytes.push(0xc0u8); - self.note_appended(1); - }, - _ => { - // reserve at least double size of the len - //self.encoder.bytes.reserve(len * 2); - 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}; - 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(); - assert_eq!(animals, vec!["cat".to_string(), "dog".to_string()]); - - let cat = rlp.at(0).unwrap(); - assert!(cat.is_data()); - assert_eq!(cat.bytes, &[0x83, b'c', b'a', b't']); - assert_eq!(String::decode_untrusted(&cat).unwrap(), "cat".to_string()); - - let dog = rlp.at(1).unwrap(); - assert!(dog.is_data()); - assert_eq!(dog.bytes, &[0x83, b'd', b'o', b'g']); - assert_eq!(String::decode_untrusted(&dog).unwrap(), "dog".to_string()); - - let cat_again = rlp.at(0).unwrap(); - assert!(cat_again.is_data()); - assert_eq!(cat_again.bytes, &[0x83, b'c', b'a', b't']); - assert_eq!(String::decode_untrusted(&cat_again).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.bytes, &[0x83, b'c', b'a', b't']); - - let dog = iter.next().unwrap(); - assert!(dog.is_data()); - assert_eq!(dog.bytes, &[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.bytes, &[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/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 new file mode 100644 index 000000000..cb36426c9 --- /dev/null +++ b/src/rlp/mod.rs @@ -0,0 +1,82 @@ +//! 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. + +pub mod errors; +pub mod traits; +pub mod rlp; +pub mod untrusted_rlp; +pub mod rlpstream; + +#[cfg(test)] +mod tests; + +pub use self::errors::DecoderError; +pub use self::traits::{Decoder, Decodable, View, Stream, Encodable, Encoder}; +pub use self::untrusted_rlp::{UntrustedRlp, UntrustedRlpIterator, PayloadInfo, Prototype}; +pub use self::rlp::{Rlp, RlpIterator}; +pub use self::rlpstream::{RlpStream}; + +/// 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); + rlp.as_val() +} + +/// 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 stream = RlpStream::new(); + stream.append(object); + stream.out() +} diff --git a/src/rlp/rlp.rs b/src/rlp/rlp.rs new file mode 100644 index 000000000..ac830cc9c --- /dev/null +++ b/src/rlp/rlp.rs @@ -0,0 +1,135 @@ +use rlp::{View, Decodable, DecoderError, UntrustedRlp, PayloadInfo, Prototype}; + +impl<'a> From> for Rlp<'a> { + fn from(rlp: UntrustedRlp<'a>) -> Rlp<'a> { + Rlp { rlp: rlp } + } +} + +/// 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. +#[derive(Debug)] +pub struct Rlp<'a> { + rlp: UntrustedRlp<'a> +} + +impl<'a, 'view> View<'a, 'view> for Rlp<'a> where 'a: 'view { + type Prototype = Prototype; + type PayloadInfo = PayloadInfo; + type Data = &'a [u8]; + type Item = Rlp<'a>; + type Iter = RlpIterator<'a, 'view>; + + /// Create a new instance of `Rlp` + fn new(bytes: &'a [u8]) -> Rlp<'a> { + Rlp { + rlp: UntrustedRlp::new(bytes) + } + } + + fn raw(&'view self) -> &'a [u8] { + self.rlp.raw() + } + + fn prototype(&self) -> Self::Prototype { + self.rlp.prototype().unwrap() + } + + fn payload_info(&self) -> Self::PayloadInfo { + self.rlp.payload_info().unwrap() + } + + fn data(&'view self) -> Self::Data { + self.rlp.data().unwrap() + } + + fn item_count(&self) -> usize { + self.rlp.item_count() + } + + fn size(&self) -> usize { + self.rlp.size() + } + + fn at(&'view self, index: usize) -> Self::Item { + From::from(self.rlp.at(index).unwrap()) + } + + fn is_null(&self) -> bool { + self.rlp.is_null() + } + + fn is_empty(&self) -> bool { + self.rlp.is_empty() + } + + fn is_list(&self) -> bool { + self.rlp.is_list() + } + + fn is_data(&self) -> bool { + self.rlp.is_data() + } + + fn is_int(&self) -> bool { + self.rlp.is_int() + } + + fn iter(&'view self) -> Self::Iter { + self.into_iter() + } + + fn as_val(&self) -> Result where T: Decodable { + self.rlp.as_val() + } + + fn val_at(&self, index: usize) -> Result where T: Decodable { + 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 { + let res: Result = r.as_val(); + res.unwrap_or_else(|_| panic!()) + } + + pub fn as_val(&self) -> T where T: Decodable { + Self::view_as_val(self) + } + + pub fn val_at(&self, index: usize) -> T where T: Decodable { + Self::view_as_val(&self.at(index)) + } +} + +/// Iterator over trusted rlp-slice list elements. +pub struct RlpIterator<'a, 'view> where 'a: 'view { + rlp: &'view Rlp<'a>, + index: usize +} + +impl<'a, 'view> IntoIterator for &'view Rlp<'a> where 'a: 'view { + type Item = Rlp<'a>; + type IntoIter = RlpIterator<'a, 'view>; + + fn into_iter(self) -> Self::IntoIter { + RlpIterator { + rlp: self, + index: 0, + } + } +} + +impl<'a, 'view> Iterator for RlpIterator<'a, 'view> { + 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 + } +} diff --git a/src/rlp/rlpstream.rs b/src/rlp/rlpstream.rs new file mode 100644 index 000000000..557c4af25 --- /dev/null +++ b/src/rlp/rlpstream.rs @@ -0,0 +1,247 @@ +use elastic_array::*; +use bytes::ToBytes; +use rlp::{Stream, Encoder, Encodable}; + +#[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 Stream for RlpStream { + fn new() -> Self { + RlpStream { + unfinished_lists: ElasticArray16::new(), + encoder: BasicEncoder::new(), + } + } + + fn new_list(len: usize) -> Self { + let mut stream = RlpStream::new(); + stream.append_list(len); + stream + } + + 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 + } + + 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 + } + + 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 + } + + 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 + } + + fn clear(&mut self) { + // clear bytes + self.encoder.bytes.clear(); + + // clear lists + self.unfinished_lists.clear(); + } + + fn is_finished(&self) -> bool { + self.unfinished_lists.len() == 0 + } + + fn out(self) -> Vec { + match self.is_finished() { + true => self.encoder.out().to_vec(), + false => panic!() + } + } +} + +impl RlpStream { + + /// 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); + } + } +} + +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); + } +} + +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) + } +} 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/traits.rs b/src/rlp/traits.rs new file mode 100644 index 000000000..1127ca3db --- /dev/null +++ b/src/rlp/traits.rs @@ -0,0 +1,289 @@ +use rlp::DecoderError; + +pub trait Decoder { + fn read_value(&self, f: F) -> Result + where F: FnOnce(&[u8]) -> Result; + + fn read_list(&self, f: F) -> Result + where F: FnOnce(&[Self]) -> Result; +} + +pub trait Decodable: Sized { + fn decode(decoder: &D) -> Result where D: Decoder; +} + +pub trait View<'a, 'view>: Sized { + type Prototype; + type PayloadInfo; + type Data; + type Item; + type Iter; + + /// Creates a new instance of `Rlp` reader + fn new(bytes: &'a [u8]) -> Self; + + /// 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']); + /// } + /// ``` + fn raw(&'view self) -> &'a [u8]; + + /// Get the prototype of the RLP. + fn prototype(&self) -> Self::Prototype; + + fn payload_info(&self) -> Self::PayloadInfo; + + fn data(&'view self) -> Self::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); + /// } + /// ``` + fn item_count(&self) -> usize; + + /// 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); + /// } + /// ``` + fn size(&self) -> usize; + + /// 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 = rlp.at(1).as_val(); + /// assert_eq!(dog, "dog".to_string()); + /// } + fn at(&'view self, index: usize) -> Self::Item; + + /// 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()); + /// } + /// ``` + fn is_null(&self) -> bool; + + /// 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()); + /// } + /// ``` + fn is_empty(&self) -> bool; + + /// 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()); + /// } + /// ``` + fn is_list(&self) -> bool; + + /// 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()); + /// } + /// ``` + fn is_data(&self) -> bool; + + /// 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); + /// } + /// ``` + fn is_int(&self) -> bool; + + /// 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 | i.as_val()).collect(); + /// } + /// ``` + fn iter(&'view self) -> Self::Iter; + + fn as_val(&self) -> Result where T: Decodable; + + fn val_at(&self, index: usize) -> Result where T: Decodable; +} + +pub trait Encoder { + fn emit_value(&mut self, bytes: &[u8]) -> (); + fn emit_list(&mut self, f: F) -> () where F: FnOnce(&mut Self) -> (); +} + +pub trait Encodable { + fn encode(&self, encoder: &mut E) -> () where E: Encoder; +} + +pub trait Stream: Sized { + + /// Initializes instance of empty `Stream`. + fn new() -> Self; + + /// Initializes the `Stream` as a list. + fn new_list(len: usize) -> Self; + + /// 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']); + /// } + /// ``` + fn append<'a, E>(&'a mut self, object: &E) -> &'a mut Self where E: Encodable; + + /// 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]); + /// } + /// ``` + fn append_list<'a>(&'a mut self, len: usize) -> &'a mut 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]); + /// } + /// ``` + fn append_empty_data<'a>(&'a mut self) -> &'a mut Self; + + /// Appends raw (pre-serialised) RLP data. Use with caution. Chainable. + fn append_raw<'a>(&'a mut self, bytes: &[u8], item_count: usize) -> &'a mut 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']); + /// } + fn clear(&mut self); + + /// 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']); + /// } + fn is_finished(&self) -> bool; + + /// Streams out encoded bytes. + /// + /// panic! if stream is not finished. + fn out(self) -> Vec; +} diff --git a/src/rlp/untrusted_rlp.rs b/src/rlp/untrusted_rlp.rs new file mode 100644 index 000000000..eae253eca --- /dev/null +++ b/src/rlp/untrusted_rlp.rs @@ -0,0 +1,342 @@ +use std::cell::Cell; +use bytes::{FromBytes}; +use rlp::{View, Decoder, Decodable, DecoderError}; + +/// 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, + } + } +} + +#[derive(Debug)] +pub enum Prototype { + Null, + Data(usize), + List(usize), +} + +/// 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, + } + } +} + +/// 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, +} + +impl<'a> Clone for UntrustedRlp<'a> { + fn clone(&self) -> UntrustedRlp<'a> { + UntrustedRlp { + bytes: self.bytes, + cache: Cell::new(OffsetCache::new(usize::max_value(), 0)) + } + } +} + +impl<'a, 'view> View<'a, 'view> for UntrustedRlp<'a> where 'a: 'view { + type Prototype = Result; + type PayloadInfo = Result; + type Data = Result<&'a [u8], DecoderError>; + type Item = Result, DecoderError>; + type Iter = UntrustedRlpIterator<'a, 'view>; + + //returns new instance of `UntrustedRlp` + fn new(bytes: &'a [u8]) -> UntrustedRlp<'a> { + UntrustedRlp { + bytes: bytes, + cache: Cell::new(OffsetCache::new(usize::max_value(), 0)), + } + } + + fn raw(&'view self) -> &'a [u8] { + self.bytes + } + + fn prototype(&self) -> Self::Prototype { + // optimize? && return appropriate errors + if self.is_data() { + Ok(Prototype::Data(self.size())) + } else if self.is_list() { + Ok(Prototype::List(self.item_count())) + } else { + Ok(Prototype::Null) + } + } + + fn payload_info(&self) -> Self::PayloadInfo { + BasicDecoder::payload_info(self.bytes) + } + + fn data(&'view self) -> Self::Data { + let pi = try!(BasicDecoder::payload_info(self.bytes)); + Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)]) + } + + fn item_count(&self) -> usize { + match self.is_list() { + true => self.iter().count(), + false => 0 + } + } + + fn size(&self) -> usize { + match self.is_data() { + // we can safely unwrap (?) cause its data + true => BasicDecoder::payload_info(self.bytes).unwrap().value_len, + false => 0 + } + } + + fn at(&'view self, index: usize) -> Self::Item { + 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])) + } + + fn is_null(&self) -> bool { + self.bytes.len() == 0 + } + + fn is_empty(&self) -> bool { + !self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80) + } + + fn is_list(&self) -> bool { + !self.is_null() && self.bytes[0] >= 0xc0 + } + + fn is_data(&self) -> bool { + !self.is_null() && self.bytes[0] < 0xc0 + } + + 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 + } + } + + fn iter(&'view self) -> Self::Iter { + self.into_iter() + } + + fn as_val(&self) -> Result where T: Decodable { + // 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 { + self.at(index).unwrap().as_val() + } +} + +impl<'a> UntrustedRlp<'a> { + /// 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, 'view> where 'a: 'view { + rlp: &'view UntrustedRlp<'a>, + index: usize, +} + +impl<'a, 'view> IntoIterator for &'view UntrustedRlp<'a> where 'a: 'view { + type Item = UntrustedRlp<'a>; + type IntoIter = UntrustedRlpIterator<'a, 'view>; + + fn into_iter(self) -> Self::IntoIter { + UntrustedRlpIterator { + rlp: self, + index: 0, + } + } +} + +impl<'a, 'view> Iterator for UntrustedRlpIterator<'a, 'view> { + type Item = UntrustedRlp<'a>; + + fn next(&mut self) -> Option> { + let index = self.index; + let result = self.rlp.at(index).ok(); + self.index += 1; + result + } +} + +struct BasicDecoder<'a> { + rlp: UntrustedRlp<'a> +} + +impl<'a> BasicDecoder<'a> { + pub fn new(rlp: UntrustedRlp<'a>) -> BasicDecoder<'a> { + BasicDecoder { + rlp: rlp + } + } + + /// 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 + _ => { unreachable!(); } + }; + + match item.header_len + item.value_len <= bytes.len() { + true => Ok(item), + false => Err(DecoderError::RlpIsTooShort), + } + } +} + +impl<'a> Decoder for BasicDecoder<'a> { + fn read_value(&self, f: F) -> Result + where F: FnOnce(&[u8]) -> Result { + + let bytes = self.rlp.raw(); + + 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! + _ => Err(DecoderError::RlpExpectedToBeData) + } + } + + fn read_list(&self, f: F) -> Result + where F: FnOnce(&[Self]) -> Result { + + let v: Vec> = self.rlp.iter() + .map(| i | BasicDecoder::new(i)) + .collect(); + f(&v) + } +} + +impl Decodable for T where T: FromBytes { + fn decode(decoder: &D) -> Result where D: Decoder { + decoder.read_value(| bytes | { + Ok(try!(T::from_bytes(bytes))) + }) + } +} + +impl Decodable for Vec where T: Decodable { + fn decode(decoder: &D) -> Result where D: Decoder { + decoder.read_list(| decoders | { + decoders.iter().map(|d| T::decode(d)).collect() + }) + } +} + +impl Decodable for Vec { + fn decode(decoder: &D) -> Result where D: Decoder { + decoder.read_value(| bytes | { + let mut res = vec![]; + res.extend(bytes); + Ok(res) + }) + } +} diff --git a/src/trie.rs b/src/trie.rs index 5c4420787..3c7e8bfb2 100644 --- a/src/trie.rs +++ b/src/trie.rs @@ -158,7 +158,7 @@ impl Journal { fn delete_node(&mut self, old: &[u8]) { let r = Rlp::new(old); if r.is_data() && r.size() == 32 { - self.delete_node_sha3(H256::decode(&r)); + self.delete_node_sha3(r.as_val()); } } } @@ -383,7 +383,7 @@ impl TrieDB { let mut handle_payload = |payload| { let p = Rlp::new(payload); if p.is_data() && p.size() == 32 { - acc.push(H256::decode(&p)); + acc.push(p.as_val()); } self.accumulate_keys(self.get_node(payload), acc); @@ -481,7 +481,7 @@ impl TrieDB { // check if its sha3 + len let r = Rlp::new(node); match r.is_data() && r.size() == 32 { - true => self.db.lookup(&H256::decode(&r)).expect("Not found!"), + true => self.db.lookup(&r.as_val::()).expect("Not found!"), false => node } } @@ -561,7 +561,7 @@ impl TrieDB { rlp.raw() } else if rlp.is_data() && rlp.size() == 32 { - let h = H256::decode(rlp); + let h = rlp.as_val(); let r = self.db.lookup(&h).unwrap_or_else(||{ println!("Node not found! rlp={:?}, node_hash={:?}", rlp.raw().pretty(), h); println!("Journal: {:?}", journal); diff --git a/src/triehash.rs b/src/triehash.rs index eea79e9d4..67ffcc666 100644 --- a/src/triehash.rs +++ b/src/triehash.rs @@ -7,7 +7,7 @@ use std::cmp; use hash::*; use sha3::*; use rlp; -use rlp::RlpStream; +use rlp::{RlpStream, Stream}; use vector::SharedPrefix; /// Generates a trie root hash for a vector of values