Skip to content
This repository was archived by the owner on Nov 6, 2020. It is now read-only.
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
7 changes: 3 additions & 4 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,10 +100,9 @@ cargo-check-benches:
stage: test
<<: *docker-cache-status
script:
- time (
cargo check --all --benches --exclude ethash --target $CARGO_TARGET --locked --verbose --color=always;
(cd ethash; time cargo check --benches --features bench --target $CARGO_TARGET --locked --verbose --color=always)
)
- time (cargo check --all --benches --exclude ethash --exclude verification --target $CARGO_TARGET --locked --verbose --color=always)
- time (cd ethash; cargo check --benches --features bench --target $CARGO_TARGET --locked --verbose --color=always)
- time (cd ethcore/verification; cargo check --benches --features bench --target $CARGO_TARGET --locked --verbose --color=always)
- sccache -s

cargo-audit:
Expand Down
9 changes: 6 additions & 3 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion ethcore/types/src/verification.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ impl VerificationQueueInfo {
}

/// An unverified block.
#[derive(PartialEq, Debug, MallocSizeOf)]
#[derive(Clone, PartialEq, Debug, MallocSizeOf)]
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clone is used for benchmarks/tests?

Why not #[cfg_attr(any(foo, bar), derive(Clone)]?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that is the reason. It's more convenience than necessity though. In general though, why is it bad to derive Clone? Reading https://rust-lang-nursery.github.io/api-guidelines/interoperability.html#c-common-traits it seems idiomatic to do so whenever it's convenient?

Copy link
Copy Markdown
Collaborator

@niklasad1 niklasad1 Sep 11, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nothing bad I guess but it might have the reasoning that such big structures should not be cloned which are enforced by rustc when no Clone impl exists but I don't know really just guessing!

EDIT: It would produce a slightly bigger binary I guess but so small that it is probably negligible

