forked from openethereum/parity-ethereum
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Benchmarks for block verification (openethereum#11035)
* WIP * wip * Benchmarks for block verification Uses real blocks from mainnet to benchmark the `verify_*` family of methods in the `verification` module. Also exposes the `TestBlockChain` in a test helper. * Cleanup, fix CI * Bash syntax error * One more try * Fix review grumbles Revert unwanted changes Tweak CI benchmark checks
- Loading branch information
Showing
12 changed files
with
312 additions
and
109 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,6 +6,10 @@ authors = ["Parity Technologies <[email protected]>"] | |
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" } | ||
|
@@ -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 not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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::{ | ||
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(); | ||
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, | ||
ðash, | ||
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(), | ||
ðash, | ||
true | ||
).is_ok()); | ||
}) | ||
}); | ||
|
||
// Phase 3 verification | ||
let block = Unverified::from_rlp(rlp_8481476.clone()).expect(PROOF); | ||
let preverified = verification::verify_block_unordered(block, ðash, 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, | ||
ðash, | ||
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, | ||
ðash, | ||
Some(full), | ||
) { | ||
panic!("verify_block_family (full) ERROR: {:?}", e) | ||
} | ||
}); | ||
}); | ||
} | ||
|
||
criterion_group!(benches, block_verification); | ||
criterion_main!(benches); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 { | ||
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!() | ||
} | ||
} |
Oops, something went wrong.