diff --git a/Cargo.lock b/Cargo.lock
index 8d2796c91a2..1f09415cf17 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -3407,6 +3407,7 @@ dependencies = [
name = "patricia-trie-ethereum"
version = "0.1.0"
dependencies = [
+ "criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"elastic-array 0.10.2 (registry+https://github.com/rust-lang/crates.io-index)",
"ethereum-types 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"hash-db 0.15.2 (registry+https://github.com/rust-lang/crates.io-index)",
diff --git a/util/patricia-trie-ethereum/Cargo.toml b/util/patricia-trie-ethereum/Cargo.toml
index b8b902f33ff..cc7e8ce8fe2 100644
--- a/util/patricia-trie-ethereum/Cargo.toml
+++ b/util/patricia-trie-ethereum/Cargo.toml
@@ -18,3 +18,8 @@ elastic-array = "0.10"
memory-db = "0.15.0"
keccak-hash = "0.4.0"
journaldb = { path = "../journaldb" }
+criterion = "0.3"
+
+[[bench]]
+name = "rlp_node_codec"
+harness = false
diff --git a/util/patricia-trie-ethereum/benches/rlp_node_codec.rs b/util/patricia-trie-ethereum/benches/rlp_node_codec.rs
new file mode 100644
index 00000000000..d16dd3c4d85
--- /dev/null
+++ b/util/patricia-trie-ethereum/benches/rlp_node_codec.rs
@@ -0,0 +1,83 @@
+// Copyright 2015-2019 Parity Technologies (UK) Ltd.
+// This file is part of Parity Ethereum.
+
+// Parity Ethereum is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+
+// Parity Ethereum is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License
+// along with Parity Ethereum. If not, see .
+
+//! Benchmarking RlpNodeCodec decoding performance
+
+extern crate criterion;
+extern crate patricia_trie_ethereum as ethtrie;
+extern crate trie_db;
+extern crate ethereum_types;
+extern crate rlp;
+
+use criterion::{Criterion, criterion_group, criterion_main};
+use ethereum_types::H256;
+use ethtrie::RlpNodeCodec;
+use rlp::RlpStream;
+use trie_db::NodeCodec;
+
+fn decoding(c: &mut Criterion) {
+ c.bench_function("decode leaf (inline)", |b| {
+ let mut stream = RlpStream::new_list(2);
+ stream.append(&"cat").append(&"dog");
+ let data = stream.out();
+ b.iter(|| { RlpNodeCodec::decode(&data) });
+ });
+
+ c.bench_function("decode extension (inline)", |b| {
+ let mut stream = RlpStream::new_list(2);
+ let payload = vec![0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9u8];
+ stream.append(&"").append(&payload);
+ let data = stream.out();
+ b.iter(|| { RlpNodeCodec::decode(&data) });
+ });
+
+ c.bench_function("decode extension (hash)", |b| {
+ let mut stream = RlpStream::new_list(2);
+ let payload = H256::random();
+ stream.append(&"").append(&payload);
+ let data = stream.out();
+ b.iter(|| { RlpNodeCodec::decode(&data) });
+ });
+
+ c.bench_function("decode branch (hash)", |b| {
+ let mut stream = RlpStream::new_list(17);
+ for _ in 0..17 {
+ stream.append(&H256::random());
+
+ }
+ let data = stream.out();
+ b.iter(|| { RlpNodeCodec::decode(&data) });
+ });
+
+ c.bench_function("decode branch (inline)", |b| {
+ let mut stream = RlpStream::new_list(17);
+ for _ in 0..17 {
+ stream.append(&[&H256::random().as_bytes(), H256::random().as_bytes()].concat());
+ }
+ let data = stream.out();
+ b.iter(|| { RlpNodeCodec::decode(&data) });
+ });
+
+ c.bench_function("decode empty data", |b| {
+ let mut stream = RlpStream::new();
+ stream.append_empty_data();
+ let data = stream.out();
+ b.iter(|| { RlpNodeCodec::decode(&data)});
+ });
+}
+
+criterion_group!(benches, decoding);
+criterion_main!(benches);
diff --git a/util/patricia-trie-ethereum/src/lib.rs b/util/patricia-trie-ethereum/src/lib.rs
index d7b6a261c8e..0ed733283c5 100644
--- a/util/patricia-trie-ethereum/src/lib.rs
+++ b/util/patricia-trie-ethereum/src/lib.rs
@@ -148,11 +148,11 @@ pub type Result = trie::Result;
#[cfg(test)]
mod tests {
-
use ethereum_types::H256;
- use crate::{TrieDB, TrieDBMut, trie::TrieMut};
use trie::Trie;
+ use crate::{TrieDB, TrieDBMut, trie::TrieMut};
+
#[test]
fn test_inline_encoding_branch() {
let mut memdb = journaldb::new_memory_db();
diff --git a/util/patricia-trie-ethereum/src/rlp_node_codec.rs b/util/patricia-trie-ethereum/src/rlp_node_codec.rs
index d44534365f9..73a65d5f360 100644
--- a/util/patricia-trie-ethereum/src/rlp_node_codec.rs
+++ b/util/patricia-trie-ethereum/src/rlp_node_codec.rs
@@ -24,11 +24,10 @@ use std::marker::PhantomData;
use std::borrow::Borrow;
use std::ops::Range;
use trie::{
- NodeCodec, ChildReference, Partial, node::{NibbleSlicePlan, NodePlan, NodeHandlePlan},
+ NodeCodec, ChildReference, Partial,
+ node::{NibbleSlicePlan, NodePlan, NodeHandlePlan},
};
-
-
/// Concrete implementation of a `NodeCodec` with Rlp encoding, generic over the `Hasher`
#[derive(Default, Clone)]
pub struct RlpNodeCodec {mark: PhantomData}
@@ -98,7 +97,7 @@ impl NodeCodec for RlpNodeCodec {
HASHED_NULL_NODE
}
- fn decode_plan(data: &[u8]) -> ::std::result::Result {
+ fn decode_plan(data: &[u8]) -> Result {
let r = Rlp::new(data);
match r.prototype()? {
// either leaf or extension - decode first item with NibbleSlice::???
@@ -230,3 +229,51 @@ impl NodeCodec for RlpNodeCodec {
}
}
+
+#[cfg(test)]
+mod tests {
+ use trie::{NodeCodec, node::{Node, NodeHandle}, NibbleSlice};
+ use rlp::RlpStream;
+ use RlpNodeCodec;
+
+ #[test]
+ fn decode_leaf() {
+ let mut stream = RlpStream::new_list(2);
+ stream.append(&"cat").append(&"dog");
+ let data = stream.out();
+ let r = RlpNodeCodec::decode(&data);
+ assert!(r.is_ok());
+ // "c" & 16 != 16 => `start` == 1
+ let cat_nib = NibbleSlice::new(&b"at"[..]);
+ assert_eq!(r.unwrap(), Node::Leaf(cat_nib, &b"dog"[..]));
+ }
+
+ #[test]
+ fn decode_ext() {
+ let mut stream = RlpStream::new_list(2);
+ let payload = vec![0x1, 0x2, 0x3u8];
+ stream.append(&"").append(&payload);
+ let data = stream.out();
+ let decoded = RlpNodeCodec::decode(&data);
+
+ assert!(decoded.is_ok());
+ assert_eq!(
+ decoded.unwrap(),
+ Node::Extension(
+ NibbleSlice::new(&[]),
+ NodeHandle::Inline(&[0x80 + 0x3, 0x1, 0x2, 0x3])
+ )
+ );
+ }
+
+ #[test]
+ fn decode_empty_data() {
+ let mut stream = RlpStream::new();
+ stream.append_empty_data();
+ let data = stream.out();
+ assert_eq!(
+ RlpNodeCodec::decode(&data),
+ Ok(Node::Empty),
+ );
+ }
+}