rlp-0.5.2/.cargo_vcs_info.json0000644000000001410000000000100116310ustar { "git": { "sha1": "86676b08e89cb99fdff0c882453ad0746dd070cf" }, "path_in_vcs": "rlp" }rlp-0.5.2/CHANGELOG.md000064400000000000000000000023251046102023000122400ustar 00000000000000# Changelog The format is based on [Keep a Changelog]. [Keep a Changelog]: http://keepachangelog.com/en/1.0.0/ ## [Unreleased] ## [0.5.2] - 2022-10-21 - Add optional `derive` feature. [#613](https://github.com/paritytech/parity-common/pull/613) ## [0.5.1] - 2021-07-30 - Fix rlp encoding/decoding for bool. [#572](https://github.com/paritytech/parity-common/pull/572) ## [0.5.0] - 2021-01-05 ### Breaking - Use BytesMut for `RlpStream`'s backing buffer. [#453](https://github.com/paritytech/parity-common/pull/453) ## [0.4.6] - 2020-09-29 - Implement Encodable, Decodable for boxed types. [#427](https://github.com/paritytech/parity-common/pull/427) ## [0.4.5] - 2020-03-16 ### Dependencies - Updated dependencies. [#361](https://github.com/paritytech/parity-common/pull/361) ## [0.4.4] - 2019-11-20 ### Added - Method `Rlp::at_with_offset`. [#269](https://github.com/paritytech/parity-common/pull/269) ## [0.4.3] - 2019-10-24 ### Dependencies - Updated dependencies. [#239](https://github.com/paritytech/parity-common/pull/239) ### Fixed - Fixed nested unbounded lists. [#203](https://github.com/paritytech/parity-common/pull/203) ### Added - Added no-std support. [#206](https://github.com/paritytech/parity-common/pull/206) rlp-0.5.2/Cargo.toml0000644000000024150000000000100076350ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "rlp" version = "0.5.2" authors = ["Parity Technologies "] description = "Recursive-length prefix encoding, decoding, and compression" readme = "README.md" license = "MIT OR Apache-2.0" repository = "https://github.com/paritytech/parity-common" [[bench]] name = "rlp" path = "benches/rlp.rs" harness = false [dependencies.bytes] version = "1" default-features = false [dependencies.rlp-derive] version = "0.1" optional = true [dependencies.rustc-hex] version = "2.0.1" default-features = false [dev-dependencies.criterion] version = "0.4.0" [dev-dependencies.hex-literal] version = "0.3.1" [dev-dependencies.primitive-types] version = "0.12" features = ["impl-rlp"] [features] default = ["std"] derive = ["rlp-derive"] std = [ "bytes/std", "rustc-hex/std", ] rlp-0.5.2/Cargo.toml.orig000064400000000000000000000014231046102023000133140ustar 00000000000000[package] name = "rlp" version = "0.5.2" description = "Recursive-length prefix encoding, decoding, and compression" repository = "https://github.com/paritytech/parity-common" license = "MIT OR Apache-2.0" authors = ["Parity Technologies "] edition = "2018" [dependencies] bytes = { version = "1", default-features = false } rustc-hex = { version = "2.0.1", default-features = false } rlp-derive = { version = "0.1", path = "../rlp-derive", optional = true } [dev-dependencies] criterion = "0.4.0" hex-literal = "0.3.1" primitive-types = { path = "../primitive-types", version = "0.12", features = ["impl-rlp"] } [features] default = ["std"] std = ["bytes/std", "rustc-hex/std"] derive = ["rlp-derive"] [[bench]] name = "rlp" path = "benches/rlp.rs" harness = false rlp-0.5.2/README.md000064400000000000000000000005011046102023000117000ustar 00000000000000# RLP Recursive-length-prefix encoding, decoding, and compression in Rust. ## License Unlike most parts of Parity, which fall under the GPLv3, this package is dual-licensed under MIT/Apache2 at the user's choice. Find the associated license files in this directory as `LICENSE-MIT` and `LICENSE-APACHE2` respectively. rlp-0.5.2/benches/rlp.rs000064400000000000000000000067001046102023000132020ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! benchmarking for rlp use criterion::{criterion_group, criterion_main, Criterion}; fn bench_encode(c: &mut Criterion) { c.bench_function("encode_u64", |b| { b.iter(|| { let mut stream = rlp::RlpStream::new(); stream.append(&0x1023_4567_89ab_cdefu64); let _ = stream.out(); }) }); c.bench_function("encode_u256", |b| { b.iter(|| { let mut stream = rlp::RlpStream::new(); let uint: primitive_types::U256 = "8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0".into(); stream.append(&uint); let _ = stream.out(); }) }); c.bench_function("encode_1000_u64", |b| { b.iter(|| { let mut stream = rlp::RlpStream::new_list(1000); for i in 0..1000u64 { stream.append(&i); } let _ = stream.out(); }) }); c.bench_function("encode_nested_empty_lists", |b| { b.iter(|| { // [ [], [[]], [ [], [[]] ] ] let mut stream = rlp::RlpStream::new_list(3); stream.begin_list(0); stream.begin_list(1).begin_list(0); stream.begin_list(2).begin_list(0).begin_list(1).begin_list(0); let _ = stream.out(); }) }); c.bench_function("encode_1000_empty_lists", |b| { b.iter(|| { let mut stream = rlp::RlpStream::new_list(1000); for _ in 0..1000 { stream.begin_list(0); } let _ = stream.out(); }) }); } fn bench_decode(c: &mut Criterion) { c.bench_function("decode_u64", |b| { b.iter(|| { let data = vec![0x88, 0x10, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; let rlp = rlp::Rlp::new(&data); let _: u64 = rlp.as_val().unwrap(); }) }); c.bench_function("decode_u256", |b| { b.iter(|| { let data = vec![ 0xa0, 0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0x09, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x77, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0xf0, ]; let rlp = rlp::Rlp::new(&data); let _: primitive_types::U256 = rlp.as_val().unwrap(); }) }); c.bench_function("decode_1000_u64", |b| { let mut stream = rlp::RlpStream::new_list(1000); for i in 0..1000u64 { stream.append(&i); } let data = stream.out(); b.iter(|| { let rlp = rlp::Rlp::new(&data); for i in 0..1000 { let _: u64 = rlp.val_at(i).unwrap(); } }); }); c.bench_function("decode_nested_empty_lists", |b| { b.iter(|| { // [ [], [[]], [ [], [[]] ] ] let data = vec![0xc7, 0xc0, 0xc1, 0xc0, 0xc3, 0xc0, 0xc1, 0xc0]; let rlp = rlp::Rlp::new(&data); let _v0: Vec = rlp.at(0).unwrap().as_list().unwrap(); let _v1: Vec = rlp.at(1).unwrap().at(0).unwrap().as_list().unwrap(); let nested_rlp = rlp.at(2).unwrap(); let _v2a: Vec = nested_rlp.at(0).unwrap().as_list().unwrap(); let _v2b: Vec = nested_rlp.at(1).unwrap().at(0).unwrap().as_list().unwrap(); }) }); c.bench_function("decode_1000_empty_lists", |b| { let mut stream = rlp::RlpStream::new_list(1000); for _ in 0..1000 { stream.begin_list(0); } let data = stream.out(); b.iter(|| { let rlp = rlp::Rlp::new(&data); for i in 0..1000 { let _: Vec = rlp.at(i).unwrap().as_list().unwrap(); } }); }); } criterion_group!(benches, bench_encode, bench_decode); criterion_main!(benches); rlp-0.5.2/src/error.rs000064400000000000000000000031431046102023000127140ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use core::fmt; #[cfg(feature = "std")] use std::error::Error as StdError; #[derive(Debug, PartialEq, Eq, Clone)] /// Error concerning the RLP decoder. pub enum DecoderError { /// Data has additional bytes at the end of the valid RLP fragment. RlpIsTooBig, /// Data has too few bytes for valid RLP. RlpIsTooShort, /// Expect an encoded list, RLP was something else. RlpExpectedToBeList, /// Expect encoded data, RLP was something else. RlpExpectedToBeData, /// Expected a different size list. RlpIncorrectListLen, /// Data length number has a prefixed zero byte, invalid for numbers. RlpDataLenWithZeroPrefix, /// List length number has a prefixed zero byte, invalid for numbers. RlpListLenWithZeroPrefix, /// Non-canonical (longer than necessary) representation used for data or list. RlpInvalidIndirection, /// Declared length is inconsistent with data specified after. RlpInconsistentLengthAndData, /// Declared length is invalid and results in overflow RlpInvalidLength, /// Custom rlp decoding error. Custom(&'static str), } #[cfg(feature = "std")] 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) } } rlp-0.5.2/src/impls.rs000064400000000000000000000127001046102023000127060ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[cfg(not(feature = "std"))] use alloc::{borrow::ToOwned, boxed::Box, string::String, vec::Vec}; use bytes::{Bytes, BytesMut}; use core::{ iter::{empty, once}, mem, str, }; use crate::{ error::DecoderError, rlpin::Rlp, stream::RlpStream, traits::{Decodable, Encodable}, }; pub fn decode_usize(bytes: &[u8]) -> Result { match bytes.len() { l if l <= mem::size_of::() => { if bytes[0] == 0 { return Err(DecoderError::RlpInvalidIndirection) } let mut res = 0usize; for (i, byte) in bytes.iter().enumerate().take(l) { let shift = (l - 1 - i) * 8; res += (*byte as usize) << shift; } Ok(res) }, _ => Err(DecoderError::RlpIsTooBig), } } impl Encodable for Box { fn rlp_append(&self, s: &mut RlpStream) { Encodable::rlp_append(&**self, s) } } impl Decodable for Box { fn decode(rlp: &Rlp) -> Result { T::decode(rlp).map(Box::new) } } impl Encodable for bool { fn rlp_append(&self, s: &mut RlpStream) { let as_uint = u8::from(*self); Encodable::rlp_append(&as_uint, s); } } impl Decodable for bool { fn decode(rlp: &Rlp) -> Result { let as_uint = ::decode(rlp)?; match as_uint { 0 => Ok(false), 1 => Ok(true), _ => Err(DecoderError::Custom("invalid boolean value")), } } } impl<'a> Encodable for &'a [u8] { fn rlp_append(&self, s: &mut RlpStream) { s.encoder().encode_value(self); } } impl Encodable for Vec { fn rlp_append(&self, s: &mut RlpStream) { s.encoder().encode_value(self); } } impl Decodable for Vec { fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| Ok(bytes.to_vec())) } } impl Encodable for Bytes { fn rlp_append(&self, s: &mut RlpStream) { s.encoder().encode_value(self); } } impl Decodable for Bytes { fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| Ok(Bytes::copy_from_slice(bytes))) } } impl Encodable for BytesMut { fn rlp_append(&self, s: &mut RlpStream) { s.encoder().encode_value(self); } } impl Decodable for BytesMut { fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| Ok(bytes.into())) } } impl Encodable for Option where T: Encodable, { fn rlp_append(&self, s: &mut RlpStream) { match *self { None => { s.begin_list(0); }, Some(ref value) => { s.begin_list(1); s.append(value); }, } } } impl Decodable for Option where T: Decodable, { fn decode(rlp: &Rlp) -> Result { let items = rlp.item_count()?; match items { 1 => rlp.val_at(0).map(Some), 0 => Ok(None), _ => Err(DecoderError::RlpIncorrectListLen), } } } impl Encodable for u8 { fn rlp_append(&self, s: &mut RlpStream) { if *self != 0 { s.encoder().encode_iter(once(*self)); } else { s.encoder().encode_iter(empty()); } } } impl Decodable for u8 { fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| match bytes.len() { 1 if bytes[0] != 0 => Ok(bytes[0]), 0 => Ok(0), 1 => Err(DecoderError::RlpInvalidIndirection), _ => Err(DecoderError::RlpIsTooBig), }) } } macro_rules! impl_encodable_for_u { ($name: ident) => { impl Encodable for $name { fn rlp_append(&self, s: &mut RlpStream) { let leading_empty_bytes = self.leading_zeros() as usize / 8; let buffer = self.to_be_bytes(); s.encoder().encode_value(&buffer[leading_empty_bytes..]); } } }; } macro_rules! impl_decodable_for_u { ($name: ident) => { impl Decodable for $name { fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| match bytes.len() { 0 | 1 => u8::decode(rlp).map(|v| v as $name), l if l <= mem::size_of::<$name>() => { if bytes[0] == 0 { return Err(DecoderError::RlpInvalidIndirection) } let mut res = 0 as $name; for (i, byte) in bytes.iter().enumerate().take(l) { let shift = (l - 1 - i) * 8; res += (*byte as $name) << shift; } Ok(res) }, _ => Err(DecoderError::RlpIsTooBig), }) } } }; } impl_encodable_for_u!(u16); impl_encodable_for_u!(u32); impl_encodable_for_u!(u64); impl_encodable_for_u!(u128); impl_decodable_for_u!(u16); impl_decodable_for_u!(u32); impl_decodable_for_u!(u64); impl_decodable_for_u!(u128); impl Encodable for usize { fn rlp_append(&self, s: &mut RlpStream) { (*self as u64).rlp_append(s); } } impl Decodable for usize { fn decode(rlp: &Rlp) -> Result { u64::decode(rlp).map(|value| value as usize) } } impl<'a> Encodable for &'a str { fn rlp_append(&self, s: &mut RlpStream) { s.encoder().encode_value(self.as_bytes()); } } impl Encodable for String { fn rlp_append(&self, s: &mut RlpStream) { s.encoder().encode_value(self.as_bytes()); } } impl Decodable for String { fn decode(rlp: &Rlp) -> Result { rlp.decoder().decode_value(|bytes| { match str::from_utf8(bytes) { Ok(s) => Ok(s.to_owned()), // consider better error type here Err(_err) => Err(DecoderError::RlpExpectedToBeData), } }) } } rlp-0.5.2/src/lib.rs000064400000000000000000000054471046102023000123420ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Recursive Length Prefix serialization crate. //! //! 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 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. #![cfg_attr(not(feature = "std"), no_std)] #[cfg(not(feature = "std"))] extern crate alloc; mod error; mod impls; mod rlpin; mod stream; mod traits; #[cfg(not(feature = "std"))] use alloc::vec::Vec; use bytes::BytesMut; use core::borrow::Borrow; #[cfg(feature = "derive")] pub use rlp_derive::{RlpDecodable, RlpDecodableWrapper, RlpEncodable, RlpEncodableWrapper}; pub use self::{ error::DecoderError, rlpin::{PayloadInfo, Prototype, Rlp, RlpIterator}, stream::RlpStream, traits::{Decodable, Encodable}, }; /// The RLP encoded empty data (used to mean "null value"). pub const NULL_RLP: [u8; 1] = [0x80; 1]; /// The RLP encoded empty list. pub const EMPTY_LIST_RLP: [u8; 1] = [0xC0; 1]; /// Shortcut function to decode trusted rlp /// /// ``` /// let data = vec![0x83, b'c', b'a', b't']; /// let animal: String = rlp::decode(&data).expect("could not decode"); /// assert_eq!(animal, "cat".to_owned()); /// ``` pub fn decode(bytes: &[u8]) -> Result where T: Decodable, { let rlp = Rlp::new(bytes); rlp.as_val() } pub fn decode_list(bytes: &[u8]) -> Vec where T: Decodable, { let rlp = Rlp::new(bytes); rlp.as_list().expect("trusted rlp should be valid") } /// Shortcut function to encode structure into rlp. /// /// ``` /// let animal = "cat"; /// let out = rlp::encode(&animal); /// assert_eq!(out, vec![0x83, b'c', b'a', b't']); /// ``` pub fn encode(object: &E) -> BytesMut where E: Encodable, { let mut stream = RlpStream::new(); stream.append(object); stream.out() } pub fn encode_list(object: &[K]) -> BytesMut where E: Encodable, K: Borrow, { let mut stream = RlpStream::new(); stream.append_list(object); stream.out() } rlp-0.5.2/src/rlpin.rs000064400000000000000000000251751046102023000127200ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[cfg(not(feature = "std"))] use alloc::{string::String, vec::Vec}; use core::{cell::Cell, fmt}; use rustc_hex::ToHex; use crate::{error::DecoderError, impls::decode_usize, traits::Decodable}; /// rlp offset #[derive(Copy, Clone, Debug)] struct OffsetCache { index: usize, offset: usize, } impl OffsetCache { const fn new(index: usize, offset: usize) -> OffsetCache { OffsetCache { index, offset } } } #[derive(Debug)] /// RLP prototype pub enum Prototype { /// Empty Null, /// Value Data(usize), /// List List(usize), } /// Stores basic information about item #[derive(Debug)] pub struct PayloadInfo { /// Header length in bytes pub header_len: usize, /// Value length in bytes pub value_len: usize, } fn calculate_payload_info(header_bytes: &[u8], len_of_len: usize) -> Result { let header_len = 1 + len_of_len; match header_bytes.get(1) { Some(&0) => return Err(DecoderError::RlpDataLenWithZeroPrefix), None => return Err(DecoderError::RlpIsTooShort), _ => (), } if header_bytes.len() < header_len { return Err(DecoderError::RlpIsTooShort) } let value_len = decode_usize(&header_bytes[1..header_len])?; if value_len <= 55 { return Err(DecoderError::RlpInvalidIndirection) } Ok(PayloadInfo::new(header_len, value_len)) } impl PayloadInfo { const fn new(header_len: usize, value_len: usize) -> PayloadInfo { PayloadInfo { header_len, value_len } } /// Total size of the RLP. pub fn total(&self) -> usize { self.header_len + self.value_len } /// Create a new object from the given bytes RLP. The bytes pub fn from(header_bytes: &[u8]) -> Result { let l = *header_bytes.first().ok_or_else(|| DecoderError::RlpIsTooShort)?; if l <= 0x7f { Ok(PayloadInfo::new(0, 1)) } else if l <= 0xb7 { Ok(PayloadInfo::new(1, l as usize - 0x80)) } else if l <= 0xbf { let len_of_len = l as usize - 0xb7; calculate_payload_info(header_bytes, len_of_len) } else if l <= 0xf7 { Ok(PayloadInfo::new(1, l as usize - 0xc0)) } else { let len_of_len = l as usize - 0xf7; calculate_payload_info(header_bytes, len_of_len) } } } /// Data-oriented view onto rlp-slice. /// /// This is an immutable structure. No operations change it. /// /// Should be used in places where, error handling is required, /// eg. on input #[derive(Debug, Clone)] pub struct Rlp<'a> { bytes: &'a [u8], offset_cache: Cell>, count_cache: Cell>, } impl<'a> fmt::Display for Rlp<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> { match self.prototype() { Ok(Prototype::Null) => write!(f, "null"), Ok(Prototype::Data(_)) => write!(f, "\"0x{}\"", self.data().unwrap().to_hex::()), Ok(Prototype::List(len)) => { write!(f, "[")?; for i in 0..len - 1 { write!(f, "{}, ", self.at(i).unwrap())?; } write!(f, "{}", self.at(len - 1).unwrap())?; write!(f, "]") }, Err(err) => write!(f, "{:?}", err), } } } impl<'a> Rlp<'a> { pub const fn new(bytes: &'a [u8]) -> Rlp<'a> { Rlp { bytes, offset_cache: Cell::new(None), count_cache: Cell::new(None) } } pub fn as_raw<'view>(&'view self) -> &'a [u8] where 'a: 'view, { self.bytes } pub fn prototype(&self) -> Result { // optimize? && return appropriate errors if self.is_data() { Ok(Prototype::Data(self.size())) } else if self.is_list() { self.item_count().map(Prototype::List) } else { Ok(Prototype::Null) } } pub fn payload_info(&self) -> Result { BasicDecoder::payload_info(self.bytes) } pub fn data<'view>(&'view self) -> Result<&'a [u8], DecoderError> where 'a: 'view, { let pi = BasicDecoder::payload_info(self.bytes)?; Ok(&self.bytes[pi.header_len..(pi.header_len + pi.value_len)]) } pub fn item_count(&self) -> Result { if self.is_list() { match self.count_cache.get() { Some(c) => Ok(c), None => { let c = self.iter().count(); self.count_cache.set(Some(c)); Ok(c) }, } } else { Err(DecoderError::RlpExpectedToBeList) } } pub fn size(&self) -> usize { if self.is_data() { // TODO: No panic on malformed data, but ideally would Err on no PayloadInfo. BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0) } else { 0 } } /// Returns an Rlp item in a list at the given index. /// /// Returns an error if this Rlp is not a list or if the index is out of range. pub fn at<'view>(&'view self, index: usize) -> Result, DecoderError> where 'a: 'view, { let (rlp, _offset) = self.at_with_offset(index)?; Ok(rlp) } /// Returns an Rlp item in a list at the given index along with the byte offset into the /// raw data slice. /// /// Returns an error if this Rlp is not a list or if the index is out of range. pub fn at_with_offset<'view>(&'view self, index: usize) -> Result<(Rlp<'a>, usize), DecoderError> where 'a: 'view, { if !self.is_list() { return Err(DecoderError::RlpExpectedToBeList) } // move to cached position if its index is less or equal to // current search index, otherwise move to beginning of list let cache = self.offset_cache.get(); let (bytes, indexes_to_skip, bytes_consumed) = match cache { Some(ref cache) if cache.index <= index => (Rlp::consume(self.bytes, cache.offset)?, index - cache.index, cache.offset), _ => { let (bytes, consumed) = self.consume_list_payload()?; (bytes, index, consumed) }, }; // skip up to x items let (bytes, consumed) = Rlp::consume_items(bytes, indexes_to_skip)?; // update the cache let offset = bytes_consumed + consumed; self.offset_cache.set(Some(OffsetCache::new(index, offset))); // construct new rlp let found = BasicDecoder::payload_info(bytes)?; Ok((Rlp::new(&bytes[0..found.header_len + found.value_len]), offset)) } pub fn is_null(&self) -> bool { self.bytes.is_empty() } pub fn is_empty(&self) -> bool { !self.is_null() && (self.bytes[0] == 0xc0 || self.bytes[0] == 0x80) } pub fn is_list(&self) -> bool { !self.is_null() && self.bytes[0] >= 0xc0 } pub fn is_data(&self) -> bool { !self.is_null() && self.bytes[0] < 0xc0 } 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 => { let payload_idx = 1 + b as usize - 0xb7; payload_idx < self.bytes.len() && self.bytes[payload_idx] != 0 }, _ => false, } } pub fn iter<'view>(&'view self) -> RlpIterator<'a, 'view> where 'a: 'view, { self.into_iter() } pub fn as_val(&self) -> Result where T: Decodable, { T::decode(self) } pub fn as_list(&self) -> Result, DecoderError> where T: Decodable, { self.iter().map(|rlp| rlp.as_val()).collect() } pub fn val_at(&self, index: usize) -> Result where T: Decodable, { self.at(index)?.as_val() } pub fn list_at(&self, index: usize) -> Result, DecoderError> where T: Decodable, { self.at(index)?.as_list() } pub fn decoder(&self) -> BasicDecoder { BasicDecoder::new(self.bytes) } /// consumes first found prefix fn consume_list_payload(&self) -> Result<(&'a [u8], usize), DecoderError> { let item = BasicDecoder::payload_info(self.bytes)?; if self.bytes.len() < (item.header_len + item.value_len) { return Err(DecoderError::RlpIsTooShort) } Ok((&self.bytes[item.header_len..item.header_len + item.value_len], item.header_len)) } /// consumes fixed number of items fn consume_items(bytes: &'a [u8], items: usize) -> Result<(&'a [u8], usize), DecoderError> { let mut result = bytes; let mut consumed = 0; for _ in 0..items { let i = BasicDecoder::payload_info(result)?; let to_consume = i.header_len + i.value_len; result = Rlp::consume(result, to_consume)?; consumed += to_consume; } Ok((result, consumed)) } /// consumes slice prefix of length `len` fn consume(bytes: &'a [u8], len: usize) -> Result<&'a [u8], DecoderError> { if bytes.len() >= len { Ok(&bytes[len..]) } else { Err(DecoderError::RlpIsTooShort) } } } /// Iterator over 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.at(index).ok(); self.index += 1; result } } impl<'a, 'view> ExactSizeIterator for RlpIterator<'a, 'view> { fn len(&self) -> usize { self.rlp.item_count().unwrap_or(0) } } pub struct BasicDecoder<'a> { rlp: &'a [u8], } impl<'a> BasicDecoder<'a> { pub const fn new(rlp: &'a [u8]) -> BasicDecoder<'a> { BasicDecoder { rlp } } /// Return first item info. fn payload_info(bytes: &[u8]) -> Result { let item = PayloadInfo::from(bytes)?; match item.header_len.checked_add(item.value_len) { Some(x) if x <= bytes.len() => Ok(item), _ => Err(DecoderError::RlpIsTooShort), } } pub fn decode_value(&self, f: F) -> Result where F: Fn(&[u8]) -> Result, { let bytes = self.rlp; let l = *bytes.first().ok_or_else(|| DecoderError::RlpIsTooShort)?; if l <= 0x7f { Ok(f(&[l])?) } else if l <= 0xb7 { let last_index_of = 1 + l as usize - 0x80; if bytes.len() < last_index_of { return Err(DecoderError::RlpInconsistentLengthAndData) } let d = &bytes[1..last_index_of]; if l == 0x81 && d[0] < 0x80 { return Err(DecoderError::RlpInvalidIndirection) } Ok(f(d)?) } else if l <= 0xbf { let len_of_len = l as usize - 0xb7; let begin_of_value = 1 as usize + len_of_len; if bytes.len() < begin_of_value { return Err(DecoderError::RlpInconsistentLengthAndData) } let len = decode_usize(&bytes[1..begin_of_value])?; let last_index_of_value = begin_of_value.checked_add(len).ok_or(DecoderError::RlpInvalidLength)?; if bytes.len() < last_index_of_value { return Err(DecoderError::RlpInconsistentLengthAndData) } Ok(f(&bytes[begin_of_value..last_index_of_value])?) } else { Err(DecoderError::RlpExpectedToBeData) } } } rlp-0.5.2/src/stream.rs000064400000000000000000000261171046102023000130640ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. #[cfg(not(feature = "std"))] use alloc::vec::Vec; use bytes::{BufMut, BytesMut}; use core::borrow::Borrow; use crate::traits::Encodable; #[derive(Debug, Copy, Clone)] struct ListInfo { position: usize, current: usize, max: Option, } impl ListInfo { fn new(position: usize, max: Option) -> ListInfo { ListInfo { position, current: 0, max } } } /// Appendable rlp encoder. pub struct RlpStream { unfinished_lists: Vec, start_pos: usize, buffer: BytesMut, finished_list: bool, } impl Default for RlpStream { fn default() -> Self { RlpStream::new() } } impl RlpStream { /// Initializes instance of empty `Stream`. pub fn new() -> Self { Self::new_with_buffer(BytesMut::with_capacity(1024)) } /// Initializes the `Stream` as a list. pub fn new_list(len: usize) -> Self { Self::new_list_with_buffer(BytesMut::with_capacity(1024), len) } /// Initializes instance of empty `Stream`. pub fn new_with_buffer(buffer: BytesMut) -> Self { RlpStream { unfinished_lists: Vec::with_capacity(16), start_pos: buffer.len(), buffer, finished_list: false } } /// Initializes the `Stream` as a list. pub fn new_list_with_buffer(buffer: BytesMut, len: usize) -> Self { let mut stream = RlpStream::new_with_buffer(buffer); stream.begin_list(len); stream } fn total_written(&self) -> usize { self.buffer.len() - self.start_pos } /// Apends null to the end of stream, chainable. /// /// ``` /// use rlp::RlpStream; /// 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(&mut self) -> &mut Self { // self push raw item self.buffer.put_u8(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(&mut self, bytes: &[u8], item_count: usize) -> &mut Self { // push raw items self.buffer.extend_from_slice(bytes); // try to finish and prepend the length self.note_appended(item_count); // return chainable self self } /// Appends value to the end of stream, chainable. /// /// ``` /// use rlp::RlpStream; /// 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(&mut self, value: &E) -> &mut Self where E: Encodable, { self.finished_list = false; value.rlp_append(self); if !self.finished_list { self.note_appended(1); } self } /// Appends iterator to the end of stream, chainable. /// /// ``` /// use rlp::RlpStream; /// let mut stream = RlpStream::new_list(2); /// stream.append(&"cat").append_iter("dog".as_bytes().iter().cloned()); /// 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_iter(&mut self, value: I) -> &mut Self where I: IntoIterator, { self.finished_list = false; self.encoder().encode_iter(value); if !self.finished_list { self.note_appended(1); } self } /// Appends list of values to the end of stream, chainable. pub fn append_list(&mut self, values: &[K]) -> &mut Self where E: Encodable, K: Borrow, { self.begin_list(values.len()); for value in values { self.append(value.borrow()); } self } /// Appends value to the end of stream, but do not count it as an appended item. /// It's useful for wrapper types pub fn append_internal(&mut self, value: &E) -> &mut Self where E: Encodable, { value.rlp_append(self); self } /// Declare appending the list of given size, chainable. /// /// ``` /// use rlp::RlpStream; /// let mut stream = RlpStream::new_list(2); /// stream.begin_list(2).append(&"cat").append(&"dog"); /// stream.append(&""); /// let out = stream.out(); /// assert_eq!(out, vec![0xca, 0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g', 0x80]); /// ``` pub fn begin_list(&mut self, len: usize) -> &mut RlpStream { self.finished_list = false; match len { 0 => { // we may finish, if the appended list len is equal 0 self.buffer.put_u8(0xc0u8); self.note_appended(1); self.finished_list = true; }, _ => { // payload is longer than 1 byte only for lists > 55 bytes // by pushing always this 1 byte we may avoid unnecessary shift of data self.buffer.put_u8(0); let position = self.total_written(); self.unfinished_lists.push(ListInfo::new(position, Some(len))); }, } // return chainable self self } /// Declare appending the list of unknown size, chainable. pub fn begin_unbounded_list(&mut self) -> &mut RlpStream { self.finished_list = false; // payload is longer than 1 byte only for lists > 55 bytes // by pushing always this 1 byte we may avoid unnecessary shift of data self.buffer.put_u8(0); let position = self.total_written(); self.unfinished_lists.push(ListInfo::new(position, None)); // return chainable self self } /// Appends raw (pre-serialised) RLP data. Checks for size overflow. pub fn append_raw_checked(&mut self, bytes: &[u8], item_count: usize, max_size: usize) -> bool { if self.estimate_size(bytes.len()) > max_size { return false } self.append_raw(bytes, item_count); true } /// Calculate total RLP size for appended payload. pub fn estimate_size(&self, add: usize) -> usize { let total_size = self.total_written() + add; let mut base_size = total_size; for list in &self.unfinished_lists[..] { let len = total_size - list.position; if len > 55 { let leading_empty_bytes = (len as u64).leading_zeros() as usize / 8; let size_bytes = 8 - leading_empty_bytes; base_size += size_bytes; } } base_size } /// Returns current RLP size in bytes for the data pushed into the list. pub fn len(&self) -> usize { self.estimate_size(0) } pub fn is_empty(&self) -> bool { self.len() == 0 } /// Clear the output stream so far. /// /// ``` /// use rlp::RlpStream; /// 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.buffer.truncate(self.start_pos); // clear lists self.unfinished_lists.clear(); } /// Returns true if stream doesnt expect any more items. /// /// ``` /// use rlp::RlpStream; /// 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.is_empty() } /// Get raw encoded bytes pub fn as_raw(&self) -> &[u8] { //&self.encoder.bytes &self.buffer } /// Streams out encoded bytes. /// /// panic! if stream is not finished. pub fn out(self) -> BytesMut { if self.is_finished() { self.buffer } else { panic!() } } /// Try to finish lists fn note_appended(&mut self, inserted_items: usize) { if self.unfinished_lists.is_empty() { 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; match x.max { Some(ref max) if x.current > *max => panic!("You cannot append more items than you expect!"), Some(ref max) => x.current == *max, _ => false, } }, }; if should_finish { let x = self.unfinished_lists.pop().unwrap(); let len = self.total_written() - x.position; self.encoder().insert_list_payload(len, x.position); self.note_appended(1); } self.finished_list = should_finish; } pub fn encoder(&mut self) -> BasicEncoder { BasicEncoder::new(self, self.start_pos) } /// Finalize current unbounded list. Panics if no unbounded list has been opened. pub fn finalize_unbounded_list(&mut self) { let list = self.unfinished_lists.pop().expect("No open list."); if list.max.is_some() { panic!("List type mismatch."); } let len = self.total_written() - list.position; self.encoder().insert_list_payload(len, list.position); self.note_appended(1); self.finished_list = true; } } pub struct BasicEncoder<'a> { buffer: &'a mut BytesMut, start_pos: usize, } impl<'a> BasicEncoder<'a> { fn new(stream: &'a mut RlpStream, start_pos: usize) -> Self { BasicEncoder { buffer: &mut stream.buffer, start_pos } } fn total_written(&self) -> usize { self.buffer.len() - self.start_pos } fn insert_size(&mut self, size: usize, position: usize) -> u8 { let size = size as u32; let leading_empty_bytes = size.leading_zeros() as usize / 8; let size_bytes = 4 - leading_empty_bytes as u8; let buffer: [u8; 4] = size.to_be_bytes(); assert!(position <= self.total_written()); self.buffer.extend_from_slice(&buffer[leading_empty_bytes..]); self.buffer[self.start_pos + position..].rotate_right(size_bytes as usize); size_bytes as u8 } /// Inserts list prefix at given position fn insert_list_payload(&mut self, len: usize, pos: usize) { // 1 byte was already reserved for payload earlier match len { 0..=55 => { self.buffer[self.start_pos + pos - 1] = 0xc0u8 + len as u8; }, _ => { let inserted_bytes = self.insert_size(len, pos); self.buffer[self.start_pos + pos - 1] = 0xf7u8 + inserted_bytes; }, }; } pub fn encode_value(&mut self, value: &[u8]) { self.encode_iter(value.iter().cloned()); } /// Pushes encoded value to the end of buffer pub fn encode_iter(&mut self, value: I) where I: IntoIterator, { let mut value = value.into_iter(); let len = match value.size_hint() { (lower, Some(upper)) if lower == upper => lower, _ => { let value = value.collect::>(); return self.encode_iter(value) }, }; match len { // just 0 0 => self.buffer.put_u8(0x80u8), len @ 1..=55 => { let first = value.next().expect("iterator length is higher than 1"); if len == 1 && first < 0x80 { // byte is its own encoding if < 0x80 self.buffer.put_u8(first); } else { // (prefix + length), followed by the string self.buffer.put_u8(0x80u8 + len as u8); self.buffer.put_u8(first); self.buffer.extend(value); } }, // (prefix + length of length), followed by the length, followd by the string len => { self.buffer.put_u8(0); let position = self.total_written(); let inserted_bytes = self.insert_size(len, position); self.buffer[self.start_pos + position - 1] = 0xb7 + inserted_bytes; self.buffer.extend(value); }, } } } rlp-0.5.2/src/traits.rs000064400000000000000000000015601046102023000130720ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! Common RLP traits use bytes::BytesMut; use crate::{error::DecoderError, rlpin::Rlp, stream::RlpStream}; /// RLP decodable trait pub trait Decodable: Sized { /// Decode a value from RLP bytes fn decode(rlp: &Rlp) -> Result; } /// Structure encodable to RLP pub trait Encodable { /// Append a value to the stream fn rlp_append(&self, s: &mut RlpStream); /// Get rlp-encoded bytes for this instance fn rlp_bytes(&self) -> BytesMut { let mut s = RlpStream::new(); self.rlp_append(&mut s); s.out() } } rlp-0.5.2/tests/tests.rs000064400000000000000000000500711046102023000133020ustar 00000000000000// Copyright 2020 Parity Technologies // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. use core::{cmp, fmt}; use bytes::{Bytes, BytesMut}; use hex_literal::hex; use primitive_types::{H160, U256}; use rlp::{Decodable, DecoderError, Encodable, Rlp, RlpStream}; #[test] fn test_rlp_display() { let data = hex!("f84d0589010efbef67941f79b2a056e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421a0c5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470"); let rlp = Rlp::new(&data); assert_eq!(format!("{}", rlp), "[\"0x05\", \"0x010efbef67941f79b2\", \"0x56e81f171bcc55a6ff8345e692c0f86e5b48e01b996cadc001622fb5e363b421\", \"0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470\"]"); } #[test] fn length_overflow() { let bs = hex!("bfffffffffffffffffffffffe5"); let rlp = Rlp::new(&bs); let res: Result = rlp.as_val(); assert_eq!(Err(DecoderError::RlpInvalidLength), res); } #[test] fn rlp_at() { 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()); let animals: Vec = rlp.as_list().unwrap(); assert_eq!(animals, vec!["cat".to_owned(), "dog".to_owned()]); let cat = rlp.at(0).unwrap(); assert!(cat.is_data()); assert_eq!(cat.as_raw(), &[0x83, b'c', b'a', b't']); assert_eq!(cat.as_val::().unwrap(), "cat".to_owned()); let dog = rlp.at(1).unwrap(); assert!(dog.is_data()); assert_eq!(dog.as_raw(), &[0x83, b'd', b'o', b'g']); assert_eq!(dog.as_val::().unwrap(), "dog".to_owned()); let cat_again = rlp.at(0).unwrap(); assert!(cat_again.is_data()); assert_eq!(cat_again.as_raw(), &[0x83, b'c', b'a', b't']); assert_eq!(cat_again.as_val::().unwrap(), "cat".to_owned()); } } #[test] fn rlp_at_with_offset() { 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()); let animals: Vec = rlp.as_list().unwrap(); assert_eq!(animals, vec!["cat".to_owned(), "dog".to_owned()]); let (cat, cat_offset) = rlp.at_with_offset(0).unwrap(); assert!(cat.is_data()); assert_eq!(cat_offset, 1); assert_eq!(cat.as_raw(), &[0x83, b'c', b'a', b't']); assert_eq!(cat.as_val::().unwrap(), "cat".to_owned()); let (dog, dog_offset) = rlp.at_with_offset(1).unwrap(); assert!(dog.is_data()); assert_eq!(dog_offset, 5); assert_eq!(dog.as_raw(), &[0x83, b'd', b'o', b'g']); assert_eq!(dog.as_val::().unwrap(), "dog".to_owned()); let (cat_again, cat_offset) = rlp.at_with_offset(0).unwrap(); assert!(cat_again.is_data()); assert_eq!(cat_offset, 1); assert_eq!(cat_again.as_raw(), &[0x83, b'c', b'a', b't']); assert_eq!(cat_again.as_val::().unwrap(), "cat".to_owned()); } } #[test] fn rlp_at_err() { let data = vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o']; { let rlp = Rlp::new(&data); assert!(rlp.is_list()); let cat_err = rlp.at(0).unwrap_err(); assert_eq!(cat_err, DecoderError::RlpIsTooShort); let dog_err = rlp.at(1).unwrap_err(); assert_eq!(dog_err, 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 = Rlp::new(&data); let mut iter = rlp.iter(); let cat = iter.next().unwrap(); assert!(cat.is_data()); assert_eq!(cat.as_raw(), &[0x83, b'c', b'a', b't']); let dog = iter.next().unwrap(); assert!(dog.is_data()); assert_eq!(dog.as_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.as_raw(), &[0x83, b'c', b'a', b't']); } } struct ETestPair(T, Vec) where T: Encodable; fn run_encode_tests(tests: Vec>) where T: Encodable, { for t in &tests { let res = rlp::encode(&t.0); assert_eq!(&res[..], &t.1[..]); } } struct VETestPair(Vec, Vec) where T: Encodable; fn run_encode_tests_list(tests: Vec>) where T: Encodable, { for t in &tests { let res = rlp::encode_list(&t.0); assert_eq!(&res[..], &t.1[..]); } } impl From<(T, Repr)> for ETestPair where T: Encodable, Repr: Into>, { fn from((v, repr): (T, Repr)) -> Self { Self(v, repr.into()) } } impl From<(Vec, Repr)> for VETestPair where T: Encodable, Repr: Into>, { fn from((v, repr): (Vec, Repr)) -> Self { Self(v, repr.into()) } } #[test] fn encode_u16() { let tests = vec![ ETestPair::from((0_u16, hex!("80"))), ETestPair::from((0x100_u16, hex!("820100"))), ETestPair::from((0xffff_u16, hex!("82ffff"))), ]; run_encode_tests(tests); } #[test] fn encode_u32() { let tests = vec![ ETestPair::from((0_u32, hex!("80"))), ETestPair::from((0x0001_0000_u32, hex!("83010000"))), ETestPair::from((0x00ff_ffff_u32, hex!("83ffffff"))), ]; run_encode_tests(tests); } #[test] fn encode_u64() { let tests = vec![ ETestPair::from((0_u64, hex!("80"))), ETestPair::from((0x0100_0000_u64, hex!("8401000000"))), ETestPair::from((0xFFFF_FFFF_u64, hex!("84ffffffff"))), ]; run_encode_tests(tests); } #[test] fn encode_u128() { let tests = vec![ ETestPair::from((0_u128, hex!("80"))), ETestPair::from((0x0100_0000_0000_0000_u128, hex!("880100000000000000"))), ETestPair::from((0xFFFF_FFFF_FFFF_FFFF_u128, hex!("88ffffffffffffffff"))), ]; run_encode_tests(tests); } #[test] fn encode_u256() { let tests = vec![ ETestPair::from((U256::from(0_u64), hex!("80"))), ETestPair::from((U256::from(0x0100_0000_u64), hex!("8401000000"))), ETestPair::from((U256::from(0xffff_ffff_u64), hex!("84ffffffff"))), ETestPair::from(( hex!(" 8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").into(), hex!("a08090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0"), )), ]; run_encode_tests(tests); } #[test] fn encode_str() { let tests = vec![ ETestPair::from(("cat", vec![0x83, b'c', b'a', b't'])), ETestPair::from(("dog", vec![0x83, b'd', b'o', b'g'])), ETestPair::from(("Marek", vec![0x85, b'M', b'a', b'r', b'e', b'k'])), ETestPair::from(("", hex!("80"))), ETestPair::from(( "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_into_existing_buffer() { let mut buffer = BytesMut::new(); buffer.extend_from_slice(b"junk"); let mut split_buffer = buffer.split_off(buffer.len()); split_buffer.extend_from_slice(b"!"); let mut s = RlpStream::new_with_buffer(split_buffer); s.append(&"cat"); buffer.unsplit(s.out()); buffer.extend_from_slice(b" and "); let mut s = RlpStream::new_with_buffer(buffer); s.append(&"dog"); let buffer = s.out(); assert_eq!( &buffer[..], &[b'j', b'u', b'n', b'k', b'!', 0x83, b'c', b'a', b't', b' ', b'a', b'n', b'd', b' ', 0x83, b'd', b'o', b'g'] ); } #[test] fn encode_address() { let tests = vec![ETestPair::from(( H160::from(hex!("ef2d6d194084c2de36e0dabfce45d046b37d1106")), hex!("94ef2d6d194084c2de36e0dabfce45d046b37d1106"), ))]; run_encode_tests(tests); } /// Vec (Bytes) is treated as a single value #[test] fn encode_vector_u8() { let tests = vec![ ETestPair::from((vec![], hex!("80"))), ETestPair::from((vec![0u8], hex!("00"))), ETestPair::from((vec![0x15], hex!("15"))), ETestPair::from((vec![0x40, 0x00], hex!("824000"))), ]; run_encode_tests(tests); } #[test] fn encode_bytes() { let tests = vec![ ETestPair::from((Bytes::from_static(&hex!("")), hex!("80"))), ETestPair::from((Bytes::from_static(&hex!("00")), hex!("00"))), ETestPair::from((Bytes::from_static(&hex!("15")), hex!("15"))), ETestPair::from((Bytes::from_static(&hex!("4000")), hex!("824000"))), ]; run_encode_tests(tests); } #[test] fn encode_bytesmut() { let tests = vec![ ETestPair::from((BytesMut::from(&[] as &[u8]), hex!("80"))), ETestPair::from((BytesMut::from(&hex!("00") as &[u8]), hex!("00"))), ETestPair::from((BytesMut::from(&hex!("15") as &[u8]), hex!("15"))), ETestPair::from((BytesMut::from(&hex!("4000") as &[u8]), hex!("824000"))), ]; run_encode_tests(tests); } #[test] fn encode_vector_u64() { let tests = vec![ VETestPair::from((vec![], hex!("c0"))), VETestPair::from((vec![15_u64], hex!("c10f"))), VETestPair::from((vec![1, 2, 3, 7, 0xff], hex!("c60102030781ff"))), VETestPair::from((vec![0xffff_ffff, 1, 2, 3, 7, 0xff], hex!("cb84ffffffff0102030781ff"))), ]; run_encode_tests_list(tests); } #[test] fn encode_vector_str() { let tests = vec![VETestPair(vec!["cat", "dog"], vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'])]; run_encode_tests_list(tests); } #[test] fn clear() { let mut buffer = BytesMut::new(); buffer.extend_from_slice(b"junk"); let mut s = RlpStream::new_with_buffer(buffer); s.append(&"parrot"); s.clear(); s.append(&"cat"); assert_eq!(&s.out()[..], &[b'j', b'u', b'n', b'k', 0x83, b'c', b'a', b't']); } struct DTestPair(T, Vec) where T: Decodable + fmt::Debug + cmp::Eq; struct VDTestPair(Vec, Vec) where T: Decodable + fmt::Debug + cmp::Eq; fn run_decode_tests(tests: Vec>) where T: Decodable + fmt::Debug + cmp::Eq, { for t in &tests { let res: Result = rlp::decode(&t.1); assert!(res.is_ok()); let res = res.unwrap(); assert_eq!(&res, &t.0); } } fn run_decode_tests_list(tests: Vec>) where T: Decodable + fmt::Debug + cmp::Eq, { for t in &tests { let res: Vec = rlp::decode_list(&t.1); assert_eq!(res, t.0); } } impl From<(T, Repr)> for DTestPair where T: Decodable + fmt::Debug + cmp::Eq, Repr: Into>, { fn from((v, repr): (T, Repr)) -> Self { Self(v, repr.into()) } } impl From<(Vec, Repr)> for VDTestPair where T: Decodable + fmt::Debug + cmp::Eq, Repr: Into>, { fn from((v, repr): (Vec, Repr)) -> Self { Self(v, repr.into()) } } /// Vec (Bytes) is treated as a single value #[test] fn decode_vector_u8() { let tests = vec![ DTestPair::from((vec![], hex!("80"))), DTestPair::from((vec![0_u8], hex!("00"))), DTestPair::from((vec![0x15], hex!("15"))), DTestPair::from((vec![0x40, 0x00], hex!("824000"))), ]; run_decode_tests(tests); } #[test] fn decode_bytes() { let tests = vec![ DTestPair::from((Bytes::from_static(&hex!("")), hex!("80"))), DTestPair::from((Bytes::from_static(&hex!("00")), hex!("00"))), DTestPair::from((Bytes::from_static(&hex!("15")), hex!("15"))), DTestPair::from((Bytes::from_static(&hex!("4000")), hex!("824000"))), ]; run_decode_tests(tests); } #[test] fn decode_bytesmut() { let tests = vec![ DTestPair::from((BytesMut::from(&hex!("") as &[u8]), hex!("80"))), DTestPair::from((BytesMut::from(&hex!("00") as &[u8]), hex!("00"))), DTestPair::from((BytesMut::from(&hex!("15") as &[u8]), hex!("15"))), DTestPair::from((BytesMut::from(&hex!("4000") as &[u8]), hex!("824000"))), ]; run_decode_tests(tests); } #[test] fn decode_untrusted_u8() { let tests = vec![ DTestPair::from((0x0_u8, hex!("80"))), DTestPair::from((0x77_u8, hex!("77"))), DTestPair::from((0xcc_u8, hex!("81cc"))), ]; run_decode_tests(tests); } #[test] fn decode_untrusted_u16() { let tests = vec![DTestPair::from((0x100u16, hex!("820100"))), DTestPair::from((0xffffu16, hex!("82ffff")))]; run_decode_tests(tests); } #[test] fn decode_untrusted_u32() { let tests = vec![DTestPair::from((0x0001_0000u32, hex!("83010000"))), DTestPair::from((0x00ff_ffffu32, hex!("83ffffff")))]; run_decode_tests(tests); } #[test] fn decode_untrusted_u64() { let tests = vec![ DTestPair::from((0x0100_0000_u64, hex!("8401000000"))), DTestPair::from((0xFFFF_FFFF_u64, hex!("84ffffffff"))), ]; run_decode_tests(tests); } #[test] fn decode_untrusted_u128() { let tests = vec![ DTestPair::from((0x0100_0000_0000_0000_u128, hex!("880100000000000000"))), DTestPair::from((0xFFFF_FFFF_FFFF_FFFF_u128, hex!("88ffffffffffffffff"))), ]; run_decode_tests(tests); } #[test] fn decode_untrusted_u256() { let tests = vec![ DTestPair::from((U256::from(0_u64), hex!("80"))), DTestPair::from((U256::from(0x0100_0000_u64), hex!("8401000000"))), DTestPair::from((U256::from(0xffff_ffff_u64), hex!("84ffffffff"))), DTestPair::from(( hex!(" 8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0").into(), hex!("a08090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0"), )), ]; run_decode_tests(tests); } #[test] fn decode_untrusted_str() { let tests = vec![ DTestPair::from(("cat".to_owned(), vec![0x83, b'c', b'a', b't'])), DTestPair::from(("dog".to_owned(), vec![0x83, b'd', b'o', b'g'])), DTestPair::from(("Marek".to_owned(), vec![0x85, b'M', b'a', b'r', b'e', b'k'])), DTestPair::from(("".to_owned(), hex!("80"))), DTestPair::from(( "Lorem ipsum dolor sit amet, consectetur adipisicing elit".to_owned(), 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() { let tests = vec![DTestPair::from(( H160::from(hex!("ef2d6d194084c2de36e0dabfce45d046b37d1106")), hex!("94ef2d6d194084c2de36e0dabfce45d046b37d1106"), ))]; run_decode_tests(tests); } #[test] fn decode_untrusted_vector_u64() { let tests = vec![ VDTestPair::from((vec![], hex!("c0"))), VDTestPair::from((vec![15_u64], hex!("c10f"))), VDTestPair::from((vec![1, 2, 3, 7, 0xff], hex!("c60102030781ff"))), VDTestPair::from((vec![0xffff_ffff, 1, 2, 3, 7, 0xff], hex!("cb84ffffffff0102030781ff"))), ]; run_decode_tests_list(tests); } #[test] fn decode_untrusted_vector_str() { let tests = vec![VDTestPair( vec!["cat".to_owned(), "dog".to_owned()], vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g'], )]; run_decode_tests_list(tests); } #[test] fn test_rlp_data_length_check() { let data = vec![0x84, b'c', b'a', b't']; let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); } #[test] fn test_rlp_long_data_length_check() { let mut data = hex!("b8ff").to_vec(); for _ in 0..253 { data.push(b'c'); } let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); } #[test] fn test_the_exact_long_string() { let mut data = hex!("b8ff").to_vec(); for _ in 0..255 { data.push(b'c'); } let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert!(as_val.is_ok()); } #[test] fn test_rlp_2bytes_data_length_check() { let mut data = hex!("b902ff").to_vec(); // 512+255 for _ in 0..700 { data.push(b'c'); } let rlp = Rlp::new(&data); let as_val: Result = rlp.as_val(); assert_eq!(Err(DecoderError::RlpInconsistentLengthAndData), as_val); } #[test] fn test_rlp_nested_empty_list_encode() { let mut stream = RlpStream::new_list(2); stream.append_list(&(Vec::new() as Vec)); stream.append(&0x28_u32); assert_eq!(stream.out()[..], hex!("c2c028")[..]); } #[test] fn test_rlp_list_length_overflow() { let data = hex!("ffffffffffffffffff000000"); let rlp = Rlp::new(&data); let as_val: Result = rlp.val_at(0); assert_eq!(Err(DecoderError::RlpIsTooShort), as_val); } #[test] fn test_rlp_stream_size_limit() { for limit in 40..270 { let item = [0u8; 1]; let mut stream = RlpStream::new(); while stream.append_raw_checked(&item, 1, limit) {} assert_eq!(stream.out().len(), limit); } } #[test] fn test_rlp_stream_unbounded_list() { let mut stream = RlpStream::new(); stream.begin_unbounded_list(); stream.append(&40u32); stream.append(&41u32); assert!(!stream.is_finished()); stream.finalize_unbounded_list(); assert!(stream.is_finished()); } #[test] fn test_rlp_is_int() { for b in 0xb8..0xc0 { let data: Vec = vec![b]; let rlp = Rlp::new(&data); assert!(!rlp.is_int()); } } #[test] fn test_bool_same_as_int() { assert_eq!(rlp::encode(&false), rlp::encode(&0x00u8)); assert_eq!(rlp::encode(&true), rlp::encode(&0x01u8)); let two = rlp::encode(&0x02u8); let invalid: Result = rlp::decode(&two); invalid.unwrap_err(); } // test described in // // https://github.com/paritytech/parity-common/issues/49 #[test] fn test_canonical_string_encoding() { assert_ne!( Rlp::new(&[0xc0 + 4, 0xb7 + 1, 2, b'a', b'b']).val_at::(0), Rlp::new(&[0xc0 + 3, 0x82, b'a', b'b']).val_at::(0) ); assert_eq!( Rlp::new(&[0xc0 + 4, 0xb7 + 1, 2, b'a', b'b']).val_at::(0), Err(DecoderError::RlpInvalidIndirection) ); } // test described in // // https://github.com/paritytech/parity-common/issues/49 #[test] fn test_canonical_list_encoding() { assert_ne!( Rlp::new(&[0xc0 + 3, 0x82, b'a', b'b']).val_at::(0), Rlp::new(&[0xf7 + 1, 3, 0x82, b'a', b'b']).val_at::(0) ); assert_eq!( Rlp::new(&[0xf7 + 1, 3, 0x82, b'a', b'b']).val_at::(0), Err(DecoderError::RlpInvalidIndirection) ); } // test described in // // https://github.com/paritytech/parity-common/issues/48 #[test] fn test_inner_length_capping_for_short_lists() { assert_eq!(Rlp::new(&[0xc0, 0x82, b'a', b'b']).val_at::(0), Err(DecoderError::RlpIsTooShort)); assert_eq!(Rlp::new(&[0xc0 + 1, 0x82, b'a', b'b']).val_at::(0), Err(DecoderError::RlpIsTooShort)); assert_eq!(Rlp::new(&[0xc0 + 2, 0x82, b'a', b'b']).val_at::(0), Err(DecoderError::RlpIsTooShort)); assert_eq!(Rlp::new(&[0xc0 + 3, 0x82, b'a', b'b']).val_at::(0), Ok("ab".to_owned())); assert_eq!(Rlp::new(&[0xc0 + 4, 0x82, b'a', b'b']).val_at::(0), Err(DecoderError::RlpIsTooShort)); } // test described in // // https://github.com/paritytech/parity-common/issues/105 #[test] fn test_nested_list_roundtrip() { #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Inner(u64, u64); impl Encodable for Inner { fn rlp_append(&self, s: &mut RlpStream) { s.begin_unbounded_list() .append(&self.0) .append(&self.1) .finalize_unbounded_list(); } } impl Decodable for Inner { fn decode(rlp: &Rlp<'_>) -> Result { Ok(Inner(rlp.val_at(0)?, rlp.val_at(1)?)) } } #[derive(Debug, Clone, PartialEq, Eq)] struct Nest(Vec); impl Encodable for Nest { fn rlp_append(&self, s: &mut RlpStream) { s.begin_unbounded_list().append_list(&self.0).finalize_unbounded_list(); } } impl Decodable for Nest { fn decode(rlp: &Rlp<'_>) -> Result { Ok(Nest(rlp.list_at(0)?)) } } let items = (0..4).map(|i| Inner(i, i + 1)).collect(); let nest = Nest(items); let encoded = rlp::encode(&nest); let decoded = rlp::decode(&encoded).unwrap(); assert_eq!(nest, decoded); let nest2 = Nest(vec![nest.clone(), nest]); let encoded = rlp::encode(&nest2); let decoded = rlp::decode(&encoded).unwrap(); assert_eq!(nest2, decoded); } // test described in // // https://github.com/paritytech/parity-ethereum/pull/9663 #[test] fn test_list_at() { let raw = hex!("f83e82022bd79020010db83c4d001500000000abcdef12820cfa8215a8d79020010db885a308d313198a2e037073488208ae82823a8443b9a355c5010203040531b9019afde696e582a78fa8d95ea13ce3297d4afb8ba6433e4154caa5ac6431af1b80ba76023fa4090c408f6b4bc3701562c031041d4702971d102c9ab7fa5eed4cd6bab8f7af956f7d565ee1917084a95398b6a21eac920fe3dd1345ec0a7ef39367ee69ddf092cbfe5b93e5e568ebc491983c09c76d922dc3"); let rlp = Rlp::new(&raw); let _rlp1 = rlp.at(1).unwrap(); let rlp2 = rlp.at(2).unwrap(); assert_eq!(rlp2.val_at::(2).unwrap(), 33338); }