pub struct Unverified {
/// Unverified block header.
pub header: Header,
Expand Down
13 changes: 13 additions & 0 deletions ethcore/verification/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ authors = ["Parity Technologies <admin@parity.io>"]
edition = "2018"
license = "GPL-3.0"

[[bench]]
name = "verification"
harness = false

[dependencies]
blockchain = { package = "ethcore-blockchain", path = "../blockchain" }
call-contract = { package = "ethcore-call-contract", path = "../call-contract" }
Expand All @@ -27,8 +31,17 @@ triehash = { package = "triehash-ethereum", version = "0.2", path = "../../util
unexpected = { path = "../../util/unexpected" }

[dev-dependencies]
criterion = "0.3"
ethcore = { path = "../", features = ["test-helpers"] }
ethkey = { path = "../../accounts/ethkey" }
machine = { path = "../machine" }
null-engine = { path = "../engines/null-engine" }
spec = { path = "../spec" }

# Benches
ethash = { package = "ethash-engine", path = "../engines/ethash" }
tempdir = "0.3.7"

[features]
# Used to selectively expose code for benchmarks.
bench = []
Binary file added ethcore/verification/benches/8447675.rlp
Binary file not shown.
Binary file not shown.
Binary file added ethcore/verification/benches/8481475.rlp
Binary file not shown.
Binary file not shown.
161 changes: 161 additions & 0 deletions ethcore/verification/benches/verification.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
// 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 <http://www.gnu.org/licenses/>.

//! benchmarking for verification

use std::collections::BTreeMap;

use common_types::verification::Unverified;
use criterion::{Criterion, criterion_group, criterion_main};
use ethash::{EthashParams, Ethash};
use ethereum_types::U256;
use ethcore::client::TestBlockChainClient;
use spec::new_constantinople_test_machine;
use tempdir::TempDir;

use ::verification::{
Comment thread
niklasad1 marked this conversation as resolved.
FullFamilyParams,
verification,
test_helpers::TestBlockChain,
};

// These are current production values. Needed when using real blocks.
fn ethash_params() -> EthashParams {
EthashParams {
minimum_difficulty: U256::from(131072),
difficulty_bound_divisor: U256::from(2048),
difficulty_increment_divisor: 10,
metropolis_difficulty_increment_divisor: 9,
duration_limit: 13,
homestead_transition: 1150000,
difficulty_hardfork_transition: u64::max_value(),
difficulty_hardfork_bound_divisor: U256::from(2048),
bomb_defuse_transition: u64::max_value(),
eip100b_transition: 4370000,
ecip1010_pause_transition: u64::max_value(),
ecip1010_continue_transition: u64::max_value(),
ecip1017_era_rounds: u64::max_value(),
block_reward: {
let mut m = BTreeMap::<u64, U256>::new();
m.insert(0, 5000000000000000000u64.into());
m.insert(4370000, 3000000000000000000u64.into());
m.insert(7280000, 2000000000000000000u64.into());
m
},
expip2_transition: u64::max_value(),
expip2_duration_limit: 30,
block_reward_contract_transition: 0,
block_reward_contract: None,
difficulty_bomb_delays: {
let mut m = BTreeMap::new();
Comment thread
niklasad1 marked this conversation as resolved.
m.insert(4370000, 3000000);
m.insert(7280000, 2000000);
m
},
progpow_transition: u64::max_value()
}
}

fn build_ethash() -> Ethash {
let machine = new_constantinople_test_machine();
let ethash_params = ethash_params();
let cache_dir = TempDir::new("").unwrap();
Ethash::new(
cache_dir.path(),
ethash_params,
machine,
None
)
}

fn block_verification(c: &mut Criterion) {
const PROOF: &str = "bytes from disk are ok";

let ethash = build_ethash();

// A fairly large block (32kb) with one uncle
let rlp_8481476 = include_bytes!("./8481476-one-uncle.rlp").to_vec();
// Parent of #8481476
let rlp_8481475 = include_bytes!("./8481475.rlp").to_vec();
// Parent of the uncle in #8481476
let rlp_8481474 = include_bytes!("./8481474-parent-to-uncle.rlp").to_vec();

// Phase 1 verification
c.bench_function("verify_block_basic", |b| {
let block = Unverified::from_rlp(rlp_8481476.clone()).expect(PROOF);
b.iter(|| {
assert!(verification::verify_block_basic(
&block,
&ethash,
true
).is_ok());
})
});

// Phase 2 verification
c.bench_function("verify_block_unordered", |b| {
let block = Unverified::from_rlp(rlp_8481476.clone()).expect(PROOF);
b.iter( || {
assert!(verification::verify_block_unordered(
block.clone(),
&ethash,
true
).is_ok());
})
});

// Phase 3 verification
let block = Unverified::from_rlp(rlp_8481476.clone()).expect(PROOF);
let preverified = verification::verify_block_unordered(block, &ethash, true).expect(PROOF);
let parent = Unverified::from_rlp(rlp_8481475.clone()).expect(PROOF);

// "partial" means we skip uncle and tx verification
c.bench_function("verify_block_family (partial)", |b| {
b.iter(|| {
if let Err(e) = verification::verify_block_family::<TestBlockChainClient>(
&preverified.header,
&parent.header,
&ethash,
None
) {
panic!("verify_block_family (partial) ERROR: {:?}", e);
}
});
});

let mut block_provider = TestBlockChain::new();
block_provider.insert(rlp_8481476.clone()); // block to verify
block_provider.insert(rlp_8481475.clone()); // parent
block_provider.insert(rlp_8481474.clone()); // uncle's parent

let client = TestBlockChainClient::default();
c.bench_function("verify_block_family (full)", |b| {
b.iter(|| {
let full = FullFamilyParams { block: &preverified, block_provider: &block_provider, client: &client };
if let Err(e) = verification::verify_block_family::<TestBlockChainClient>(
&preverified.header,
&parent.header,
&ethash,
Some(full),
) {
panic!("verify_block_family (full) ERROR: {:?}", e)
}
});
});
}

criterion_group!(benches, block_verification);
criterion_main!(benches);
5 changes: 5 additions & 0 deletions ethcore/verification/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@ use client_traits::BlockInfo;
// The MallocSizeOf derive looks for this in the root
use parity_util_mem as malloc_size_of;

#[cfg(feature = "bench" )]
pub mod verification;
#[cfg(not(feature = "bench" ))]
mod verification;
mod verifier;
pub mod queue;
mod canon_verifier;
mod noop_verifier;
#[cfg(any(test, feature = "bench" ))]
pub mod test_helpers;

pub use self::verification::FullFamilyParams;
pub use self::verifier::Verifier;
Expand Down
114 changes: 114 additions & 0 deletions ethcore/verification/src/test_helpers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
// 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 <http://www.gnu.org/licenses/>.

//! Verification test helpers.

use std::collections::HashMap;

use blockchain::{BlockProvider, BlockChain, BlockDetails, TransactionAddress, BlockReceipts};
use common_types::{
BlockNumber,
encoded,
verification::Unverified,
log_entry::{LogEntry, LocalizedLogEntry},
};
use ethereum_types::{BloomRef, H256};
use parity_bytes::Bytes;

#[derive(Default)]
pub struct TestBlockChain {
Comment thread
niklasad1 marked this conversation as resolved.
blocks: HashMap<H256, Bytes>,
numbers: HashMap<BlockNumber, H256>,
}

impl TestBlockChain {
pub fn new() -> Self { TestBlockChain::default() }

pub fn insert(&mut self, bytes: Bytes) {
let header = Unverified::from_rlp(bytes.clone()).unwrap().header;
let hash = header.hash();
self.blocks.insert(hash, bytes);
self.numbers.insert(header.number(), hash);
}
}

impl BlockProvider for TestBlockChain {
fn is_known(&self, hash: &H256) -> bool {
self.blocks.contains_key(hash)
}

fn first_block(&self) -> Option<H256> {
unimplemented!()
}

fn best_ancient_block(&self) -> Option<H256> {
None
}

/// Get raw block data
fn block(&self, hash: &H256) -> Option<encoded::Block> {
self.blocks.get(hash).cloned().map(encoded::Block::new)
}

/// Get the familial details concerning a block.
fn block_details(&self, hash: &H256) -> Option<BlockDetails> {
self.blocks.get(hash).map(|bytes| {
let header = Unverified::from_rlp(bytes.to_vec()).unwrap().header;
BlockDetails {
number: header.number(),
total_difficulty: *header.difficulty(),
parent: *header.parent_hash(),
children: Vec::new(),
is_finalized: false,
}
})
}

/// Get the hash of given block's number.
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
self.numbers.get(&index).cloned()
}

fn transaction_address(&self, _hash: &H256) -> Option<TransactionAddress> {
unimplemented!()
}

fn block_receipts(&self, _hash: &H256) -> Option<BlockReceipts> {
unimplemented!()
}

fn block_header_data(&self, hash: &H256) -> Option<encoded::Header> {
self.block(hash)
.map(|b| b.header_view().rlp().as_raw().to_vec())
.map(encoded::Header::new)
}

fn block_body(&self, hash: &H256) -> Option<encoded::Body> {
self.block(hash)
.map(|b| BlockChain::block_to_body(&b.into_inner()))
.map(encoded::Body::new)
}

fn blocks_with_bloom<'a, B, I, II>(&self, _blooms: II, _from_block: BlockNumber, _to_block: BlockNumber) -> Vec<BlockNumber>
where BloomRef<'a>: From<B>, II: IntoIterator<Item = B, IntoIter = I> + Copy, I: Iterator<Item = B>, Self: Sized {
unimplemented!()
}

fn logs<F>(&self, _blocks: Vec<H256>, _matches: F, _limit: Option<usize>) -> Vec<LocalizedLogEntry>
where F: Fn(&LogEntry) -> bool, Self: Sized {
unimplemented!()
}
}
Loading