Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,4 @@ script:
- 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 ..
- cd triehash/ && cargo check --benches && cd ..
12 changes: 10 additions & 2 deletions triehash/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,21 @@ authors = ["Parity Technologies <admin@parity.io>"]
description = "In-memory patricia trie operations"
repository = "https://github.com/paritytech/parity-common"
license = "GPL-3.0"
edition = "2018"

[dependencies]
hash-db = "0.15"
rlp = { version = "0.4", path = "../rlp" }

[dev-dependencies]
criterion = "0.3"
keccak-hasher = "0.15"
tiny-keccak = "1.4.2"
ethereum-types = { version = "0.7", path = "../ethereum-types" }
tiny-keccak = "1.5"
trie-standardmap = "0.15"
hex-literal = "0.2"
ethereum-types = { version = "0.7", path = "../ethereum-types" }

[[bench]]
name = "triehash"
path = "benches/triehash.rs"
harness = false
169 changes: 72 additions & 97 deletions triehash/benches/triehash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,16 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.

#![feature(test)]

extern crate ethereum_types;
extern crate keccak_hasher;
extern crate test;
extern crate tiny_keccak;
extern crate trie_standardmap;
extern crate triehash;

use criterion::{criterion_group, criterion_main, Criterion};
use ethereum_types::H256;
use keccak_hasher::KeccakHasher;
use test::Bencher;
use tiny_keccak::keccak256;
use trie_standardmap::{Alphabet, ValueMode, StandardMap};
use trie_standardmap::{Alphabet, StandardMap, ValueMode};
use triehash::trie_root;

