Skip to content

Commit

Permalink
Merge pull request #127 from darwinia-network/denny_fixing_ethereum_b…
Browse files Browse the repository at this point in the history
…ridge

Relay header and check proof logic
  • Loading branch information
hackfisher authored Dec 3, 2019
2 parents 4f3b6f3 + e3892d8 commit 39b5af8
Show file tree
Hide file tree
Showing 23 changed files with 3,179 additions and 348 deletions.
516 changes: 384 additions & 132 deletions Cargo.lock

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ members = [
"core/merkle-mountain-range",
"core/fly-client",
"core/sr-eth-primitives",
"core/merkle-patricia-trie",

"node/cli",
"node/executor",
Expand All @@ -16,7 +17,7 @@ members = [
"node/runtime",

"srml/balances",
"srml/ethereum-bridge",
"srml/eth-relay",
"srml/kton",
"srml/staking",
"srml/support"
Expand Down
30 changes: 30 additions & 0 deletions core/merkle-patricia-trie/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
[package]
name = "merkle-patricia-trie"
version = "0.1.0"
authors = ["Darwinia Network <[email protected]>"]
edition = "2018"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
rlp = { git = "https://github.com/darwinia-network/parity-common.git", default-features = false }
hash = { package = "keccak-hash", git = "https://github.com/darwinia-network/parity-common.git", default-features = false }
hashbrown = { version = "0.6.0" }

[dev-dependencies]
rand = "0.6.3"
hex = "0.3.2"
criterion = "0.2.10"
ethereum-types = "0.5.2"
uuid = { version = "0.7", features = ["serde", "v4"] }

[features]
default = ["std"]
std = [
"rlp/std",
"hash/std"
]

[[bench]]
name = "trie"
harness = false
99 changes: 99 additions & 0 deletions core/merkle-patricia-trie/benches/trie.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
use std::rc::Rc;

use criterion::{criterion_group, criterion_main, Criterion};
use merkle_patricia_trie::{MemoryDB, MerklePatriciaTrie, Trie};
use uuid::Uuid;

fn insert_worse_case_benchmark(c: &mut Criterion) {
c.bench_function("insert one", |b| {
let mut trie = MerklePatriciaTrie::new(Rc::new(MemoryDB::new()));

b.iter(|| {
let key = Uuid::new_v4().as_bytes().to_vec();
let value = Uuid::new_v4().as_bytes().to_vec();
trie.insert(key, value).unwrap()
})
});

c.bench_function("insert 1k", |b| {
let mut trie = MerklePatriciaTrie::new(Rc::new(MemoryDB::new()));

let (keys, values) = random_data(1000);
b.iter(|| {
for i in 0..keys.len() {
trie.insert(keys[i].clone(), values[i].clone()).unwrap()
}
});
});

c.bench_function("insert 10k", |b| {
let mut trie = MerklePatriciaTrie::new(Rc::new(MemoryDB::new()));

let (keys, values) = random_data(10000);
b.iter(|| {
for i in 0..keys.len() {
trie.insert(keys[i].clone(), values[i].clone()).unwrap()
}
});
});

c.bench_function("get based 10k", |b| {
let mut trie = MerklePatriciaTrie::new(Rc::new(MemoryDB::new()));

let (keys, values) = random_data(10000);
for i in 0..keys.len() {
trie.insert(keys[i].clone(), values[i].clone()).unwrap()
}

b.iter(|| {
let key = trie.get(&keys[7777]).unwrap();
assert_ne!(key, None);
});
});

c.bench_function("remove 1k", |b| {
let mut trie = MerklePatriciaTrie::new(Rc::new(MemoryDB::new()));

let (keys, values) = random_data(1000);
for i in 0..keys.len() {
trie.insert(keys[i].clone(), values[i].clone()).unwrap()
}

b.iter(|| {
for key in keys.iter() {
trie.remove(key).unwrap();
}
});
});

c.bench_function("remove 10k", |b| {
let mut trie = MerklePatriciaTrie::new(Rc::new(MemoryDB::new()));

let (keys, values) = random_data(10000);
for i in 0..keys.len() {
trie.insert(keys[i].clone(), values[i].clone()).unwrap()
}

b.iter(|| {
for key in keys.iter() {
trie.remove(key).unwrap();
}
});
});
}

fn random_data(n: usize) -> (Vec<Vec<u8>>, Vec<Vec<u8>>) {
let mut keys = Vec::with_capacity(n);
let mut values = Vec::with_capacity(n);
for _ in 0..n {
let key = Uuid::new_v4().as_bytes().to_vec();
let value = Uuid::new_v4().as_bytes().to_vec();
keys.push(key);
values.push(value);
}

(keys, values)
}

criterion_group!(benches, insert_worse_case_benchmark);
criterion_main!(benches);
52 changes: 52 additions & 0 deletions core/merkle-patricia-trie/src/db.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
use crate::std::*;
use hashbrown::HashMap;

#[derive(Debug)]
pub struct MemoryDB {
data: RefCell<HashMap<Vec<u8>, Vec<u8>>>,
}

impl MemoryDB {
pub fn new() -> Self {
MemoryDB {
data: RefCell::new(HashMap::new()),
}
}

pub fn get(&self, key: &[u8]) -> Option<Vec<u8>> {
let data = self.data.borrow();
if let Some(d) = data.get(key) {
Some(d.clone())
} else {
None
}
}

pub fn insert(&self, key: Vec<u8>, value: Vec<u8>) -> Option<Vec<u8>> {
self.data.borrow_mut().insert(key, value)
}

pub fn contains(&self, key: &[u8]) -> bool {
self.data.borrow().contains_key(key)
}

pub fn remove(&self, key: &[u8]) -> Option<Vec<u8>> {
self.data.borrow_mut().remove(key)
}

/// Insert a batch of data into the cache.
pub fn insert_batch(&self, keys: Vec<Vec<u8>>, values: Vec<Vec<u8>>) {
for i in 0..keys.len() {
let key = keys[i].clone();
let value = values[i].clone();
self.insert(key, value);
}
}

/// Remove a batch of data into the cache.
pub fn remove_batch(&self, keys: &[Vec<u8>]) {
for key in keys {
self.remove(key);
}
}
}
30 changes: 30 additions & 0 deletions core/merkle-patricia-trie/src/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
use crate::std::*;
use rlp::DecoderError;

#[derive(Debug)]
pub enum TrieError {
DB(String),
Decoder(DecoderError),
InvalidData,
InvalidStateRoot,
InvalidProof,
}

impl fmt::Display for TrieError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let printable = match *self {
TrieError::DB(ref err) => format!("trie error: {:?}", err),
TrieError::Decoder(ref err) => format!("trie error: {:?}", err),
TrieError::InvalidData => "trie error: invalid data".to_owned(),
TrieError::InvalidStateRoot => "trie error: invalid state root".to_owned(),
TrieError::InvalidProof => "trie error: invalid proof".to_owned(),
};
write!(f, "{}", printable)
}
}

