diff --git a/.travis.yml b/.travis.yml index e4ce037d8..a878ee064 100644 --- a/.travis.yml +++ b/.travis.yml @@ -27,15 +27,15 @@ script: - cargo build --all - cargo test --all --exclude uint --exclude fixed-hash - if [ "$TRAVIS_RUST_VERSION" == "nightly" ]; then - cd fixed-hash/ && cargo test --no-default-features --features="rustc-hex,byteorder" && cd ..; - cd keccak-hash/ && cargo test --no-default-features && cd ..; cd contract-address/ && cargo test --features=external_doc && cd ..; fi - - cd ethbloom/ && cargo test --no-default-features --features="rustc-hex" && cargo test --benches && cd .. - - cd fixed-hash/ && cargo test --all-features && cd .. - - cd uint/ && cargo test --features=std,quickcheck --release && cd .. + - cd ethbloom/ && cargo test --no-default-features --features="rustc-hex" && cargo check --benches && cd .. + - cd fixed-hash/ && cargo test --all-features && cargo test --no-default-features --features="byteorder,rustc-hex" && cd .. + - cd uint/ && cargo test --all-features && cargo test --no-default-features && cd .. + - cd keccak-hash/ && cargo test --no-default-features && cd .. - cd plain_hasher/ && cargo test --no-default-features && cargo check --benches && cd .. - cd parity-bytes/ && cargo test --no-default-features && cd .. - cd parity-util-mem/ && cargo test --features=estimate-heapsize && cd .. - cd parity-util-mem/ && cargo test --features=jemalloc-global && cd .. - cd parity-util-mem/ && cargo test --features=mimalloc-global && cd .. + - cd rlp/ && cargo test --no-default-features && cargo check --benches && cd .. diff --git a/primitive-types/Cargo.toml b/primitive-types/Cargo.toml index cf19f7d27..178826eef 100644 --- a/primitive-types/Cargo.toml +++ b/primitive-types/Cargo.toml @@ -21,4 +21,4 @@ libc = ["fixed-hash/libc"] rustc-hex = ["fixed-hash/rustc-hex"] serde = ["std", "impl-serde"] codec = ["impl-codec"] -rlp = ["std", "impl-rlp"] +rlp = ["impl-rlp"] diff --git a/primitive-types/impls/rlp/Cargo.toml b/primitive-types/impls/rlp/Cargo.toml index 7f0ee2696..f2de4e8ba 100644 --- a/primitive-types/impls/rlp/Cargo.toml +++ b/primitive-types/impls/rlp/Cargo.toml @@ -7,4 +7,8 @@ homepage = "https://github.com/paritytech/parity-common" description = "RLP serialization support for uint and fixed hash." [dependencies] -rlp = { version = "0.4", path = "../../../rlp" } +rlp = { version = "0.4", path = "../../../rlp", default-features = false } + +[features] +default = ["std"] +std = ["rlp/std"] diff --git a/primitive-types/impls/rlp/src/lib.rs b/primitive-types/impls/rlp/src/lib.rs index 56f34328c..dffbfe96b 100644 --- a/primitive-types/impls/rlp/src/lib.rs +++ b/primitive-types/impls/rlp/src/lib.rs @@ -8,6 +8,8 @@ //! RLP serialization support for uint and fixed hash. +#![cfg_attr(not(feature = "std"), no_std)] + #[doc(hidden)] pub extern crate rlp; diff --git a/rlp/Cargo.toml b/rlp/Cargo.toml index 8795f84ec..0ad6d40ea 100644 --- a/rlp/Cargo.toml +++ b/rlp/Cargo.toml @@ -8,8 +8,18 @@ authors = ["Parity Technologies "] edition = "2018" [dependencies] -rustc-hex = {version = "2.0", default-features = false } +rustc-hex = { version = "2.0", default-features = false } [dev-dependencies] +criterion = "0.3" hex-literal = "0.2" primitive-types = { path = "../primitive-types", version = "0.5", features = ["impl-rlp"] } + +[features] +default = ["std"] +std = ["rustc-hex/std"] + +[[bench]] +name = "rlp" +path = "benches/rlp.rs" +harness = false diff --git a/rlp/benches/rlp.rs b/rlp/benches/rlp.rs index 606f20a4d..e874cb0da 100644 --- a/rlp/benches/rlp.rs +++ b/rlp/benches/rlp.rs @@ -7,111 +7,97 @@ // except according to those terms. //! benchmarking for rlp -//! should be started with: -//! ```bash -//! multirust run nightly cargo bench -//! ``` -#![feature(test)] +use criterion::{criterion_group, criterion_main, Criterion}; -// TODO: get rid of this one fine day: https://doc.rust-lang.org/nightly/edition-guide/rust-2018/module-system/path-clarity.html#an-exception -extern crate test; - -use primitive_types::U256; -use rlp::{RlpStream, Rlp}; -use test::Bencher; - -#[bench] -fn bench_stream_u64_value(b: &mut Bencher) { - b.iter(|| { - // u64 - let mut stream = RlpStream::new(); - stream.append(&0x1023456789abcdefu64); +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(); - }); -} - -#[bench] -fn bench_decode_u64_value(b: &mut Bencher) { - b.iter(|| { - // u64 - let data = vec![0x88, 0x10, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]; - let rlp = Rlp::new(&data); - let _: u64 = rlp.as_val().unwrap(); - }); -} - -#[bench] -fn bench_stream_u256_value(b: &mut Bencher) { - b.iter(|| { - // u256 - let mut stream = RlpStream::new(); - let uint: U256 = "8090a0b0c0d0e0f00910203040506077000000000000000100000000000012f0".into(); + })); + 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(); - }); -} - -#[bench] -fn bench_decode_u256_value(b: &mut Bencher) { - b.iter(|| { - // u256 - 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::new(&data); - let _ : U256 = rlp.as_val().unwrap(); - }); -} - -#[bench] -fn bench_stream_nested_empty_lists(b: &mut Bencher) { - b.iter(|| { + })); + 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 = RlpStream::new_list(3); + 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(); + })); } -#[bench] -fn bench_decode_nested_empty_lists(b: &mut Bencher) { - b.iter(|| { +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::new(&data); + 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(); - }); -} - -#[bench] -fn bench_stream_1000_empty_lists(b: &mut Bencher) { - b.iter(|| { - let mut stream = RlpStream::new_list(1000); + })); + 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 _ = stream.out(); + 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(); + } + }); }); } -#[bench] -fn bench_decode_1000_values(b: &mut Bencher) { - let mut stream = RlpStream::new_list(1000); - for _ in 0..1000 { - stream.append(&U256::from(1)); - } - let data= stream.out(); - b.iter(|| { - let rlp = Rlp::new(&data); - for i in 0..1000 { - let _: U256 = rlp.val_at(i).unwrap(); - } - }); -} +criterion_group!(benches, bench_encode, bench_decode); +criterion_main!(benches); diff --git a/rlp/src/error.rs b/rlp/src/error.rs index 7aef6cfbf..d810130b0 100644 --- a/rlp/src/error.rs +++ b/rlp/src/error.rs @@ -6,7 +6,8 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::fmt; +use core::fmt; +#[cfg(feature = "std")] use std::error::Error as StdError; #[derive(Debug, PartialEq, Eq, Clone)] @@ -36,6 +37,7 @@ pub enum DecoderError { Custom(&'static str), } +#[cfg(feature = "std")] impl StdError for DecoderError { fn description(&self) -> &str { "builder error" diff --git a/rlp/src/impls.rs b/rlp/src/impls.rs index c478d3a22..3fbf3cf20 100644 --- a/rlp/src/impls.rs +++ b/rlp/src/impls.rs @@ -6,11 +6,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::{mem, str}; -use std::iter::{once, empty}; -use crate::traits::{Encodable, Decodable}; +#[cfg(not(feature = "std"))] +use alloc::{borrow::ToOwned, vec::Vec, string::String}; +use core::{mem, str}; +use core::iter::{once, empty}; + +use crate::error::DecoderError; +use crate::rlpin::Rlp; use crate::stream::RlpStream; -use crate::{Rlp, DecoderError}; +use crate::traits::{Encodable, Decodable}; pub fn decode_usize(bytes: &[u8]) -> Result { match bytes.len() { @@ -19,9 +23,9 @@ pub fn decode_usize(bytes: &[u8]) -> Result { return Err(DecoderError::RlpInvalidIndirection); } let mut res = 0usize; - for i in 0..l { + for (i, byte) in bytes.iter().enumerate().take(l) { let shift = (l - 1 - i) * 8; - res = res + ((bytes[i] as usize) << shift); + res += (*byte as usize) << shift; } Ok(res) } @@ -139,9 +143,9 @@ macro_rules! impl_decodable_for_u { return Err(DecoderError::RlpInvalidIndirection); } let mut res = 0 as $name; - for i in 0..l { + for (i, byte) in bytes.iter().enumerate().take(l) { let shift = (l - 1 - i) * 8; - res = res + ((bytes[i] as $name) << shift); + res += (*byte as $name) << shift; } Ok(res) } diff --git a/rlp/src/lib.rs b/rlp/src/lib.rs index e85c1a0db..1baa52c2f 100644 --- a/rlp/src/lib.rs +++ b/rlp/src/lib.rs @@ -32,7 +32,10 @@ //! * You want to get view onto rlp-slice. //! * You don't want to decode whole rlp at once. -use std::borrow::Borrow; +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(not(feature = "std"))] +extern crate alloc; mod traits; mod error; @@ -40,10 +43,14 @@ mod rlpin; mod stream; mod impls; -pub use crate::error::DecoderError; -pub use crate::traits::{Decodable, Encodable}; -pub use crate::rlpin::{Rlp, RlpIterator, PayloadInfo, Prototype}; -pub use crate::stream::RlpStream; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; +use core::borrow::Borrow; + +pub use self::error::DecoderError; +pub use self::rlpin::{Rlp, RlpIterator, PayloadInfo, Prototype}; +pub use self::stream::RlpStream; +pub use self::traits::{Decodable, Encodable}; /// The RLP encoded empty data (used to mean "null value"). pub const NULL_RLP: [u8; 1] = [0x80; 1]; diff --git a/rlp/src/rlpin.rs b/rlp/src/rlpin.rs index be3f30224..0d8c9ad2a 100644 --- a/rlp/src/rlpin.rs +++ b/rlp/src/rlpin.rs @@ -6,11 +6,16 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::cell::Cell; -use std::fmt; +#[cfg(not(feature = "std"))] +use alloc::{string::String, vec::Vec}; +use core::cell::Cell; +use core::fmt; + use rustc_hex::ToHex; + +use crate::error::DecoderError; use crate::impls::decode_usize; -use crate::{Decodable, DecoderError}; +use crate::traits::Decodable; /// rlp offset #[derive(Copy, Clone, Debug)] @@ -21,10 +26,7 @@ struct OffsetCache { impl OffsetCache { fn new(index: usize, offset: usize) -> OffsetCache { - OffsetCache { - index: index, - offset: offset, - } + OffsetCache { index, offset } } } @@ -67,10 +69,7 @@ fn calculate_payload_info(header_bytes: &[u8], len_of_len: usize) -> Result PayloadInfo { - PayloadInfo { - header_len: header_len, - value_len: value_len, - } + PayloadInfo { header_len, value_len } } /// Total size of the RLP. @@ -129,7 +128,7 @@ impl<'a> fmt::Display for Rlp<'a> { impl<'a> Rlp<'a> { pub fn new(bytes: &'a [u8]) -> Rlp<'a> { Rlp { - bytes: bytes, + bytes, offset_cache: Cell::new(None), count_cache: Cell::new(None) } @@ -160,24 +159,26 @@ impl<'a> Rlp<'a> { } pub fn item_count(&self) -> Result { - match self.is_list() { - true => match self.count_cache.get() { + 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) } - }, - false => Err(DecoderError::RlpExpectedToBeList), + } + } else { + Err(DecoderError::RlpExpectedToBeList) } } pub fn size(&self) -> usize { - match self.is_data() { + if self.is_data() { // TODO: No panic on malformed data, but ideally would Err on no PayloadInfo. - true => BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0), - false => 0 + BasicDecoder::payload_info(self.bytes).map(|b| b.value_len).unwrap_or(0) + } else { + 0 } } @@ -211,7 +212,7 @@ impl<'a> Rlp<'a> { } pub fn is_null(&self) -> bool { - self.bytes.len() == 0 + self.bytes.is_empty() } pub fn is_empty(&self) -> bool { @@ -290,9 +291,10 @@ impl<'a> Rlp<'a> { /// 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) + if bytes.len() >= len { + Ok(&bytes[len..]) + } else { + Err(DecoderError::RlpIsTooShort) } } } @@ -384,24 +386,3 @@ impl<'a> BasicDecoder<'a> { } } } - -#[cfg(test)] -mod tests { - use crate::{Rlp, DecoderError}; - use hex_literal::hex; - - #[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 = [0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5]; - let rlp = Rlp::new(&bs); - let res: Result = rlp.as_val(); - assert_eq!(Err(DecoderError::RlpInvalidLength), res); - } -} diff --git a/rlp/src/stream.rs b/rlp/src/stream.rs index 7aa8d80e4..cfddc2d95 100644 --- a/rlp/src/stream.rs +++ b/rlp/src/stream.rs @@ -6,7 +6,10 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use std::borrow::Borrow; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; +use core::borrow::Borrow; + use crate::traits::Encodable; #[derive(Debug, Copy, Clone)] @@ -86,7 +89,7 @@ impl RlpStream { } /// 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 Self { + pub fn append_raw(&mut self, bytes: &[u8], item_count: usize) -> &mut Self { // push raw items self.buffer.extend_from_slice(bytes); @@ -110,7 +113,7 @@ impl RlpStream { /// 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, value: &E) -> &'a mut Self where E: Encodable { + pub fn append(&mut self, value: &E) -> &mut Self where E: Encodable { self.finished_list = false; value.rlp_append(self); if !self.finished_list { @@ -132,7 +135,7 @@ impl RlpStream { /// assert_eq!(out, vec![0xc8, 0x83, b'c', b'a', b't', 0x83, b'd', b'o', b'g']); /// } /// ``` - pub fn append_iter<'a, I>(&'a mut self, value: I) -> &'a mut Self + pub fn append_iter(&mut self, value: I) -> &mut Self where I: IntoIterator, { self.finished_list = false; @@ -144,7 +147,7 @@ impl RlpStream { } /// Appends list of values to the end of stream, chainable. - pub fn append_list<'a, E, K>(&'a mut self, values: &[K]) -> &'a mut Self where E: Encodable, K: Borrow { + 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()); @@ -154,7 +157,7 @@ impl RlpStream { /// 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<'a, E>(&'a mut self, value: &E) -> &'a mut Self where E: Encodable { + pub fn append_internal(&mut self, value: &E) -> &mut Self where E: Encodable { value.rlp_append(self); self } @@ -209,7 +212,7 @@ impl RlpStream { } /// Appends raw (pre-serialised) RLP data. Checks for size oveflow. - pub fn append_raw_checked<'a>(&'a mut self, bytes: &[u8], item_count: usize, max_size: usize) -> bool { + 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; } @@ -218,7 +221,7 @@ impl RlpStream { } /// Calculate total RLP size for appended payload. - pub fn estimate_size<'a>(&'a self, add: usize) -> usize { + pub fn estimate_size(&self, add: usize) -> usize { let total_size = self.buffer.len() + add; let mut base_size = total_size; for list in &self.unfinished_lists[..] { @@ -233,10 +236,14 @@ impl RlpStream { } /// Returns current RLP size in bytes for the data pushed into the list. - pub fn len<'a>(&'a self) -> usize { + pub fn len(&self) -> usize { self.estimate_size(0) } + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + /// Clear the output stream so far. /// /// ```rust @@ -275,7 +282,7 @@ impl RlpStream { /// 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 + self.unfinished_lists.is_empty() } /// Get raw encoded bytes @@ -288,15 +295,16 @@ impl RlpStream { /// /// panic! if stream is not finished. pub fn out(self) -> Vec { - match self.is_finished() { - true => self.buffer, - false => panic!() + if self.is_finished() { + self.buffer + } else { + panic!() } } /// Try to finish lists fn note_appended(&mut self, inserted_items: usize) { - if self.unfinished_lists.len() == 0 { + if self.unfinished_lists.is_empty() { return; } @@ -394,7 +402,7 @@ impl<'a> BasicEncoder<'a> { match len { // just 0 0 => self.buffer.push(0x80u8), - len @ 1 ..= 55 => { + 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 diff --git a/rlp/src/traits.rs b/rlp/src/traits.rs index b5502bb15..13531a1b6 100644 --- a/rlp/src/traits.rs +++ b/rlp/src/traits.rs @@ -7,7 +7,12 @@ // except according to those terms. //! Common RLP traits -use crate::{DecoderError, Rlp, RlpStream}; +#[cfg(not(feature = "std"))] +use alloc::vec::Vec; + +use crate::error::DecoderError; +use crate::rlpin::Rlp; +use crate::stream::RlpStream; /// RLP decodable trait pub trait Decodable: Sized { diff --git a/rlp/tests/tests.rs b/rlp/tests/tests.rs index 455f1055a..ba5a423b7 100644 --- a/rlp/tests/tests.rs +++ b/rlp/tests/tests.rs @@ -6,10 +6,26 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::{fmt, cmp}; + +use hex_literal::hex; use primitive_types::{H160, U256}; -use std::{fmt, cmp}; use rlp::{Encodable, Decodable, Rlp, RlpStream, DecoderError}; -use hex_literal::hex; + +#[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 = [0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe5]; + let rlp = Rlp::new(&bs); + let res: Result = rlp.as_val(); + assert_eq!(Err(DecoderError::RlpInvalidLength), res); +} #[test] fn rlp_at() { @@ -112,8 +128,8 @@ fn encode_u16() { fn encode_u32() { let tests = vec![ ETestPair(0u32, vec![0x80u8]), - ETestPair(0x10000, vec![0x83, 0x01, 0x00, 0x00]), - ETestPair(0xffffff, vec![0x83, 0xff, 0xff, 0xff]), + ETestPair(0x0001_0000, vec![0x83, 0x01, 0x00, 0x00]), + ETestPair(0x00ff_ffff, vec![0x83, 0xff, 0xff, 0xff]), ]; run_encode_tests(tests); } @@ -122,8 +138,8 @@ fn encode_u32() { 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]), + ETestPair(0x0100_0000, vec![0x84, 0x01, 0x00, 0x00, 0x00]), + ETestPair(0xFFFF_FFFF, vec![0x84, 0xff, 0xff, 0xff, 0xff]), ]; run_encode_tests(tests); } @@ -131,8 +147,8 @@ fn encode_u64() { #[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), + ETestPair(U256::from(0x0100_0000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + ETestPair(U256::from(0xffff_ffffu64), vec![0x84, 0xff, 0xff, 0xff, 0xff]), ETestPair(("8090a0b0c0d0e0f00910203040506077000000000000\ 000100000000000012f0").into(), @@ -189,7 +205,7 @@ fn encode_vector_u64() { VETestPair(vec![], vec![0xc0]), VETestPair(vec![15u64], vec![0xc1, 0x0f]), VETestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), - VETestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), + VETestPair(vec![0xffff_ffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), ]; run_encode_tests_list(tests); } @@ -255,8 +271,8 @@ fn decode_untrusted_u16() { #[test] fn decode_untrusted_u32() { let tests = vec![ - DTestPair(0x10000u32, vec![0x83, 0x01, 0x00, 0x00]), - DTestPair(0xffffffu32, vec![0x83, 0xff, 0xff, 0xff]), + DTestPair(0x0001_0000u32, vec![0x83, 0x01, 0x00, 0x00]), + DTestPair(0x00ff_ffffu32, vec![0x83, 0xff, 0xff, 0xff]), ]; run_decode_tests(tests); } @@ -264,8 +280,8 @@ fn decode_untrusted_u32() { #[test] fn decode_untrusted_u64() { let tests = vec![ - DTestPair(0x1000000u64, vec![0x84, 0x01, 0x00, 0x00, 0x00]), - DTestPair(0xFFFFFFFFu64, vec![0x84, 0xff, 0xff, 0xff, 0xff]), + DTestPair(0x0100_0000u64, vec![0x84, 0x01, 0x00, 0x00, 0x00]), + DTestPair(0xFFFF_FFFFu64, vec![0x84, 0xff, 0xff, 0xff, 0xff]), ]; run_decode_tests(tests); } @@ -273,8 +289,8 @@ fn decode_untrusted_u64() { #[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), + DTestPair(U256::from(0x0100_0000u64), vec![0x84, 0x01, 0x00, 0x00, 0x00]), + DTestPair(U256::from(0xffff_ffffu64), vec![0x84, 0xff, 0xff, 0xff, 0xff]), DTestPair(("8090a0b0c0d0e0f00910203040506077000000000000\ 000100000000000012f0").into(), @@ -321,7 +337,7 @@ fn decode_untrusted_vector_u64() { VDTestPair(vec![], vec![0xc0]), VDTestPair(vec![15u64], vec![0xc1, 0x0f]), VDTestPair(vec![1, 2, 3, 7, 0xff], vec![0xc6, 1, 2, 3, 7, 0x81, 0xff]), - VDTestPair(vec![0xffffffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), + VDTestPair(vec![0xffff_ffff, 1, 2, 3, 7, 0xff], vec![0xcb, 0x84, 0xff, 0xff, 0xff, 0xff, 1, 2, 3, 7, 0x81, 0xff]), ]; run_decode_tests_list(tests); } @@ -437,12 +453,12 @@ fn test_rlp_is_int() { #[test] fn test_canonical_string_encoding() { assert_ne!( - Rlp::new(&vec![0xc0 + 4, 0xb7 + 1, 2, b'a', b'b']).val_at::(0), - Rlp::new(&vec![0xc0 + 3, 0x82, b'a', b'b']).val_at::(0) + 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(&vec![0xc0 + 4, 0xb7 + 1, 2, b'a', b'b']).val_at::(0), + Rlp::new(&[0xc0 + 4, 0xb7 + 1, 2, b'a', b'b']).val_at::(0), Err(DecoderError::RlpInvalidIndirection) ); } @@ -453,12 +469,12 @@ fn test_canonical_string_encoding() { #[test] fn test_canonical_list_encoding() { assert_ne!( - Rlp::new(&vec![0xc0 + 3, 0x82, b'a', b'b']).val_at::(0), - Rlp::new(&vec![0xf7 + 1, 3, 0x82, b'a', b'b']).val_at::(0) + 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(&vec![0xf7 + 1, 3, 0x82, b'a', b'b']).val_at::(0), + Rlp::new(&[0xf7 + 1, 3, 0x82, b'a', b'b']).val_at::(0), Err(DecoderError::RlpInvalidIndirection) ); } @@ -468,11 +484,11 @@ fn test_canonical_list_encoding() { // https://github.com/paritytech/parity-common/issues/48 #[test] fn test_inner_length_capping_for_short_lists() { - assert_eq!(Rlp::new(&vec![0xc0 + 0, 0x82, b'a', b'b']).val_at::(0), Err(DecoderError::RlpIsTooShort)); - assert_eq!(Rlp::new(&vec![0xc0 + 1, 0x82, b'a', b'b']).val_at::(0), Err(DecoderError::RlpIsTooShort)); - assert_eq!(Rlp::new(&vec![0xc0 + 2, 0x82, b'a', b'b']).val_at::(0), Err(DecoderError::RlpIsTooShort)); - assert_eq!(Rlp::new(&vec![0xc0 + 3, 0x82, b'a', b'b']).val_at::(0), Ok("ab".to_owned())); - assert_eq!(Rlp::new(&vec![0xc0 + 4, 0x82, b'a', b'b']).val_at::(0), Err(DecoderError::RlpIsTooShort)); + 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