fn random_word(alphabet: &[u8], min_count: usize, diff_count: usize, seed: &mut H256) -> Vec<u8> {
assert!(min_count + diff_count <= 32);
*seed = H256(keccak256(&seed));
*seed = H256(keccak256(seed.as_bytes()));
let r = min_count + (seed[31] as usize % (diff_count + 1));
let mut ret: Vec<u8> = Vec::with_capacity(r);
for i in 0..r {
Expand All @@ -43,107 +34,91 @@ fn random_word(alphabet: &[u8], min_count: usize, diff_count: usize, seed: &mut

fn random_bytes(min_count: usize, diff_count: usize, seed: &mut H256) -> Vec<u8> {
assert!(min_count + diff_count <= 32);
*seed = H256(keccak256(&seed));
*seed = H256(keccak256(seed.as_bytes()));
let r = min_count + (seed[31] as usize % (diff_count + 1));
seed[0..r].to_vec()
}

fn random_value(seed: &mut H256) -> Vec<u8> {
*seed = H256(keccak256(&seed));
*seed = H256(keccak256(seed.as_bytes()));
match seed[0] % 2 {
1 => vec![seed[31];1],
_ => seed.to_vec(),
_ => seed.as_bytes().to_vec(),
}
}

#[bench]
fn triehash_insertions_32_mir_1k(b: &mut Bencher) {
let st = StandardMap {
alphabet: Alphabet::All,
min_key: 32,
journal_key: 0,
value_mode: ValueMode::Mirror,
count: 1000,
};
let d = st.make();
b.iter(&mut ||{
let _ = trie_root::<KeccakHasher, _, _, _>(d.clone()).clone();
fn bench_insertions(c: &mut Criterion) {
c.bench_function("32_mir_1k", |b| {
let st = StandardMap {
alphabet: Alphabet::All,
min_key: 32,
journal_key: 0,
value_mode: ValueMode::Mirror,
count: 1000,
};
let d = st.make();
b.iter(|| trie_root::<KeccakHasher, _, _, _>(d.clone()));
});
}

#[bench]
fn triehash_insertions_32_ran_1k(b: &mut Bencher) {
let st = StandardMap {
alphabet: Alphabet::All,
min_key: 32,
journal_key: 0,
value_mode: ValueMode::Random,
count: 1000,
};
let d = st.make();
b.iter(&mut ||{
let _ = trie_root::<KeccakHasher, _, _, _>(d.clone()).clone();
c.bench_function("32_ran_1k", |b| {
let st = StandardMap {
alphabet: Alphabet::All,
min_key: 32,
journal_key: 0,
value_mode: ValueMode::Random,
count: 1000,
};
let d = st.make();
b.iter(|| trie_root::<KeccakHasher, _, _, _>(d.clone()));
});
}

#[bench]
fn triehash_insertions_six_high(b: &mut Bencher) {
let mut d: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
let mut seed = H256::new();
for _ in 0..1000 {
let k = random_bytes(6, 0, &mut seed);
let v = random_value(&mut seed);
d.push((k, v))
}

b.iter(&||{
let _ = trie_root::<KeccakHasher, _, _, _>(d.clone());
})
}
c.bench_function("six_high", |b| {
let mut d: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
let mut seed = H256::default();
for _ in 0..1000 {
let k = random_bytes(6, 0, &mut seed);
let v = random_value(&mut seed);
d.push((k, v))
}
b.iter(|| trie_root::<KeccakHasher, _, _, _>(d.clone()));
});

#[bench]
fn triehash_insertions_six_mid(b: &mut Bencher) {
let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_";
let mut d: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
let mut seed = H256::new();
for _ in 0..1000 {
let k = random_word(alphabet, 6, 0, &mut seed);
let v = random_value(&mut seed);
d.push((k, v))
}
b.iter(||{
let _ = trie_root::<KeccakHasher, _, _, _>(d.clone());
})
}
c.bench_function("six_mid", |b| {
let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_";
let mut d: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
let mut seed = H256::default();
for _ in 0..1000 {
let k = random_word(alphabet, 6, 0, &mut seed);
let v = random_value(&mut seed);
d.push((k, v))
}
b.iter(|| trie_root::<KeccakHasher, _, _, _>(d.clone()));
});

#[bench]
fn triehash_insertions_random_mid(b: &mut Bencher) {
let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_";
let mut d: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
let mut seed = H256::new();
for _ in 0..1000 {
let k = random_word(alphabet, 1, 5, &mut seed);
let v = random_value(&mut seed);
d.push((k, v))
}
c.bench_function("random_mid", |b| {
let alphabet = b"@QWERTYUIOPASDFGHJKLZXCVBNM[/]^_";
let mut d: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
let mut seed = H256::default();
for _ in 0..1000 {
let k = random_word(alphabet, 1, 5, &mut seed);
let v = random_value(&mut seed);
d.push((k, v))
}
b.iter(|| trie_root::<KeccakHasher, _, _, _>(d.clone()));
});

b.iter(||{
let _ = trie_root::<KeccakHasher, _, _, _>(d.clone());
})
c.bench_function("six_low", |b| {
let alphabet = b"abcdef";
let mut d: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
let mut seed = H256::default();
for _ in 0..1000 {
let k = random_word(alphabet, 6, 0, &mut seed);
let v = random_value(&mut seed);
d.push((k, v))
}
b.iter(|| trie_root::<KeccakHasher, _, _, _>(d.clone()));
});
}

#[bench]
fn triehash_insertions_six_low(b: &mut Bencher) {
let alphabet = b"abcdef";
let mut d: Vec<(Vec<u8>, Vec<u8>)> = Vec::new();
let mut seed = H256::new();
for _ in 0..1000 {
let k = random_word(alphabet, 6, 0, &mut seed);
let v = random_value(&mut seed);
d.push((k, v))
}

b.iter(||{
let _ = trie_root::<KeccakHasher, _, _, _>(d.clone());
})
}
criterion_group!(benches, bench_insertions);
criterion_main!(benches);
72 changes: 33 additions & 39 deletions triehash/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,17 +18,10 @@
//!
//! This module should be used to generate trie root hash.

extern crate hash_db;
extern crate rlp;
#[cfg(test)]
extern crate keccak_hasher;
#[cfg(test)]
#[macro_use]
extern crate hex_literal;

use std::collections::BTreeMap;
use std::cmp;
use std::collections::BTreeMap;
use std::iter::once;

use hash_db::Hasher;
use rlp::RlpStream;

Expand Down Expand Up @@ -96,7 +89,6 @@ where
H: Hasher,
<H as hash_db::Hasher>::Out: cmp::Ord,
{

// first put elements into btree to sort them and to remove duplicates
let input = input
.into_iter()
Expand Down Expand Up @@ -240,20 +232,16 @@ where
stream.begin_list(17);

// if first key len is equal to prefix_len, move to next element
let mut begin = match pre_len == key.len() {
true => 1,
false => 0
};
let mut begin = if pre_len == key.len() { 1 } else { 0 };

// iterate over all possible nibbles
for i in 0..16 {
// count how many successive elements have same next nibble
let len = match begin < input.len() {
true => input[begin..].iter()
.take_while(| pair | pair.0.as_ref()[pre_len] == i )
.count(),
false => 0
};
let len = input
.iter()
.skip(begin)
.take_while(|pair| pair.0.as_ref()[pre_len] == i)
.count();

// if at least 1 successive element has the same nibble
// append their suffixes
Expand All @@ -265,10 +253,11 @@ where
}

// if fist key len is equal prefix, append its value
match pre_len == key.len() {
true => { stream.append(&value); },
false => { stream.append_empty_data(); }
};
if pre_len == key.len() {
stream.append(&value);
} else {
stream.append_empty_data();
}
}

fn hash256aux<H, A, B>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream)
Expand All @@ -288,10 +277,10 @@ where

#[cfg(test)]
mod tests {
extern crate ethereum_types;
use super::{trie_root, shared_prefix_len, hex_prefix_encode};
use keccak_hasher::KeccakHasher;
use self::ethereum_types::H256;
use ethereum_types::H256;
use hex_literal::hex;

#[test]
fn test_hex_prefix_encode() {
Expand Down Expand Up @@ -328,23 +317,28 @@ mod tests {

#[test]
fn simple_test() {
assert_eq!(trie_root::<KeccakHasher, _, _, _>(vec![
(b"A", b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" as &[u8])
]), H256::from(hex!("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")).as_ref());
assert_eq!(
trie_root::<KeccakHasher, _, _, _>(vec![
(b"A", b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" as &[u8])
]),
H256::from(hex!("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")).as_ref(),
);
}

#[test]
fn test_triehash_out_of_order() {
assert!(trie_root::<KeccakHasher, _, _, _>(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
(vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]),
]) ==
trie_root::<KeccakHasher, _, _, _>(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), // last two tuples are swapped
(vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
]));
assert_eq!(
trie_root::<KeccakHasher, _, _, _>(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
(vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]),
]),
trie_root::<KeccakHasher, _, _, _>(vec![
(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
(vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), // last two tuples are swapped
(vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
]),
);
}

#[test]
Expand Down