impl From<DecoderError> for TrieError {
fn from(error: DecoderError) -> Self {
TrieError::Decoder(error)
}
}
99 changes: 99 additions & 0 deletions core/merkle-patricia-trie/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
// Ensure we're `no_std` when compiling for Wasm.
#![cfg_attr(not(feature = "std"), no_std)]

#[cfg(not(feature = "std"))]
extern crate alloc;
#[cfg(not(feature = "std"))]
extern crate core;

#[cfg(not(feature = "std"))]
mod std {
pub use alloc::borrow::ToOwned;
pub use alloc::format;
pub use alloc::rc::Rc;
pub use alloc::string::String;
pub use alloc::vec;
pub use alloc::vec::Vec;

pub use core::cell::RefCell;
pub use core::fmt;
}

#[cfg(feature = "std")]
mod std {
pub use std::cell::RefCell;
pub use std::fmt;
pub use std::rc::Rc;
}

mod db;
mod error;
mod nibbles;
mod node;
mod proof;
mod tests;
pub mod trie;

pub use db::MemoryDB;
pub use error::TrieError;
pub use proof::Proof;
pub use trie::{MerklePatriciaTrie, Trie, TrieResult};

/// Generates a trie for a vector of key-value tuples
///
/// ```rust
/// extern crate merkle_patricia_trie as trie;
/// extern crate hex;
///
/// use trie::{Trie, build_trie};
/// use hex::FromHex;
///
/// fn main() {
/// let v = vec![
/// ("doe", "reindeer"),
/// ("dog", "puppy"),
/// ("dogglesworth", "cat"),
/// ];
///
/// let root:Vec<u8> = Vec::from_hex("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3").unwrap();
/// assert_eq!(build_trie(v).unwrap().root().unwrap(), root);
/// }
/// ```
pub fn build_trie<I, A, B>(data: I) -> TrieResult<MerklePatriciaTrie>
where
I: IntoIterator<Item = (A, B)>,
A: AsRef<[u8]> + Ord,
B: AsRef<[u8]>,
{
let memdb = std::Rc::new(MemoryDB::new());
let mut trie = MerklePatriciaTrie::new(memdb.clone());
data.into_iter().for_each(|(key, value)| {
// TODO the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `core::ops::Try`)
trie.insert(key.as_ref().to_vec(), value.as_ref().to_vec());
});
trie.root()?;
Ok(trie)
}

/// Generates a trie for a vector of values
///
/// ```rust
/// extern crate merkle_patricia_trie as trie;
/// extern crate hex;
///
/// use trie::{Trie, build_order_trie};
/// use hex::FromHex;
///
/// fn main() {
/// let v = &["doe", "reindeer"];
/// let root:Vec<u8> = Vec::from_hex("e766d5d51b89dc39d981b41bda63248d7abce4f0225eefd023792a540bcffee3").unwrap();
/// assert_eq!(build_order_trie(v).unwrap().root().unwrap(), root);
/// }
/// ```
pub fn build_order_trie<I>(data: I) -> TrieResult<MerklePatriciaTrie>
where
I: IntoIterator,
I::Item: AsRef<[u8]>,
{
build_trie(data.into_iter().enumerate().map(|(i, v)| (rlp::encode(&i), v)))
}
Loading

0 comments on commit 39b5af8

Please sign in to comment.