Benchmarks for block verification (#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
This commit is contained in:
parent
48629c2bd4
commit
f4d14e271f
@ -100,10 +100,9 @@ cargo-check-benches:
|
|||||||
stage: test
|
stage: test
|
||||||
<<: *docker-cache-status
|
<<: *docker-cache-status
|
||||||
script:
|
script:
|
||||||
- time (
|
- time (cargo check --all --benches --exclude ethash --exclude verification --target $CARGO_TARGET --locked --verbose --color=always)
|
||||||
cargo check --all --benches --exclude ethash --target $CARGO_TARGET --locked --verbose --color=always;
|
- time (cd ethash; cargo check --benches --features bench --target $CARGO_TARGET --locked --verbose --color=always)
|
||||||
(cd ethash; time 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
|
- sccache -s
|
||||||
|
|
||||||
cargo-audit:
|
cargo-audit:
|
||||||
|
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -4996,7 +4996,9 @@ version = "0.1.0"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"client-traits 0.1.0",
|
"client-traits 0.1.0",
|
||||||
"common-types 0.1.0",
|
"common-types 0.1.0",
|
||||||
|
"criterion 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"engine 0.1.0",
|
"engine 0.1.0",
|
||||||
|
"ethash-engine 0.1.0",
|
||||||
"ethcore 1.12.0",
|
"ethcore 1.12.0",
|
||||||
"ethcore-blockchain 0.1.0",
|
"ethcore-blockchain 0.1.0",
|
||||||
"ethcore-call-contract 0.1.0",
|
"ethcore-call-contract 0.1.0",
|
||||||
@ -5014,6 +5016,7 @@ dependencies = [
|
|||||||
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
"parking_lot 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"rlp 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"spec 0.1.0",
|
"spec 0.1.0",
|
||||||
|
"tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"time-utils 0.1.0",
|
"time-utils 0.1.0",
|
||||||
"triehash-ethereum 0.2.0",
|
"triehash-ethereum 0.2.0",
|
||||||
"unexpected 0.1.0",
|
"unexpected 0.1.0",
|
||||||
|
@ -57,7 +57,7 @@ impl VerificationQueueInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// An unverified block.
|
/// An unverified block.
|
||||||
#[derive(PartialEq, Debug, MallocSizeOf)]
|
#[derive(Clone, PartialEq, Debug, MallocSizeOf)]
|
||||||
pub struct Unverified {
|
pub struct Unverified {
|
||||||
/// Unverified block header.
|
/// Unverified block header.
|
||||||
pub header: Header,
|
pub header: Header,
|
||||||
|
@ -6,6 +6,10 @@ authors = ["Parity Technologies <admin@parity.io>"]
|
|||||||
edition = "2018"
|
edition = "2018"
|
||||||
license = "GPL-3.0"
|
license = "GPL-3.0"
|
||||||
|
|
||||||
|
[[bench]]
|
||||||
|
name = "verification"
|
||||||
|
harness = false
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
blockchain = { package = "ethcore-blockchain", path = "../blockchain" }
|
blockchain = { package = "ethcore-blockchain", path = "../blockchain" }
|
||||||
call-contract = { package = "ethcore-call-contract", path = "../call-contract" }
|
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" }
|
unexpected = { path = "../../util/unexpected" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
|
criterion = "0.3"
|
||||||
ethcore = { path = "../", features = ["test-helpers"] }
|
ethcore = { path = "../", features = ["test-helpers"] }
|
||||||
ethkey = { path = "../../accounts/ethkey" }
|
ethkey = { path = "../../accounts/ethkey" }
|
||||||
machine = { path = "../machine" }
|
machine = { path = "../machine" }
|
||||||
null-engine = { path = "../engines/null-engine" }
|
null-engine = { path = "../engines/null-engine" }
|
||||||
spec = { path = "../spec" }
|
spec = { path = "../spec" }
|
||||||
|
|
||||||
|
# Benches
|
||||||
|
ethash = { package = "ethash-engine", path = "../engines/ethash" }
|
||||||
|
tempdir = "0.3.7"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
# Used to selectively expose code for benchmarks.
|
||||||
|
bench = []
|
||||||
|
BIN
ethcore/verification/benches/8447675.rlp
Normal file
BIN
ethcore/verification/benches/8447675.rlp
Normal file
Binary file not shown.
BIN
ethcore/verification/benches/8481474-parent-to-uncle.rlp
Normal file
BIN
ethcore/verification/benches/8481474-parent-to-uncle.rlp
Normal file
Binary file not shown.
BIN
ethcore/verification/benches/8481475.rlp
Normal file
BIN
ethcore/verification/benches/8481475.rlp
Normal file
Binary file not shown.
BIN
ethcore/verification/benches/8481476-one-uncle.rlp
Normal file
BIN
ethcore/verification/benches/8481476-one-uncle.rlp
Normal file
Binary file not shown.
161
ethcore/verification/benches/verification.rs
Normal file
161
ethcore/verification/benches/verification.rs
Normal file
@ -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);
|
@ -21,11 +21,16 @@ use client_traits::BlockInfo;
|
|||||||
// The MallocSizeOf derive looks for this in the root
|
// The MallocSizeOf derive looks for this in the root
|
||||||
use parity_util_mem as malloc_size_of;
|
use parity_util_mem as malloc_size_of;
|
||||||
|
|
||||||
|
#[cfg(feature = "bench" )]
|
||||||
|
pub mod verification;
|
||||||
|
#[cfg(not(feature = "bench" ))]
|
||||||
mod verification;
|
mod verification;
|
||||||
mod verifier;
|
mod verifier;
|
||||||
pub mod queue;
|
pub mod queue;
|
||||||
mod canon_verifier;
|
mod canon_verifier;
|
||||||
mod noop_verifier;
|
mod noop_verifier;
|
||||||
|
#[cfg(any(test, feature = "bench" ))]
|
||||||
|
pub mod test_helpers;
|
||||||
|
|
||||||
pub use self::verification::FullFamilyParams;
|
pub use self::verification::FullFamilyParams;
|
||||||
pub use self::verifier::Verifier;
|
pub use self::verifier::Verifier;
|
||||||
|
114
ethcore/verification/src/test_helpers.rs
Normal file
114
ethcore/verification/src/test_helpers.rs
Normal file
@ -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!()
|
||||||
|
}
|
||||||
|
}
|
@ -119,7 +119,12 @@ pub struct FullFamilyParams<'a, C: BlockInfo + CallContract + 'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Phase 3 verification. Check block information against parent and uncles.
|
/// Phase 3 verification. Check block information against parent and uncles.
|
||||||
pub fn verify_block_family<C: BlockInfo + CallContract>(header: &Header, parent: &Header, engine: &dyn Engine, do_full: Option<FullFamilyParams<C>>) -> Result<(), Error> {
|
pub fn verify_block_family<C: BlockInfo + CallContract>(
|
||||||
|
header: &Header,
|
||||||
|
parent: &Header,
|
||||||
|
engine: &dyn Engine,
|
||||||
|
do_full: Option<FullFamilyParams<C>>
|
||||||
|
) -> Result<(), Error> {
|
||||||
// TODO: verify timestamp
|
// TODO: verify timestamp
|
||||||
verify_parent(&header, &parent, engine)?;
|
verify_parent(&header, &parent, engine)?;
|
||||||
engine.verify_block_family(&header, &parent)?;
|
engine.verify_block_family(&header, &parent)?;
|
||||||
@ -128,7 +133,6 @@ pub fn verify_block_family<C: BlockInfo + CallContract>(header: &Header, parent:
|
|||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
verify_uncles(params.block, params.block_provider, engine)?;
|
verify_uncles(params.block, params.block_provider, engine)?;
|
||||||
|
|
||||||
for tx in ¶ms.block.transactions {
|
for tx in ¶ms.block.transactions {
|
||||||
@ -248,7 +252,7 @@ pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error>
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Check basic header parameters.
|
/// Check basic header parameters.
|
||||||
pub fn verify_header_params(header: &Header, engine: &dyn Engine, is_full: bool, check_seal: bool) -> Result<(), Error> {
|
pub(crate) fn verify_header_params(header: &Header, engine: &dyn Engine, is_full: bool, check_seal: bool) -> Result<(), Error> {
|
||||||
if check_seal {
|
if check_seal {
|
||||||
let expected_seal_fields = engine.seal_fields(header);
|
let expected_seal_fields = engine.seal_fields(header);
|
||||||
if header.seal().len() != expected_seal_fields {
|
if header.seal().len() != expected_seal_fields {
|
||||||
@ -306,7 +310,7 @@ pub fn verify_header_params(header: &Header, engine: &dyn Engine, is_full: bool,
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Check header parameters agains parent header.
|
/// Check header parameters against parent header.
|
||||||
fn verify_parent(header: &Header, parent: &Header, engine: &dyn Engine) -> Result<(), Error> {
|
fn verify_parent(header: &Header, parent: &Header, engine: &dyn Engine) -> Result<(), Error> {
|
||||||
assert!(header.parent_hash().is_zero() || &parent.hash() == header.parent_hash(),
|
assert!(header.parent_hash().is_zero() || &parent.hash() == header.parent_hash(),
|
||||||
"Parent hash should already have been verified; qed");
|
"Parent hash should already have been verified; qed");
|
||||||
@ -364,11 +368,10 @@ fn verify_block_integrity(block: &Unverified) -> Result<(), Error> {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::BTreeMap;
|
||||||
use std::time::{SystemTime, UNIX_EPOCH};
|
use std::time::{SystemTime, UNIX_EPOCH};
|
||||||
|
|
||||||
use ethereum_types::{H256, BloomRef, U256, Address};
|
use ethereum_types::{H256, U256, Address};
|
||||||
use blockchain::{BlockDetails, TransactionAddress, BlockReceipts};
|
|
||||||
use parity_bytes::Bytes;
|
use parity_bytes::Bytes;
|
||||||
use keccak_hash::keccak;
|
use keccak_hash::keccak;
|
||||||
use engine::Engine;
|
use engine::Engine;
|
||||||
@ -379,17 +382,17 @@ mod tests {
|
|||||||
test_helpers::{create_test_block_with_data, create_test_block}
|
test_helpers::{create_test_block_with_data, create_test_block}
|
||||||
};
|
};
|
||||||
use common_types::{
|
use common_types::{
|
||||||
encoded,
|
|
||||||
engines::params::CommonParams,
|
engines::params::CommonParams,
|
||||||
errors::BlockError::*,
|
errors::BlockError::*,
|
||||||
transaction::{SignedTransaction, Transaction, UnverifiedTransaction, Action},
|
transaction::{SignedTransaction, Transaction, UnverifiedTransaction, Action},
|
||||||
log_entry::{LogEntry, LocalizedLogEntry},
|
|
||||||
};
|
};
|
||||||
use rlp;
|
use rlp;
|
||||||
use triehash::ordered_trie_root;
|
use triehash::ordered_trie_root;
|
||||||
use machine::Machine;
|
use machine::Machine;
|
||||||
use null_engine::NullEngine;
|
use null_engine::NullEngine;
|
||||||
|
|
||||||
|
use crate::test_helpers::TestBlockChain;
|
||||||
|
|
||||||
fn check_ok(result: Result<(), Error>) {
|
fn check_ok(result: Result<(), Error>) {
|
||||||
result.unwrap_or_else(|e| panic!("Block verification failed: {:?}", e));
|
result.unwrap_or_else(|e| panic!("Block verification failed: {:?}", e));
|
||||||
}
|
}
|
||||||
@ -412,101 +415,6 @@ mod tests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct TestBlockChain {
|
|
||||||
blocks: HashMap<H256, Bytes>,
|
|
||||||
numbers: HashMap<BlockNumber, H256>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for TestBlockChain {
|
|
||||||
fn default() -> Self {
|
|
||||||
TestBlockChain::new()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TestBlockChain {
|
|
||||||
pub fn new() -> Self {
|
|
||||||
TestBlockChain {
|
|
||||||
blocks: HashMap::new(),
|
|
||||||
numbers: HashMap::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get raw block data
|
|
||||||
fn block(&self, hash: &H256) -> Option<encoded::Block> {
|
|
||||||
self.blocks.get(hash).cloned().map(encoded::Block::new)
|
|
||||||
}
|
|
||||||
|
|
||||||
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 best_ancient_block(&self) -> Option<H256> {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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,
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn transaction_address(&self, _hash: &H256) -> Option<TransactionAddress> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the hash of given block's number.
|
|
||||||
fn block_hash(&self, index: BlockNumber) -> Option<H256> {
|
|
||||||
self.numbers.get(&index).cloned()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn block_receipts(&self, _hash: &H256) -> Option<BlockReceipts> {
|
|
||||||
unimplemented!()
|
|
||||||
}
|
|
||||||
|
|
||||||
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!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn basic_test(bytes: &[u8], engine: &dyn Engine) -> Result<(), Error> {
|
fn basic_test(bytes: &[u8], engine: &dyn Engine) -> Result<(), Error> {
|
||||||
let unverified = Unverified::from_rlp(bytes.to_vec())?;
|
let unverified = Unverified::from_rlp(bytes.to_vec())?;
|
||||||
verify_block_basic(&unverified, engine, true)
|
verify_block_basic(&unverified, engine, true)
|
||||||
|
Loading…
Reference in New Issue
Block a user