Generalize engine trait (#6591)

* move common forks and parameters to common params

* port specs over to new format

* fix RPC tests

* parity-machine skeleton

* remove block type

* extract out ethereum-specific methods into EthereumMachine

* beginning to integrate Machine into engines. dealing with stale transitions in Ethash

* initial porting to machine

* move block reward back into engine

* abstract block reward logic

* move last hash and DAO HF logic into machine

* begin making engine function parameters generic

* abstract epoch verifier and ethash block reward logic

* instantiate special ethereummachine for ethash in spec

* optional full verification in verify_block_family

* re-instate tx_filter in a way that works for all engines

* fix warnings

* fix most tests, further generalize engine trait

* uncomment nullengine, get ethcore tests compiling

* fix warnings

* update a bunch of specs

* re-enable engine signer, validator set, and transition handler

* migrate basic_authority engine

* move last hashes into executedblock

* port tendermint

* make all ethcore tests pass

* json-tests compilation

* fix RPC tests: change in gas limit for new block changed PoW hash

* fix minor grumbles

* validate chainspecs

* fix broken import

* fix transaction verification for pre-homestead
This commit is contained in:
Robert Habermeier
2017-09-26 14:19:08 +02:00
committed by Gav Wood
parent d8af9f4e7b
commit bc167a211b
85 changed files with 2233 additions and 1923 deletions

View File

@@ -362,7 +362,7 @@ fn transaction_proof() {
let root = client.best_block_header().state_root();
let mut state = State::from_existing(backend, root, 0.into(), factories.clone()).unwrap();
Executive::new(&mut state, &client.latest_env_info(), &*test_spec.engine)
Executive::new(&mut state, &client.latest_env_info(), test_spec.engine.machine())
.transact(&transaction, TransactOptions::with_no_tracing().dont_check_nonce()).unwrap();
assert_eq!(state.balance(&Address::default()).unwrap(), 5.into());

View File

@@ -24,7 +24,7 @@ fn test_blockhash_eip210(factory: Factory) {
let test_blockhash_contract = "73fffffffffffffffffffffffffffffffffffffffe33141561007a57600143036020526000356101006020510755600061010060205107141561005057600035610100610100602051050761010001555b6000620100006020510714156100755760003561010062010000602051050761020001555b61014a565b4360003512151561009057600060405260206040f35b610100600035430312156100b357610100600035075460605260206060f3610149565b62010000600035430312156100d157600061010060003507146100d4565b60005b156100f6576101006101006000350507610100015460805260206080f3610148565b630100000060003543031215610116576000620100006000350714610119565b60005b1561013c57610100620100006000350507610200015460a052602060a0f3610147565b600060c052602060c0f35b5b5b5b5b";
let blockhash_contract_code = Arc::new(test_blockhash_contract.from_hex().unwrap());
let blockhash_contract_code_hash = keccak(blockhash_contract_code.as_ref());
let engine = TestEngine::new_constantinople();
let machine = ::ethereum::new_constantinople_test_machine();
let mut env_info = EnvInfo::default();
// populate state with 256 last hashes
@@ -46,7 +46,7 @@ fn test_blockhash_eip210(factory: Factory) {
data: Some(H256::from(i - 1).to_vec()),
call_type: CallType::Call,
};
let mut ex = Executive::new(&mut state, &env_info, &engine);
let mut ex = Executive::new(&mut state, &env_info, &machine);
let mut substate = Substate::new();
let mut output = [];
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
@@ -68,7 +68,7 @@ fn test_blockhash_eip210(factory: Factory) {
data: None,
call_type: CallType::Call,
};
let mut ex = Executive::new(&mut state, &env_info, &engine);
let mut ex = Executive::new(&mut state, &env_info, &machine);
let mut substate = Substate::new();
let mut output = H256::new();
if let Err(e) = ex.call(params, &mut substate, BytesRef::Fixed(&mut output), &mut NoopTracer, &mut NoopVMTracer) {

View File

@@ -14,82 +14,31 @@
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use std::collections::BTreeMap;
use std::sync::Arc;
use hash::keccak;
use ethkey::KeyPair;
use io::*;
use client::{BlockChainClient, Client, ClientConfig};
use bigint::prelude::U256;
use bigint::hash::H256;
use util::*;
use bytes::Bytes;
use spec::*;
use account_provider::AccountProvider;
use state_db::StateDB;
use bigint::hash::H256;
use bigint::prelude::U256;
use block::{OpenBlock, Drain};
use blockchain::{BlockChain, Config as BlockChainConfig};
use builtin::Builtin;
use state::*;
use evm::{Schedule, Factory as EvmFactory};
use factory::Factories;
use engines::Engine;
use ethereum;
use bytes::Bytes;
use client::{BlockChainClient, Client, ClientConfig};
use ethereum::ethash::EthashParams;
use miner::Miner;
use ethkey::KeyPair;
use evm::Factory as EvmFactory;
use factory::Factories;
use hash::keccak;
use header::Header;
use transaction::{Action, Transaction, SignedTransaction};
use io::*;
use machine::EthashExtensions;
use miner::Miner;
use rlp::{self, RlpStream};
use spec::*;
use state_db::StateDB;
use state::*;
use std::sync::Arc;
use transaction::{Action, Transaction, SignedTransaction};
use util::*;
use views::BlockView;
pub struct TestEngine {
engine: Arc<Engine>,
max_depth: usize,
}
impl TestEngine {
pub fn new(max_depth: usize) -> TestEngine {
TestEngine {
engine: ethereum::new_frontier_test().engine,
max_depth: max_depth,
}
}
pub fn new_byzantium() -> TestEngine {
TestEngine {
engine: ethereum::new_byzantium_test().engine,
max_depth: 0,
}
}
pub fn new_constantinople() -> TestEngine {
TestEngine {
engine: ethereum::new_constantinople_test().engine,
max_depth: 0,
}
}
}
impl Engine for TestEngine {
fn name(&self) -> &str {
"TestEngine"
}
fn params(&self) -> &CommonParams {
self.engine.params()
}
fn builtins(&self) -> &BTreeMap<Address, Builtin> {
self.engine.builtins()
}
fn schedule(&self, _block_number: u64) -> Schedule {
let mut schedule = self.engine.schedule(0);
schedule.max_depth = self.max_depth;
schedule
}
}
// TODO: move everything over to get_null_spec.
pub fn get_test_spec() -> Spec {
Spec::new_test()
@@ -233,9 +182,9 @@ pub fn generate_dummy_client_with_spec_accounts_and_data<F>(get_test_spec: F, ac
pub fn push_blocks_to_client(client: &Arc<Client>, timestamp_salt: u64, starting_number: usize, block_number: usize) {
let test_spec = get_test_spec();
let test_engine = &test_spec.engine;
//let test_engine = test_spec.to_engine().unwrap();
let state_root = test_spec.genesis_header().state_root().clone();
let genesis_gas = test_spec.genesis_header().gas_limit().clone();
let mut rolling_hash = client.chain_info().best_block_hash;
let mut rolling_block_number = starting_number as u64;
let mut rolling_timestamp = timestamp_salt + starting_number as u64 * 10;
@@ -243,7 +192,7 @@ pub fn push_blocks_to_client(client: &Arc<Client>, timestamp_salt: u64, starting
for _ in 0..block_number {
let mut header = Header::new();
header.set_gas_limit(test_engine.params().min_gas_limit);
header.set_gas_limit(genesis_gas);
header.set_difficulty(U256::from(0x20000));
header.set_timestamp(rolling_timestamp);
header.set_number(rolling_block_number);
@@ -272,9 +221,9 @@ pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> Arc<Client> {
IoChannel::disconnected(),
).unwrap();
for block in &blocks {
if client.import_block(block.clone()).is_err() {
panic!("panic importing block which is well-formed");
for block in blocks {
if let Err(e) = client.import_block(block) {
panic!("error importing block which is well-formed: {:?}", e);
}
}
client.flush_queue();
@@ -344,13 +293,13 @@ pub fn get_good_dummy_block_seq(count: usize) -> Vec<Bytes> {
pub fn get_good_dummy_block_fork_seq(start_number: usize, count: usize, parent_hash: &H256) -> Vec<Bytes> {
let test_spec = get_test_spec();
let test_engine = &test_spec.engine;
let genesis_gas = test_spec.genesis_header().gas_limit().clone();
let mut rolling_timestamp = start_number as u64 * 10;
let mut parent = *parent_hash;
let mut r = Vec::new();
for i in start_number .. start_number + count + 1 {
let mut block_header = Header::new();
block_header.set_gas_limit(test_engine.params().min_gas_limit);
block_header.set_gas_limit(genesis_gas);
block_header.set_difficulty(U256::from(i) * U256([0, 1, 0, 0]));
block_header.set_timestamp(rolling_timestamp);
block_header.set_number(i as u64);
@@ -368,8 +317,8 @@ pub fn get_good_dummy_block_fork_seq(start_number: usize, count: usize, parent_h
pub fn get_good_dummy_block_hash() -> (H256, Bytes) {
let mut block_header = Header::new();
let test_spec = get_test_spec();
let test_engine = &test_spec.engine;
block_header.set_gas_limit(test_engine.params().min_gas_limit);
let genesis_gas = test_spec.genesis_header().gas_limit().clone();
block_header.set_gas_limit(genesis_gas);
block_header.set_difficulty(U256::from(0x20000));
block_header.set_timestamp(40);
block_header.set_number(1);
@@ -387,8 +336,9 @@ pub fn get_good_dummy_block() -> Bytes {
pub fn get_bad_state_dummy_block() -> Bytes {
let mut block_header = Header::new();
let test_spec = get_test_spec();
let test_engine = &test_spec.engine;
block_header.set_gas_limit(test_engine.params().min_gas_limit);
let genesis_gas = test_spec.genesis_header().gas_limit().clone();
block_header.set_gas_limit(genesis_gas);
block_header.set_difficulty(U256::from(0x20000));
block_header.set_timestamp(40);
block_header.set_number(1);
@@ -398,33 +348,35 @@ pub fn get_bad_state_dummy_block() -> Bytes {
create_test_block(&block_header)
}
pub fn get_default_ethash_extensions() -> EthashExtensions {
EthashExtensions {
homestead_transition: 1150000,
eip150_transition: u64::max_value(),
eip160_transition: u64::max_value(),
eip161abc_transition: u64::max_value(),
eip161d_transition: u64::max_value(),
dao_hardfork_transition: u64::max_value(),
dao_hardfork_beneficiary: "0000000000000000000000000000000000000001".into(),
dao_hardfork_accounts: Vec::new(),
}
}
pub fn get_default_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,
dao_hardfork_transition: u64::max_value(),
dao_hardfork_beneficiary: "0000000000000000000000000000000000000001".into(),
dao_hardfork_accounts: vec![],
duration_limit: 13,
block_reward: 0.into(),
difficulty_hardfork_transition: u64::max_value(),
difficulty_hardfork_bound_divisor: U256::from(0),
bomb_defuse_transition: u64::max_value(),
eip100b_transition: u64::max_value(),
eip150_transition: u64::max_value(),
eip160_transition: u64::max_value(),
eip161abc_transition: u64::max_value(),
eip161d_transition: u64::max_value(),
ecip1010_pause_transition: u64::max_value(),
ecip1010_continue_transition: u64::max_value(),
ecip1017_era_rounds: u64::max_value(),
max_code_size: u64::max_value(),
max_gas_limit_transition: u64::max_value(),
max_gas_limit: U256::max_value(),
min_gas_price_transition: u64::max_value(),
min_gas_price: U256::zero(),
eip649_transition: u64::max_value(),
eip649_delay: 3_000_000,
eip649_reward: None,

View File

@@ -65,6 +65,8 @@ fn can_trace_block_and_uncle_reward() {
// block with transaction and uncle
let genesis_header = spec.genesis_header();
let genesis_gas = genesis_header.gas_limit().clone();
let mut db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
let mut rolling_timestamp = 40;
let mut last_hashes = vec![];
@@ -165,7 +167,7 @@ fn can_trace_block_and_uncle_reward() {
let uncle_author: Address = "ef2d6d194084c2de36e0dabfce45d046b37d1106".into();
uncle.set_author(uncle_author);
uncle.set_parent_hash(root_header.hash());
uncle.set_gas_limit(U256::from(50_000));
uncle.set_gas_limit(genesis_gas);
uncle.set_number(root_header.number() + 1);
uncle.set_timestamp(rolling_timestamp);
block.push_uncle(uncle).unwrap();