2020-01-17 14:27:28 +01:00
|
|
|
// Copyright 2015-2020 Parity Technologies (UK) Ltd.
|
2019-01-07 11:33:07 +01:00
|
|
|
// This file is part of Parity Ethereum.
|
2016-02-05 13:40:41 +01:00
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is free software: you can redistribute it and/or modify
|
2016-02-05 13:40:41 +01:00
|
|
|
// 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.
|
|
|
|
|
2019-01-07 11:33:07 +01:00
|
|
|
// Parity Ethereum is distributed in the hope that it will be useful,
|
2016-02-05 13:40:41 +01:00
|
|
|
// 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
|
2019-01-07 11:33:07 +01:00
|
|
|
// along with Parity Ethereum. If not, see <http://www.gnu.org/licenses/>.
|
2016-02-05 13:40:41 +01:00
|
|
|
|
2016-11-10 18:30:17 +01:00
|
|
|
//! Block and transaction verification functions
|
|
|
|
//!
|
|
|
|
//! Block verification is done in 3 steps
|
|
|
|
//! 1. Quick verification upon adding to the block queue
|
|
|
|
//! 2. Signatures verification done in the queue.
|
|
|
|
//! 3. Final verification against the blockchain done before enactment.
|
2016-01-10 21:30:22 +01:00
|
|
|
|
2017-07-29 17:12:07 +02:00
|
|
|
use std::collections::HashSet;
|
2018-04-14 21:35:58 +02:00
|
|
|
use std::time::{Duration, SystemTime, UNIX_EPOCH};
|
2017-09-26 14:19:08 +02:00
|
|
|
|
2019-08-28 10:09:42 +02:00
|
|
|
use keccak_hash::keccak;
|
2018-04-16 15:52:12 +02:00
|
|
|
use rlp::Rlp;
|
2017-09-26 14:19:08 +02:00
|
|
|
use triehash::ordered_trie_root;
|
|
|
|
use unexpected::{Mismatch, OutOfBounds};
|
2016-01-09 19:10:05 +01:00
|
|
|
|
2019-11-12 15:05:49 +01:00
|
|
|
use blockchain::BlockProvider;
|
2019-01-17 16:43:08 +01:00
|
|
|
use call_contract::CallContract;
|
2019-08-13 12:33:34 +02:00
|
|
|
use client_traits::BlockInfo;
|
2019-08-15 17:59:22 +02:00
|
|
|
use engine::Engine;
|
2019-08-28 10:09:42 +02:00
|
|
|
use common_types::{
|
2019-07-18 12:27:08 +02:00
|
|
|
BlockNumber,
|
|
|
|
header::Header,
|
|
|
|
errors::{EthcoreError as Error, BlockError},
|
|
|
|
engines::MAX_UNCLE_AGE,
|
|
|
|
block::PreverifiedBlock,
|
2019-08-15 17:59:22 +02:00
|
|
|
verification::Unverified,
|
2019-07-18 12:27:08 +02:00
|
|
|
};
|
2018-01-17 11:45:29 +01:00
|
|
|
|
2019-03-19 23:17:05 +01:00
|
|
|
use time_utils::CheckedSystemTime;
|
2019-02-12 15:16:23 +01:00
|
|
|
|
2016-01-10 21:30:22 +01:00
|
|
|
/// Phase 1 quick block verification. Only does checks that are cheap. Operates on a single block
|
2019-06-28 10:18:18 +02:00
|
|
|
pub fn verify_block_basic(block: &Unverified, engine: &dyn Engine, check_seal: bool) -> Result<(), Error> {
|
2019-11-12 15:05:49 +01:00
|
|
|
verify_header_params(&block.header, engine, check_seal)?;
|
|
|
|
verify_header_time(&block.header)?;
|
2018-07-25 14:36:46 +02:00
|
|
|
verify_block_integrity(block)?;
|
2018-09-06 04:37:41 +02:00
|
|
|
|
|
|
|
if check_seal {
|
|
|
|
engine.verify_block_basic(&block.header)?;
|
|
|
|
}
|
2018-07-25 14:36:46 +02:00
|
|
|
|
|
|
|
for uncle in &block.uncles {
|
2019-11-12 15:05:49 +01:00
|
|
|
verify_header_params(uncle, engine, check_seal)?;
|
2018-09-06 04:37:41 +02:00
|
|
|
if check_seal {
|
|
|
|
engine.verify_block_basic(uncle)?;
|
|
|
|
}
|
2016-01-10 19:47:32 +01:00
|
|
|
}
|
2018-03-01 19:55:24 +01:00
|
|
|
|
2020-01-13 11:27:03 +01:00
|
|
|
if let Some(gas_limit) = engine.gas_limit_override(&block.header) {
|
|
|
|
if *block.header.gas_limit() != gas_limit {
|
|
|
|
return Err(From::from(BlockError::InvalidGasLimit(
|
|
|
|
OutOfBounds { min: Some(gas_limit), max: Some(gas_limit), found: *block.header.gas_limit() }
|
|
|
|
)));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-25 14:36:46 +02:00
|
|
|
for t in &block.transactions {
|
|
|
|
engine.verify_transaction_basic(t, &block.header)?;
|
2016-01-16 18:30:27 +01:00
|
|
|
}
|
2018-07-25 14:36:46 +02:00
|
|
|
|
2016-01-10 19:47:32 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
2016-01-09 19:10:05 +01:00
|
|
|
|
2016-01-10 21:30:22 +01:00
|
|
|
/// Phase 2 verification. Perform costly checks such as transaction signatures and block nonce for ethash.
|
|
|
|
/// Still operates on a individual block
|
2016-04-06 10:07:24 +02:00
|
|
|
/// Returns a `PreverifiedBlock` structure populated with transactions
|
2019-06-28 10:18:18 +02:00
|
|
|
pub fn verify_block_unordered(block: Unverified, engine: &dyn Engine, check_seal: bool) -> Result<PreverifiedBlock, Error> {
|
2018-07-25 14:36:46 +02:00
|
|
|
let header = block.header;
|
2016-10-24 15:09:13 +02:00
|
|
|
if check_seal {
|
2017-09-26 14:19:08 +02:00
|
|
|
engine.verify_block_unordered(&header)?;
|
2018-07-25 14:36:46 +02:00
|
|
|
for uncle in &block.uncles {
|
|
|
|
engine.verify_block_unordered(uncle)?;
|
2016-10-24 15:09:13 +02:00
|
|
|
}
|
2016-01-10 19:47:32 +01:00
|
|
|
}
|
2016-03-04 11:56:04 +01:00
|
|
|
// Verify transactions.
|
2017-06-28 09:10:57 +02:00
|
|
|
let nonce_cap = if header.number() >= engine.params().dust_protection_transition {
|
|
|
|
Some((engine.params().nonce_cap_increment * header.number()).into())
|
2018-07-25 14:36:46 +02:00
|
|
|
} else {
|
|
|
|
None
|
|
|
|
};
|
|
|
|
|
|
|
|
let transactions = block.transactions
|
|
|
|
.into_iter()
|
|
|
|
.map(|t| {
|
2019-07-21 21:15:08 +02:00
|
|
|
let t = t.verify_unordered()?;
|
2017-06-28 09:10:57 +02:00
|
|
|
if let Some(max_nonce) = nonce_cap {
|
|
|
|
if t.nonce >= max_nonce {
|
|
|
|
return Err(BlockError::TooManyTransactions(t.sender()).into());
|
|
|
|
}
|
|
|
|
}
|
2018-07-25 14:36:46 +02:00
|
|
|
Ok(t)
|
|
|
|
})
|
|
|
|
.collect::<Result<Vec<_>, Error>>()?;
|
|
|
|
|
2016-03-01 00:02:48 +01:00
|
|
|
Ok(PreverifiedBlock {
|
2018-07-25 14:36:46 +02:00
|
|
|
header,
|
|
|
|
transactions,
|
|
|
|
uncles: block.uncles,
|
|
|
|
bytes: block.bytes,
|
2016-01-17 23:07:58 +01:00
|
|
|
})
|
2016-01-09 19:10:05 +01:00
|
|
|
}
|
|
|
|
|
2018-03-03 18:42:13 +01:00
|
|
|
/// Parameters for full verification of block family
|
|
|
|
pub struct FullFamilyParams<'a, C: BlockInfo + CallContract + 'a> {
|
2018-07-25 14:36:46 +02:00
|
|
|
/// Preverified block
|
|
|
|
pub block: &'a PreverifiedBlock,
|
2018-03-03 18:42:13 +01:00
|
|
|
|
|
|
|
/// Block provider to use during verification
|
2019-06-14 18:48:35 +02:00
|
|
|
pub block_provider: &'a dyn BlockProvider,
|
2018-03-03 18:42:13 +01:00
|
|
|
|
|
|
|
/// Engine client to use during verification
|
|
|
|
pub client: &'a C,
|
|
|
|
}
|
2017-09-26 14:19:08 +02:00
|
|
|
|
2016-01-11 13:51:58 +01:00
|
|
|
/// Phase 3 verification. Check block information against parent and uncles.
|
2019-09-11 14:15:19 +02:00
|
|
|
pub fn verify_block_family<C: BlockInfo + CallContract>(
|
|
|
|
header: &Header,
|
|
|
|
parent: &Header,
|
|
|
|
engine: &dyn Engine,
|
2019-11-12 15:05:49 +01:00
|
|
|
params: FullFamilyParams<C>
|
2019-09-11 14:15:19 +02:00
|
|
|
) -> Result<(), Error> {
|
2016-01-14 01:28:37 +01:00
|
|
|
// TODO: verify timestamp
|
2018-04-05 10:11:21 +02:00
|
|
|
verify_parent(&header, &parent, engine)?;
|
2017-09-26 14:19:08 +02:00
|
|
|
engine.verify_block_family(&header, &parent)?;
|
2018-07-25 14:36:46 +02:00
|
|
|
verify_uncles(params.block, params.block_provider, engine)?;
|
2017-09-26 14:19:08 +02:00
|
|
|
|
2018-07-25 14:36:46 +02:00
|
|
|
for tx in ¶ms.block.transactions {
|
2018-11-13 12:58:53 +01:00
|
|
|
// transactions are verified against the parent header since the current
|
|
|
|
// state wasn't available when the tx was created
|
|
|
|
engine.machine().verify_transaction(tx, parent, params.client)?;
|
2017-09-26 14:19:08 +02:00
|
|
|
}
|
2016-01-10 19:47:32 +01:00
|
|
|
|
2017-09-26 14:19:08 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-06-28 10:18:18 +02:00
|
|
|
fn verify_uncles(block: &PreverifiedBlock, bc: &dyn BlockProvider, engine: &dyn Engine) -> Result<(), Error> {
|
2018-07-25 14:36:46 +02:00
|
|
|
let header = &block.header;
|
|
|
|
let num_uncles = block.uncles.len();
|
2017-12-05 15:57:45 +01:00
|
|
|
let max_uncles = engine.maximum_uncle_count(header.number());
|
2016-01-10 19:47:32 +01:00
|
|
|
if num_uncles != 0 {
|
2017-12-05 15:57:45 +01:00
|
|
|
if num_uncles > max_uncles {
|
|
|
|
return Err(From::from(BlockError::TooManyUncles(OutOfBounds {
|
|
|
|
min: None,
|
|
|
|
max: Some(max_uncles),
|
|
|
|
found: num_uncles,
|
|
|
|
})));
|
2016-01-10 19:47:32 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
let mut excluded = HashSet::new();
|
|
|
|
excluded.insert(header.hash());
|
2016-08-29 11:35:24 +02:00
|
|
|
let mut hash = header.parent_hash().clone();
|
2016-01-10 19:47:32 +01:00
|
|
|
excluded.insert(hash.clone());
|
2019-03-14 21:34:26 +01:00
|
|
|
for _ in 0..MAX_UNCLE_AGE {
|
2016-01-10 19:47:32 +01:00
|
|
|
match bc.block_details(&hash) {
|
|
|
|
Some(details) => {
|
2018-11-01 11:04:32 +01:00
|
|
|
excluded.insert(details.parent);
|
2019-11-12 15:05:49 +01:00
|
|
|
let b = bc.block(&hash).expect("parent already known to be stored; qed");
|
2016-12-28 13:44:51 +01:00
|
|
|
excluded.extend(b.uncle_hashes());
|
2016-01-10 19:47:32 +01:00
|
|
|
hash = details.parent;
|
|
|
|
}
|
|
|
|
None => break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-07-10 13:36:42 +02:00
|
|
|
let mut verified = HashSet::new();
|
2018-07-25 14:36:46 +02:00
|
|
|
for uncle in &block.uncles {
|
2016-01-12 13:14:01 +01:00
|
|
|
if excluded.contains(&uncle.hash()) {
|
|
|
|
return Err(From::from(BlockError::UncleInChain(uncle.hash())))
|
2016-01-10 19:47:32 +01:00
|
|
|
}
|
|
|
|
|
2017-07-10 13:36:42 +02:00
|
|
|
if verified.contains(&uncle.hash()) {
|
|
|
|
return Err(From::from(BlockError::DuplicateUncle(uncle.hash())))
|
|
|
|
}
|
|
|
|
|
2019-11-22 10:26:50 +01:00
|
|
|
// uncle.number() needs to be within specific number range which is
|
|
|
|
// [header.number() - MAX_UNCLE_AGE, header.number() - 1]
|
|
|
|
//
|
|
|
|
// depth is the difference between uncle.number() and header.number()
|
|
|
|
// and the previous condition implies that it is always in range
|
|
|
|
// [1, MAX_UNCLE_AGE]
|
|
|
|
let depth = if header.number() > uncle.number() &&
|
|
|
|
uncle.number() + MAX_UNCLE_AGE >= header.number() {
|
|
|
|
header.number() - uncle.number()
|
|
|
|
} else {
|
|
|
|
return Err(BlockError::UncleOutOfBounds(OutOfBounds {
|
|
|
|
min: Some(header.number() - MAX_UNCLE_AGE),
|
2019-11-12 15:05:49 +01:00
|
|
|
max: Some(header.number() - 1),
|
|
|
|
found: uncle.number()
|
2019-11-22 10:26:50 +01:00
|
|
|
}).into());
|
|
|
|
};
|
2016-01-10 19:47:32 +01:00
|
|
|
|
|
|
|
// cB
|
|
|
|
// cB.p^1 1 depth, valid uncle
|
|
|
|
// cB.p^2 ---/ 2
|
|
|
|
// cB.p^3 -----/ 3
|
|
|
|
// cB.p^4 -------/ 4
|
|
|
|
// cB.p^5 ---------/ 5
|
|
|
|
// cB.p^6 -----------/ 6
|
|
|
|
// cB.p^7 -------------/
|
|
|
|
// cB.p^8
|
2016-08-29 11:35:24 +02:00
|
|
|
let mut expected_uncle_parent = header.parent_hash().clone();
|
2019-11-12 15:05:49 +01:00
|
|
|
let uncle_parent = bc.block_header_data(&uncle.parent_hash())
|
2019-11-22 10:26:50 +01:00
|
|
|
.ok_or_else(|| BlockError::UnknownUncleParent(*uncle.parent_hash()))?;
|
2016-01-11 12:45:35 +01:00
|
|
|
for _ in 0..depth {
|
2016-01-12 13:14:01 +01:00
|
|
|
match bc.block_details(&expected_uncle_parent) {
|
2016-03-04 11:56:04 +01:00
|
|
|
Some(details) => {
|
2016-01-12 13:14:01 +01:00
|
|
|
expected_uncle_parent = details.parent;
|
|
|
|
},
|
|
|
|
None => break
|
|
|
|
}
|
2016-01-10 19:47:32 +01:00
|
|
|
}
|
|
|
|
if expected_uncle_parent != uncle_parent.hash() {
|
|
|
|
return Err(From::from(BlockError::UncleParentNotInChain(uncle_parent.hash())));
|
|
|
|
}
|
|
|
|
|
2018-05-09 12:05:56 +02:00
|
|
|
let uncle_parent = uncle_parent.decode()?;
|
2018-04-05 10:11:21 +02:00
|
|
|
verify_parent(&uncle, &uncle_parent, engine)?;
|
2017-09-26 14:19:08 +02:00
|
|
|
engine.verify_block_family(&uncle, &uncle_parent)?;
|
2017-07-10 13:36:42 +02:00
|
|
|
verified.insert(uncle.hash());
|
2016-01-10 19:47:32 +01:00
|
|
|
}
|
|
|
|
}
|
2017-09-26 14:19:08 +02:00
|
|
|
|
2016-01-09 19:10:05 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
2016-01-10 21:30:22 +01:00
|
|
|
|
2016-01-14 19:03:48 +01:00
|
|
|
/// Phase 4 verification. Check block information against transaction enactment results,
|
2017-03-29 19:59:20 +02:00
|
|
|
pub fn verify_block_final(expected: &Header, got: &Header) -> Result<(), Error> {
|
2018-10-31 15:44:46 +01:00
|
|
|
if expected.state_root() != got.state_root() {
|
2019-11-12 15:05:49 +01:00
|
|
|
return Err(From::from(BlockError::InvalidStateRoot(Mismatch {
|
|
|
|
expected: *expected.state_root(),
|
|
|
|
found: *got.state_root()
|
|
|
|
})))
|
2018-10-31 15:44:46 +01:00
|
|
|
}
|
2016-08-29 11:35:24 +02:00
|
|
|
if expected.gas_used() != got.gas_used() {
|
2019-11-12 15:05:49 +01:00
|
|
|
return Err(From::from(BlockError::InvalidGasUsed(Mismatch {
|
|
|
|
expected: *expected.gas_used(),
|
|
|
|
found: *got.gas_used()
|
|
|
|
})))
|
2016-01-14 19:03:48 +01:00
|
|
|
}
|
2016-08-29 11:35:24 +02:00
|
|
|
if expected.log_bloom() != got.log_bloom() {
|
2019-11-12 15:05:49 +01:00
|
|
|
return Err(From::from(BlockError::InvalidLogBloom(Box::new(Mismatch {
|
|
|
|
expected: *expected.log_bloom(),
|
|
|
|
found: *got.log_bloom()
|
|
|
|
}))))
|
2016-01-14 19:03:48 +01:00
|
|
|
}
|
2017-03-29 19:59:20 +02:00
|
|
|
if expected.receipts_root() != got.receipts_root() {
|
2019-11-12 15:05:49 +01:00
|
|
|
return Err(From::from(BlockError::InvalidReceiptsRoot(Mismatch {
|
|
|
|
expected: *expected.receipts_root(),
|
|
|
|
found: *got.receipts_root()
|
|
|
|
})))
|
2016-01-14 19:03:48 +01:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-01-10 21:30:22 +01:00
|
|
|
/// Check basic header parameters.
|
2019-11-12 15:05:49 +01:00
|
|
|
pub(crate) fn verify_header_params(header: &Header, engine: &dyn Engine, check_seal: bool) -> Result<(), Error> {
|
2018-10-16 12:24:47 +02:00
|
|
|
if check_seal {
|
|
|
|
let expected_seal_fields = engine.seal_fields(header);
|
|
|
|
if header.seal().len() != expected_seal_fields {
|
|
|
|
return Err(From::from(BlockError::InvalidSealArity(
|
|
|
|
Mismatch { expected: expected_seal_fields, found: header.seal().len() }
|
|
|
|
)));
|
|
|
|
}
|
2017-09-26 14:19:08 +02:00
|
|
|
}
|
|
|
|
|
2016-08-29 11:35:24 +02:00
|
|
|
if header.number() >= From::from(BlockNumber::max_value()) {
|
2019-11-12 15:05:49 +01:00
|
|
|
return Err(From::from(BlockError::RidiculousNumber(OutOfBounds {
|
|
|
|
max: Some(From::from(BlockNumber::max_value())),
|
|
|
|
min: None,
|
|
|
|
found: header.number()
|
|
|
|
})))
|
2016-01-10 21:30:22 +01:00
|
|
|
}
|
2016-08-29 11:35:24 +02:00
|
|
|
if header.gas_used() > header.gas_limit() {
|
2019-11-12 15:05:49 +01:00
|
|
|
return Err(From::from(BlockError::TooMuchGasUsed(OutOfBounds {
|
|
|
|
max: Some(*header.gas_limit()),
|
|
|
|
min: None,
|
|
|
|
found: *header.gas_used()
|
|
|
|
})));
|
2016-01-10 21:30:22 +01:00
|
|
|
}
|
2020-01-13 11:27:03 +01:00
|
|
|
if engine.gas_limit_override(header).is_none() {
|
|
|
|
let min_gas_limit = engine.min_gas_limit();
|
|
|
|
if header.gas_limit() < &min_gas_limit {
|
2019-11-12 15:05:49 +01:00
|
|
|
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds {
|
2020-01-13 11:27:03 +01:00
|
|
|
min: Some(min_gas_limit),
|
|
|
|
max: None,
|
2019-11-12 15:05:49 +01:00
|
|
|
found: *header.gas_limit()
|
|
|
|
})));
|
2018-11-01 11:04:32 +01:00
|
|
|
}
|
2020-01-13 11:27:03 +01:00
|
|
|
if let Some(limit) = engine.maximum_gas_limit() {
|
|
|
|
if header.gas_limit() > &limit {
|
|
|
|
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds {
|
|
|
|
min: None,
|
|
|
|
max: Some(limit),
|
|
|
|
found: *header.gas_limit()
|
|
|
|
})));
|
|
|
|
}
|
|
|
|
}
|
2016-01-11 15:19:43 +01:00
|
|
|
}
|
|
|
|
let maximum_extra_data_size = engine.maximum_extra_data_size();
|
2016-08-29 11:35:24 +02:00
|
|
|
if header.number() != 0 && header.extra_data().len() > maximum_extra_data_size {
|
2019-11-12 15:05:49 +01:00
|
|
|
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds {
|
|
|
|
min: None,
|
|
|
|
max: Some(maximum_extra_data_size),
|
|
|
|
found: header.extra_data().len()
|
|
|
|
})));
|
2016-01-11 15:19:43 +01:00
|
|
|
}
|
2017-09-26 14:19:08 +02:00
|
|
|
|
|
|
|
if let Some(ref ext) = engine.machine().ethash_extensions() {
|
|
|
|
if header.number() >= ext.dao_hardfork_transition &&
|
|
|
|
header.number() <= ext.dao_hardfork_transition + 9 &&
|
|
|
|
header.extra_data()[..] != b"dao-hard-fork"[..] {
|
2019-11-12 15:05:49 +01:00
|
|
|
return Err(From::from(BlockError::ExtraDataOutOfBounds(OutOfBounds {
|
|
|
|
min: None,
|
|
|
|
max: None,
|
|
|
|
found: 0
|
|
|
|
})));
|
2017-09-26 14:19:08 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-12 15:05:49 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
2017-12-21 15:01:05 +01:00
|
|
|
|
2019-11-12 15:05:49 +01:00
|
|
|
/// A header verification step that should be done for new block headers, but not for uncles.
|
|
|
|
pub(crate) fn verify_header_time(header: &Header) -> Result<(), Error> {
|
|
|
|
const ACCEPTABLE_DRIFT: Duration = Duration::from_secs(15);
|
|
|
|
// this will resist overflow until `year 2037`
|
|
|
|
let max_time = SystemTime::now() + ACCEPTABLE_DRIFT;
|
|
|
|
let invalid_threshold = max_time + ACCEPTABLE_DRIFT * 9;
|
|
|
|
let timestamp = CheckedSystemTime::checked_add(UNIX_EPOCH, Duration::from_secs(header.timestamp()))
|
|
|
|
.ok_or(BlockError::TimestampOverflow)?;
|
|
|
|
|
|
|
|
if timestamp > invalid_threshold {
|
|
|
|
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds {
|
|
|
|
max: Some(max_time),
|
|
|
|
min: None,
|
|
|
|
found: timestamp
|
|
|
|
}.into())))
|
|
|
|
}
|
2017-12-21 15:01:05 +01:00
|
|
|
|
2019-11-12 15:05:49 +01:00
|
|
|
if timestamp > max_time {
|
|
|
|
return Err(From::from(BlockError::TemporarilyInvalid(OutOfBounds {
|
|
|
|
max: Some(max_time),
|
|
|
|
min: None,
|
|
|
|
found: timestamp
|
|
|
|
}.into())))
|
2016-11-28 15:14:43 +01:00
|
|
|
}
|
2017-12-21 15:01:05 +01:00
|
|
|
|
2016-01-10 21:30:22 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2019-09-11 14:15:19 +02:00
|
|
|
/// Check header parameters against parent header.
|
2019-06-28 10:18:18 +02:00
|
|
|
fn verify_parent(header: &Header, parent: &Header, engine: &dyn Engine) -> Result<(), Error> {
|
2018-04-05 11:03:25 +02:00
|
|
|
assert!(header.parent_hash().is_zero() || &parent.hash() == header.parent_hash(),
|
|
|
|
"Parent hash should already have been verified; qed");
|
|
|
|
|
2018-04-05 10:11:21 +02:00
|
|
|
if !engine.is_timestamp_valid(header.timestamp(), parent.timestamp()) {
|
2019-03-19 23:17:05 +01:00
|
|
|
let now = SystemTime::now();
|
2019-06-20 09:00:50 +02:00
|
|
|
let min = CheckedSystemTime::checked_add(now, Duration::from_secs(parent.timestamp().saturating_add(1)))
|
2019-03-19 23:17:05 +01:00
|
|
|
.ok_or(BlockError::TimestampOverflow)?;
|
2019-06-20 09:00:50 +02:00
|
|
|
let found = CheckedSystemTime::checked_add(now, Duration::from_secs(header.timestamp()))
|
2019-03-19 23:17:05 +01:00
|
|
|
.ok_or(BlockError::TimestampOverflow)?;
|
2019-05-06 15:06:20 +02:00
|
|
|
return Err(From::from(BlockError::InvalidTimestamp(OutOfBounds { max: None, min: Some(min), found }.into())))
|
2016-01-10 21:30:22 +01:00
|
|
|
}
|
2016-08-29 11:35:24 +02:00
|
|
|
if header.number() != parent.number() + 1 {
|
2019-11-12 15:05:49 +01:00
|
|
|
return Err(From::from(BlockError::InvalidNumber(Mismatch {
|
|
|
|
expected: parent.number() + 1,
|
|
|
|
found: header.number()
|
|
|
|
})));
|
2016-01-10 21:30:22 +01:00
|
|
|
}
|
2017-09-26 14:19:08 +02:00
|
|
|
|
|
|
|
if header.number() == 0 {
|
2019-11-12 15:05:49 +01:00
|
|
|
return Err(BlockError::RidiculousNumber(OutOfBounds {
|
|
|
|
min: Some(1),
|
|
|
|
max: None,
|
|
|
|
found: header.number()
|
|
|
|
}).into());
|
2017-09-26 14:19:08 +02:00
|
|
|
}
|
2020-01-13 11:27:03 +01:00
|
|
|
if engine.gas_limit_override(header).is_none() {
|
|
|
|
let gas_limit_divisor = engine.params().gas_limit_bound_divisor;
|
|
|
|
let parent_gas_limit = *parent.gas_limit();
|
|
|
|
let min_gas = parent_gas_limit - parent_gas_limit / gas_limit_divisor;
|
|
|
|
let max_gas = parent_gas_limit + parent_gas_limit / gas_limit_divisor;
|
|
|
|
if header.gas_limit() <= &min_gas || header.gas_limit() >= &max_gas {
|
|
|
|
return Err(From::from(BlockError::InvalidGasLimit(OutOfBounds {
|
|
|
|
min: Some(min_gas),
|
|
|
|
max: Some(max_gas),
|
|
|
|
found: *header.gas_limit()
|
|
|
|
})));
|
|
|
|
}
|
2017-09-26 14:19:08 +02:00
|
|
|
}
|
|
|
|
|
2016-01-10 21:30:22 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Verify block data against header: transactions root and uncles hash.
|
2018-07-25 14:36:46 +02:00
|
|
|
fn verify_block_integrity(block: &Unverified) -> Result<(), Error> {
|
|
|
|
let block_rlp = Rlp::new(&block.bytes);
|
|
|
|
let tx = block_rlp.at(1)?;
|
|
|
|
let expected_root = ordered_trie_root(tx.iter().map(|r| r.as_raw()));
|
|
|
|
if &expected_root != block.header.transactions_root() {
|
2019-05-06 15:06:20 +02:00
|
|
|
return Err(BlockError::InvalidTransactionsRoot(Mismatch {
|
2018-07-25 14:36:46 +02:00
|
|
|
expected: expected_root,
|
|
|
|
found: *block.header.transactions_root(),
|
2019-05-06 15:06:20 +02:00
|
|
|
}).into());
|
2018-07-25 14:36:46 +02:00
|
|
|
}
|
|
|
|
let expected_uncles = keccak(block_rlp.at(2)?.as_raw());
|
|
|
|
if &expected_uncles != block.header.uncles_hash(){
|
2019-05-06 15:06:20 +02:00
|
|
|
return Err(BlockError::InvalidUnclesHash(Mismatch {
|
2018-07-25 14:36:46 +02:00
|
|
|
expected: expected_uncles,
|
|
|
|
found: *block.header.uncles_hash(),
|
2019-05-06 15:06:20 +02:00
|
|
|
}).into());
|
2016-01-10 21:30:22 +01:00
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2016-01-12 13:14:01 +01:00
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2018-01-11 17:49:10 +01:00
|
|
|
use super::*;
|
|
|
|
|
2019-09-11 14:15:19 +02:00
|
|
|
use std::collections::BTreeMap;
|
2018-03-14 12:29:52 +01:00
|
|
|
use std::time::{SystemTime, UNIX_EPOCH};
|
2019-08-28 10:09:42 +02:00
|
|
|
|
2019-09-11 14:15:19 +02:00
|
|
|
use ethereum_types::{H256, U256, Address};
|
2019-08-28 10:09:42 +02:00
|
|
|
use parity_bytes::Bytes;
|
|
|
|
use keccak_hash::keccak;
|
2019-08-15 17:59:22 +02:00
|
|
|
use engine::Engine;
|
2019-10-23 13:03:46 +02:00
|
|
|
use parity_crypto::publickey::{Random, Generator};
|
2019-08-23 15:32:58 +02:00
|
|
|
use spec;
|
2019-09-17 16:42:22 +02:00
|
|
|
use ethcore::test_helpers::{
|
|
|
|
create_test_block_with_data, create_test_block, TestBlockChainClient
|
2019-08-28 10:09:42 +02:00
|
|
|
};
|
|
|
|
use common_types::{
|
2019-07-18 12:27:08 +02:00
|
|
|
engines::params::CommonParams,
|
|
|
|
errors::BlockError::*,
|
|
|
|
transaction::{SignedTransaction, Transaction, UnverifiedTransaction, Action},
|
|
|
|
};
|
2018-03-01 19:55:24 +01:00
|
|
|
use rlp;
|
|
|
|
use triehash::ordered_trie_root;
|
2019-08-28 10:09:42 +02:00
|
|
|
use machine::Machine;
|
|
|
|
use null_engine::NullEngine;
|
2016-01-12 13:14:01 +01:00
|
|
|
|
2019-09-11 14:15:19 +02:00
|
|
|
use crate::test_helpers::TestBlockChain;
|
|
|
|
|
2016-01-12 13:14:01 +01:00
|
|
|
fn check_ok(result: Result<(), Error>) {
|
|
|
|
result.unwrap_or_else(|e| panic!("Block verification failed: {:?}", e));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn check_fail(result: Result<(), Error>, e: BlockError) {
|
|
|
|
match result {
|
2019-05-06 15:06:20 +02:00
|
|
|
Err(Error::Block(ref error)) if *error == e => (),
|
2016-01-12 13:14:01 +01:00
|
|
|
Err(other) => panic!("Block verification failed.\nExpected: {:?}\nGot: {:?}", e, other),
|
|
|
|
Ok(_) => panic!("Block verification failed.\nExpected: {:?}\nGot: Ok", e),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-21 15:01:05 +01:00
|
|
|
fn check_fail_timestamp(result: Result<(), Error>, temp: bool) {
|
|
|
|
let name = if temp { "TemporarilyInvalid" } else { "InvalidTimestamp" };
|
2016-11-29 12:18:33 +01:00
|
|
|
match result {
|
2019-05-06 15:06:20 +02:00
|
|
|
Err(Error::Block(BlockError::InvalidTimestamp(_))) if !temp => (),
|
|
|
|
Err(Error::Block(BlockError::TemporarilyInvalid(_))) if temp => (),
|
2017-12-21 15:01:05 +01:00
|
|
|
Err(other) => panic!("Block verification failed.\nExpected: {}\nGot: {:?}", name, other),
|
|
|
|
Ok(_) => panic!("Block verification failed.\nExpected: {}\nGot: Ok", name),
|
2016-11-29 12:18:33 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-28 10:18:18 +02:00
|
|
|
fn basic_test(bytes: &[u8], engine: &dyn Engine) -> Result<(), Error> {
|
2018-07-25 14:36:46 +02:00
|
|
|
let unverified = Unverified::from_rlp(bytes.to_vec())?;
|
2018-09-06 04:37:41 +02:00
|
|
|
verify_block_basic(&unverified, engine, true)
|
2016-01-15 12:26:04 +01:00
|
|
|
}
|
|
|
|
|
2019-06-28 10:18:18 +02:00
|
|
|
fn family_test<BC>(bytes: &[u8], engine: &dyn Engine, bc: &BC) -> Result<(), Error> where BC: BlockProvider {
|
2018-08-24 11:53:31 +02:00
|
|
|
let block = Unverified::from_rlp(bytes.to_vec()).unwrap();
|
|
|
|
let header = block.header;
|
|
|
|
let transactions: Vec<_> = block.transactions
|
2017-09-26 14:19:08 +02:00
|
|
|
.into_iter()
|
|
|
|
.map(SignedTransaction::new)
|
|
|
|
.collect::<Result<_,_>>()?;
|
|
|
|
|
|
|
|
// TODO: client is really meant to be used for state query here by machine
|
|
|
|
// additions that need access to state (tx filter in specific)
|
|
|
|
// no existing tests need access to test, so having this not function
|
|
|
|
// is fine.
|
2019-08-28 10:09:42 +02:00
|
|
|
let client = TestBlockChainClient::default();
|
2018-04-03 10:01:28 +02:00
|
|
|
let parent = bc.block_header_data(header.parent_hash())
|
2018-11-01 11:04:32 +01:00
|
|
|
.ok_or(BlockError::UnknownParent(*header.parent_hash()))?
|
2018-05-09 12:05:56 +02:00
|
|
|
.decode()?;
|
2017-09-26 14:19:08 +02:00
|
|
|
|
2018-07-25 14:36:46 +02:00
|
|
|
let block = PreverifiedBlock {
|
|
|
|
header,
|
|
|
|
transactions,
|
2018-08-24 11:53:31 +02:00
|
|
|
uncles: block.uncles,
|
2018-07-25 14:36:46 +02:00
|
|
|
bytes: bytes.to_vec(),
|
|
|
|
};
|
|
|
|
|
2018-03-03 18:42:13 +01:00
|
|
|
let full_params = FullFamilyParams {
|
2018-07-25 14:36:46 +02:00
|
|
|
block: &block,
|
2019-06-14 18:48:35 +02:00
|
|
|
block_provider: bc as &dyn BlockProvider,
|
2018-03-03 18:42:13 +01:00
|
|
|
client: &client,
|
|
|
|
};
|
2019-11-12 15:05:49 +01:00
|
|
|
verify_block_family(&block.header, &parent, engine, full_params)
|
2016-01-15 12:26:04 +01:00
|
|
|
}
|
|
|
|
|
2019-06-28 10:18:18 +02:00
|
|
|
fn unordered_test(bytes: &[u8], engine: &dyn Engine) -> Result<(), Error> {
|
2018-07-25 14:36:46 +02:00
|
|
|
let un = Unverified::from_rlp(bytes.to_vec())?;
|
|
|
|
verify_block_unordered(un, engine, false)?;
|
2017-06-28 09:10:57 +02:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2018-03-01 19:55:24 +01:00
|
|
|
#[test]
|
|
|
|
fn test_verify_block_basic_with_invalid_transactions() {
|
2019-08-07 16:52:48 +02:00
|
|
|
let spec = spec::new_test();
|
2018-03-01 19:55:24 +01:00
|
|
|
let engine = &*spec.engine;
|
|
|
|
|
|
|
|
let block = {
|
|
|
|
let mut rlp = rlp::RlpStream::new_list(3);
|
|
|
|
let mut header = Header::default();
|
|
|
|
// that's an invalid transaction list rlp
|
|
|
|
let invalid_transactions = vec![vec![0u8]];
|
|
|
|
header.set_transactions_root(ordered_trie_root(&invalid_transactions));
|
2020-01-13 11:27:03 +01:00
|
|
|
header.set_gas_limit(engine.min_gas_limit());
|
2018-03-01 19:55:24 +01:00
|
|
|
rlp.append(&header);
|
|
|
|
rlp.append_list::<Vec<u8>, _>(&invalid_transactions);
|
|
|
|
rlp.append_raw(&rlp::EMPTY_LIST_RLP, 1);
|
|
|
|
rlp.out()
|
|
|
|
};
|
|
|
|
|
|
|
|
assert!(basic_test(&block, engine).is_err());
|
|
|
|
}
|
|
|
|
|
2016-01-12 13:14:01 +01:00
|
|
|
#[test]
|
|
|
|
fn test_verify_block() {
|
2017-03-20 19:14:29 +01:00
|
|
|
use rlp::RlpStream;
|
2016-09-01 14:29:59 +02:00
|
|
|
|
2020-01-28 17:24:36 +01:00
|
|
|
// Test against null_morden
|
2016-01-12 13:14:01 +01:00
|
|
|
let mut good = Header::new();
|
2019-08-07 16:52:48 +02:00
|
|
|
let spec = spec::new_test();
|
2016-08-10 16:29:40 +02:00
|
|
|
let engine = &*spec.engine;
|
2016-01-12 13:14:01 +01:00
|
|
|
|
2020-01-13 11:27:03 +01:00
|
|
|
let min_gas_limit = engine.min_gas_limit();
|
2016-08-29 11:35:24 +02:00
|
|
|
good.set_gas_limit(min_gas_limit);
|
|
|
|
good.set_timestamp(40);
|
|
|
|
good.set_number(10);
|
2016-01-12 13:14:01 +01:00
|
|
|
|
2020-02-10 18:29:21 +01:00
|
|
|
let keypair = Random.generate();
|
2016-02-04 23:48:29 +01:00
|
|
|
|
|
|
|
let tr1 = Transaction {
|
|
|
|
action: Action::Create,
|
|
|
|
value: U256::from(0),
|
|
|
|
data: Bytes::new(),
|
|
|
|
gas: U256::from(30_000),
|
|
|
|
gas_price: U256::from(40_000),
|
|
|
|
nonce: U256::one()
|
2016-11-03 22:22:25 +01:00
|
|
|
}.sign(keypair.secret(), None);
|
2016-02-04 23:48:29 +01:00
|
|
|
|
|
|
|
let tr2 = Transaction {
|
|
|
|
action: Action::Create,
|
|
|
|
value: U256::from(0),
|
|
|
|
data: Bytes::new(),
|
|
|
|
gas: U256::from(30_000),
|
|
|
|
gas_price: U256::from(40_000),
|
|
|
|
nonce: U256::from(2)
|
2016-11-03 22:22:25 +01:00
|
|
|
}.sign(keypair.secret(), None);
|
2016-02-04 23:48:29 +01:00
|
|
|
|
2018-06-05 19:49:11 +02:00
|
|
|
let tr3 = Transaction {
|
2019-06-03 15:36:21 +02:00
|
|
|
action: Action::Call(Address::from_low_u64_be(0x0)),
|
2018-06-05 19:49:11 +02:00
|
|
|
value: U256::from(0),
|
|
|
|
data: Bytes::new(),
|
|
|
|
gas: U256::from(30_000),
|
|
|
|
gas_price: U256::from(0),
|
|
|
|
nonce: U256::zero(),
|
|
|
|
}.null_sign(0);
|
|
|
|
|
2016-06-16 12:44:08 +02:00
|
|
|
let good_transactions = [ tr1.clone(), tr2.clone() ];
|
2018-06-05 19:49:11 +02:00
|
|
|
let eip86_transactions = [ tr3.clone() ];
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
let diff_inc = U256::from(0x40);
|
|
|
|
|
|
|
|
let mut parent6 = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
parent6.set_number(6);
|
2016-01-12 13:14:01 +01:00
|
|
|
let mut parent7 = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
parent7.set_number(7);
|
|
|
|
parent7.set_parent_hash(parent6.hash());
|
|
|
|
parent7.set_difficulty(parent6.difficulty().clone() + diff_inc);
|
|
|
|
parent7.set_timestamp(parent6.timestamp() + 10);
|
2016-01-12 13:14:01 +01:00
|
|
|
let mut parent8 = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
parent8.set_number(8);
|
|
|
|
parent8.set_parent_hash(parent7.hash());
|
|
|
|
parent8.set_difficulty(parent7.difficulty().clone() + diff_inc);
|
|
|
|
parent8.set_timestamp(parent7.timestamp() + 10);
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
let mut good_uncle1 = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
good_uncle1.set_number(9);
|
|
|
|
good_uncle1.set_parent_hash(parent8.hash());
|
|
|
|
good_uncle1.set_difficulty(parent8.difficulty().clone() + diff_inc);
|
|
|
|
good_uncle1.set_timestamp(parent8.timestamp() + 10);
|
2019-01-04 14:05:46 +01:00
|
|
|
let mut ex = good_uncle1.extra_data().to_vec();
|
|
|
|
ex.push(1u8);
|
|
|
|
good_uncle1.set_extra_data(ex);
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
let mut good_uncle2 = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
good_uncle2.set_number(8);
|
|
|
|
good_uncle2.set_parent_hash(parent7.hash());
|
|
|
|
good_uncle2.set_difficulty(parent7.difficulty().clone() + diff_inc);
|
|
|
|
good_uncle2.set_timestamp(parent7.timestamp() + 10);
|
2019-01-04 14:05:46 +01:00
|
|
|
let mut ex = good_uncle2.extra_data().to_vec();
|
|
|
|
ex.push(2u8);
|
|
|
|
good_uncle2.set_extra_data(ex);
|
2016-01-12 13:14:01 +01:00
|
|
|
|
2016-01-12 13:43:43 +01:00
|
|
|
let good_uncles = vec![ good_uncle1.clone(), good_uncle2.clone() ];
|
2016-01-12 13:14:01 +01:00
|
|
|
let mut uncles_rlp = RlpStream::new();
|
2017-03-20 19:14:29 +01:00
|
|
|
uncles_rlp.append_list(&good_uncles);
|
2017-08-30 19:18:28 +02:00
|
|
|
let good_uncles_hash = keccak(uncles_rlp.as_raw());
|
2018-02-16 20:24:16 +01:00
|
|
|
let good_transactions_root = ordered_trie_root(good_transactions.iter().map(|t| ::rlp::encode::<UnverifiedTransaction>(t)));
|
2018-06-05 19:49:11 +02:00
|
|
|
let eip86_transactions_root = ordered_trie_root(eip86_transactions.iter().map(|t| ::rlp::encode::<UnverifiedTransaction>(t)));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
let mut parent = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
parent.set_number(9);
|
|
|
|
parent.set_timestamp(parent8.timestamp() + 10);
|
|
|
|
parent.set_parent_hash(parent8.hash());
|
|
|
|
parent.set_difficulty(parent8.difficulty().clone() + diff_inc);
|
2016-01-12 13:14:01 +01:00
|
|
|
|
2016-08-29 11:35:24 +02:00
|
|
|
good.set_parent_hash(parent.hash());
|
|
|
|
good.set_difficulty(parent.difficulty().clone() + diff_inc);
|
|
|
|
good.set_timestamp(parent.timestamp() + 10);
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
let mut bc = TestBlockChain::new();
|
|
|
|
bc.insert(create_test_block(&good));
|
|
|
|
bc.insert(create_test_block(&parent));
|
|
|
|
bc.insert(create_test_block(&parent6));
|
|
|
|
bc.insert(create_test_block(&parent7));
|
|
|
|
bc.insert(create_test_block(&parent8));
|
|
|
|
|
2016-08-10 16:29:40 +02:00
|
|
|
check_ok(basic_test(&create_test_block(&good), engine));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
2018-06-05 19:49:11 +02:00
|
|
|
let mut bad_header = good.clone();
|
|
|
|
bad_header.set_transactions_root(eip86_transactions_root.clone());
|
|
|
|
bad_header.set_uncles_hash(good_uncles_hash.clone());
|
|
|
|
|
2016-01-12 13:14:01 +01:00
|
|
|
let mut header = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
header.set_transactions_root(good_transactions_root.clone());
|
|
|
|
header.set_uncles_hash(good_uncles_hash.clone());
|
2016-08-10 16:29:40 +02:00
|
|
|
check_ok(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
2018-09-04 20:13:51 +02:00
|
|
|
header.set_gas_limit(min_gas_limit - 1);
|
2016-08-10 16:29:40 +02:00
|
|
|
check_fail(basic_test(&create_test_block(&header), engine),
|
2016-08-29 11:35:24 +02:00
|
|
|
InvalidGasLimit(OutOfBounds { min: Some(min_gas_limit), max: None, found: header.gas_limit().clone() }));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
header = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
header.set_number(BlockNumber::max_value());
|
2016-08-10 16:29:40 +02:00
|
|
|
check_fail(basic_test(&create_test_block(&header), engine),
|
2016-08-29 11:35:24 +02:00
|
|
|
RidiculousNumber(OutOfBounds { max: Some(BlockNumber::max_value()), min: None, found: header.number() }));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
header = good.clone();
|
2018-09-04 20:13:51 +02:00
|
|
|
let gas_used = header.gas_limit().clone() + 1;
|
2016-08-29 11:35:24 +02:00
|
|
|
header.set_gas_used(gas_used);
|
2016-08-10 16:29:40 +02:00
|
|
|
check_fail(basic_test(&create_test_block(&header), engine),
|
2016-08-29 11:35:24 +02:00
|
|
|
TooMuchGasUsed(OutOfBounds { max: Some(header.gas_limit().clone()), min: None, found: header.gas_used().clone() }));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
header = good.clone();
|
2019-01-04 14:05:46 +01:00
|
|
|
let mut ex = header.extra_data().to_vec();
|
|
|
|
ex.resize(engine.maximum_extra_data_size() + 1, 0u8);
|
|
|
|
header.set_extra_data(ex);
|
2016-08-10 16:29:40 +02:00
|
|
|
check_fail(basic_test(&create_test_block(&header), engine),
|
2016-08-29 11:35:24 +02:00
|
|
|
ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data().len() }));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
header = good.clone();
|
2019-01-04 14:05:46 +01:00
|
|
|
let mut ex = header.extra_data().to_vec();
|
|
|
|
ex.resize(engine.maximum_extra_data_size() + 1, 0u8);
|
|
|
|
header.set_extra_data(ex);
|
2016-08-10 16:29:40 +02:00
|
|
|
check_fail(basic_test(&create_test_block(&header), engine),
|
2016-08-29 11:35:24 +02:00
|
|
|
ExtraDataOutOfBounds(OutOfBounds { max: Some(engine.maximum_extra_data_size()), min: None, found: header.extra_data().len() }));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
header = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
header.set_uncles_hash(good_uncles_hash.clone());
|
2016-08-10 16:29:40 +02:00
|
|
|
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine),
|
2016-08-29 11:35:24 +02:00
|
|
|
InvalidTransactionsRoot(Mismatch { expected: good_transactions_root.clone(), found: header.transactions_root().clone() }));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
header = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
header.set_transactions_root(good_transactions_root.clone());
|
2016-08-10 16:29:40 +02:00
|
|
|
check_fail(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine),
|
2016-08-29 11:35:24 +02:00
|
|
|
InvalidUnclesHash(Mismatch { expected: good_uncles_hash.clone(), found: header.uncles_hash().clone() }));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
2016-08-10 16:29:40 +02:00
|
|
|
check_ok(family_test(&create_test_block(&good), engine, &bc));
|
|
|
|
check_ok(family_test(&create_test_block_with_data(&good, &good_transactions, &good_uncles), engine, &bc));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
header = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
header.set_parent_hash(H256::random());
|
2016-08-10 16:29:40 +02:00
|
|
|
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
|
2016-08-29 11:35:24 +02:00
|
|
|
UnknownParent(header.parent_hash().clone()));
|
2016-01-12 13:14:01 +01:00
|
|
|
|
|
|
|
header = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
header.set_timestamp(10);
|
2018-04-14 21:35:58 +02:00
|
|
|
check_fail_timestamp(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc), false);
|
2016-01-12 13:14:01 +01:00
|
|
|
|
2016-11-28 15:14:43 +01:00
|
|
|
header = good.clone();
|
2019-02-12 15:16:23 +01:00
|
|
|
// will return `BlockError::TimestampOverflow` when timestamp > `i32::max_value()`
|
|
|
|
header.set_timestamp(i32::max_value() as u64);
|
2017-12-21 15:01:05 +01:00
|
|
|
check_fail_timestamp(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine), false);
|
2016-11-28 15:14:43 +01:00
|
|
|
|
|
|
|
header = good.clone();
|
2018-03-14 12:29:52 +01:00
|
|
|
header.set_timestamp(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() + 20);
|
2017-12-21 15:01:05 +01:00
|
|
|
check_fail_timestamp(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine), true);
|
2016-11-28 15:14:43 +01:00
|
|
|
|
2017-12-08 11:43:31 +01:00
|
|
|
header = good.clone();
|
2018-03-14 12:29:52 +01:00
|
|
|
header.set_timestamp(SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() + 10);
|
2017-12-08 11:43:31 +01:00
|
|
|
header.set_uncles_hash(good_uncles_hash.clone());
|
|
|
|
header.set_transactions_root(good_transactions_root.clone());
|
|
|
|
check_ok(basic_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine));
|
|
|
|
|
2016-01-12 13:14:01 +01:00
|
|
|
header = good.clone();
|
2016-08-29 11:35:24 +02:00
|
|
|
header.set_number(9);
|
2016-08-10 16:29:40 +02:00
|
|
|
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &good_uncles), engine, &bc),
|
2016-08-29 11:35:24 +02:00
|
|
|
InvalidNumber(Mismatch { expected: parent.number() + 1, found: header.number() }));
|
2016-03-04 11:56:04 +01:00
|
|
|
|
2016-01-12 13:43:43 +01:00
|
|
|
header = good.clone();
|
|
|
|
let mut bad_uncles = good_uncles.clone();
|
|
|
|
bad_uncles.push(good_uncle1.clone());
|
2016-08-10 16:29:40 +02:00
|
|
|
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
|
2017-12-05 15:57:45 +01:00
|
|
|
TooManyUncles(OutOfBounds { max: Some(engine.maximum_uncle_count(header.number())), min: None, found: bad_uncles.len() }));
|
2016-01-12 13:43:43 +01:00
|
|
|
|
2017-07-10 13:36:42 +02:00
|
|
|
header = good.clone();
|
|
|
|
bad_uncles = vec![ good_uncle1.clone(), good_uncle1.clone() ];
|
|
|
|
check_fail(family_test(&create_test_block_with_data(&header, &good_transactions, &bad_uncles), engine, &bc),
|
|
|
|
DuplicateUncle(good_uncle1.hash()));
|
|
|
|
|
2017-09-26 14:19:08 +02:00
|
|
|
header = good.clone();
|
|
|
|
header.set_gas_limit(0.into());
|
|
|
|
header.set_difficulty("0000000000000000000000000000000000000000000000000000000000020000".parse::<U256>().unwrap());
|
|
|
|
match family_test(&create_test_block(&header), engine, &bc) {
|
2019-05-06 15:06:20 +02:00
|
|
|
Err(Error::Block(InvalidGasLimit(_))) => {},
|
2017-09-26 14:19:08 +02:00
|
|
|
Err(_) => { panic!("should be invalid difficulty fail"); },
|
|
|
|
_ => { panic!("Should be error, got Ok"); },
|
|
|
|
}
|
|
|
|
|
2016-01-12 13:43:43 +01:00
|
|
|
// TODO: some additional uncle checks
|
2016-01-12 13:14:01 +01:00
|
|
|
}
|
2017-06-28 09:10:57 +02:00
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn dust_protection() {
|
|
|
|
let mut params = CommonParams::default();
|
|
|
|
params.dust_protection_transition = 0;
|
|
|
|
params.nonce_cap_increment = 2;
|
|
|
|
|
|
|
|
let mut header = Header::default();
|
|
|
|
header.set_number(1);
|
|
|
|
|
2020-02-10 18:29:21 +01:00
|
|
|
let keypair = Random.generate();
|
2017-06-28 09:10:57 +02:00
|
|
|
let bad_transactions: Vec<_> = (0..3).map(|i| Transaction {
|
|
|
|
action: Action::Create,
|
|
|
|
value: U256::zero(),
|
|
|
|
data: Vec::new(),
|
|
|
|
gas: 0.into(),
|
|
|
|
gas_price: U256::zero(),
|
|
|
|
nonce: i.into(),
|
|
|
|
}.sign(keypair.secret(), None)).collect();
|
|
|
|
|
|
|
|
let good_transactions = [bad_transactions[0].clone(), bad_transactions[1].clone()];
|
|
|
|
|
2019-06-26 14:16:05 +02:00
|
|
|
let machine = Machine::regular(params, BTreeMap::new());
|
2017-09-26 14:19:08 +02:00
|
|
|
let engine = NullEngine::new(Default::default(), machine);
|
2017-06-28 09:10:57 +02:00
|
|
|
check_fail(unordered_test(&create_test_block_with_data(&header, &bad_transactions, &[]), &engine), TooManyTransactions(keypair.address()));
|
|
|
|
unordered_test(&create_test_block_with_data(&header, &good_transactions, &[]), &engine).unwrap();
|
|
|
|
}
|
2016-01-12 13:14:01 +01:00
|
|
|
}
|