Extract spec to own crate (#10978)
* Add client-traits crate Move the BlockInfo trait to new crate * New crate `machine` Contains code extracted from ethcore that defines `Machine`, `Externalities` and other execution related code. * Use new machine and client-traits crates in ethcore * Use new crates machine and client-traits instead of ethcore where appropriate * Fix tests * Don't re-export so many types from ethcore::client * Fixing more fallout from removing re-export * fix test * More fallout from not re-exporting types * Add some docs * cleanup * import the macro edition style * Tweak docs * Add missing import * remove unused ethabi_derive imports * Use latest ethabi-contract * Move many traits from ethcore/client/traits to client-traits crate Initial version of extracted Engine trait * Move snapshot related traits to the engine crate (eew) * Move a few snapshot related types to common_types Cleanup Executed as exported from machine crate * fix warning * Gradually introduce new engine crate: snapshot * ethcore typechecks with new engine crate * Sort out types outside ethcore * Add an EpochVerifier to ethash and use that in Engine.epoch_verifier() Cleanup * Document pub members * Sort out tests Sort out default impls for EpochVerifier * Add test-helpers feature and move EngineSigner impl to the right place * Sort out tests * Sort out tests and refactor verification types * Fix missing traits * More missing traits Fix Histogram * Fix tests and cleanup * cleanup * Put back needed logger import * Don't rexport common_types from ethcore/src/client Don't export ethcore::client::* * Remove files no longer used Use types from the engine crate Explicit exports from engine::engine * Get rid of itertools * Move a few more traits from ethcore to client-traits: BlockChainReset, ScheduleInfo, StateClient * Move ProvingBlockChainClient to client-traits * Don't re-export ForkChoice and Transition from ethcore * Address grumbles: sort imports, remove commented out code * Fix merge resolution error * Extract the Clique engine to own crate * Extract NullEngine and the block_reward module from ethcore * Extract InstantSeal engine to own crate * Extract remaining engines * Extract executive_state to own crate so it can be used by engine crates * Remove snapshot stuff from the engine crate * Put snapshot traits back in ethcore * cleanup * Remove stuff from ethcore * Don't use itertools * itertools in aura is legit-ish * More post-merge fixes * Re-export less types in client * cleanup * Extract spec to own crate * Put back the test-helpers from basic-authority * Fix ethcore benchmarks * Reduce the public api of ethcore/verification * Update ethcore/block-reward/Cargo.toml Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Update ethcore/engines/basic-authority/Cargo.toml Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Update ethcore/engines/ethash/Cargo.toml Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * Update ethcore/engines/clique/src/lib.rs Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * signers is already a ref * Add an EngineType enum to tighten up Engine.name() * Introduce Snapshotting enum to distinguish the type of snapshots a chain uses * Rename supports_warp to snapshot_mode * Missing import * Update ethcore/src/snapshot/consensus/mod.rs Co-Authored-By: Tomasz Drwięga <tomusdrw@users.noreply.github.com> * missing import * Fix import * double semi
This commit is contained in:
@@ -500,7 +500,7 @@ mod tests {
|
||||
verification::Unverified,
|
||||
};
|
||||
use hash_db::EMPTY_PREFIX;
|
||||
use crate::spec;
|
||||
use spec;
|
||||
|
||||
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
|
||||
fn enact_bytes(
|
||||
|
||||
@@ -58,6 +58,7 @@ use types::{
|
||||
client_types::Mode,
|
||||
blockchain_info::BlockChainInfo,
|
||||
block_status::BlockStatus,
|
||||
verification::VerificationQueueInfo as BlockQueueInfo,
|
||||
};
|
||||
use vm::{Schedule, LastHashes};
|
||||
|
||||
@@ -80,7 +81,6 @@ use spec::{Spec, self};
|
||||
use account_state::state::StateInfo;
|
||||
use state_db::StateDB;
|
||||
use trace::LocalizedTrace;
|
||||
use verification::queue::QueueInfo as BlockQueueInfo;
|
||||
|
||||
/// Test client.
|
||||
pub struct TestBlockChainClient {
|
||||
|
||||
@@ -39,7 +39,7 @@ use ethtrie;
|
||||
use rlp::RlpStream;
|
||||
use hash::keccak;
|
||||
use ethereum_types::BigEndianHash;
|
||||
use crate::spec;
|
||||
use spec;
|
||||
|
||||
use super::HookType;
|
||||
|
||||
|
||||
@@ -55,32 +55,23 @@
|
||||
|
||||
extern crate account_db;
|
||||
extern crate account_state;
|
||||
extern crate authority_round;
|
||||
extern crate ansi_term;
|
||||
extern crate basic_authority;
|
||||
extern crate client_traits;
|
||||
extern crate common_types as types;
|
||||
extern crate clique;
|
||||
extern crate crossbeam_utils;
|
||||
extern crate engine;
|
||||
extern crate ethabi;
|
||||
extern crate ethash;
|
||||
extern crate ethash_engine;
|
||||
extern crate ethcore_blockchain as blockchain;
|
||||
extern crate ethcore_bloom_journal as bloom_journal;
|
||||
extern crate ethcore_builtin as builtin;
|
||||
extern crate ethcore_call_contract as call_contract;
|
||||
extern crate ethcore_db as db;
|
||||
extern crate ethcore_io as io;
|
||||
extern crate ethcore_miner;
|
||||
extern crate ethereum_types;
|
||||
extern crate ethjson;
|
||||
extern crate ethkey;
|
||||
extern crate executive_state;
|
||||
extern crate trie_vm_factories;
|
||||
extern crate futures;
|
||||
extern crate hash_db;
|
||||
extern crate instant_seal;
|
||||
extern crate itertools;
|
||||
extern crate journaldb;
|
||||
extern crate keccak_hash as hash;
|
||||
@@ -92,12 +83,10 @@ extern crate kvdb_memorydb;
|
||||
extern crate len_caching_lock;
|
||||
extern crate machine;
|
||||
extern crate memory_cache;
|
||||
extern crate null_engine;
|
||||
extern crate num_cpus;
|
||||
extern crate parity_bytes as bytes;
|
||||
extern crate parity_snappy as snappy;
|
||||
extern crate parking_lot;
|
||||
extern crate pod;
|
||||
extern crate trie_db as trie;
|
||||
extern crate patricia_trie_ethereum as ethtrie;
|
||||
extern crate rand;
|
||||
@@ -108,6 +97,7 @@ extern crate parity_util_mem as malloc_size_of;
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
extern crate rustc_hex;
|
||||
extern crate serde;
|
||||
extern crate spec;
|
||||
extern crate state_db;
|
||||
extern crate time_utils;
|
||||
extern crate trace;
|
||||
@@ -122,6 +112,13 @@ extern crate rand_xorshift;
|
||||
extern crate ethcore_accounts as accounts;
|
||||
#[cfg(feature = "stratum")]
|
||||
extern crate ethcore_stratum;
|
||||
#[cfg(any(test, feature = "stratum"))]
|
||||
extern crate ethash;
|
||||
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
extern crate ethkey;
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
extern crate ethjson;
|
||||
#[cfg(any(test, feature = "tempdir"))]
|
||||
extern crate tempdir;
|
||||
#[cfg(any(test, feature = "kvdb-rocksdb"))]
|
||||
@@ -129,9 +126,13 @@ extern crate kvdb_rocksdb;
|
||||
#[cfg(any(test, feature = "json-tests"))]
|
||||
#[macro_use]
|
||||
extern crate lazy_static;
|
||||
#[cfg(any(test, feature = "json-tests", feature = "test-helpers", feature = "parity"))]
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
#[macro_use]
|
||||
extern crate macros;
|
||||
#[cfg(test)]
|
||||
extern crate null_engine;
|
||||
#[cfg(any(test, feature = "test-helpers"))]
|
||||
extern crate pod;
|
||||
#[cfg(any(test, feature = "blooms-db"))]
|
||||
extern crate blooms_db;
|
||||
#[cfg(any(test, feature = "env_logger"))]
|
||||
@@ -161,7 +162,6 @@ pub mod block;
|
||||
pub mod client;
|
||||
pub mod miner;
|
||||
pub mod snapshot;
|
||||
pub mod spec;
|
||||
pub mod verification;
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -1498,7 +1498,7 @@ mod tests {
|
||||
BlockNumber,
|
||||
transaction::Transaction
|
||||
};
|
||||
use crate::spec;
|
||||
use spec;
|
||||
|
||||
#[test]
|
||||
fn should_prepare_block_to_seal() {
|
||||
|
||||
@@ -907,7 +907,7 @@ impl Drop for Service {
|
||||
mod tests {
|
||||
use client::ClientIoMessage;
|
||||
use io::{IoService};
|
||||
use crate::spec;
|
||||
use spec;
|
||||
use journaldb::Algorithm;
|
||||
use snapshot::SnapshotService;
|
||||
use super::*;
|
||||
|
||||
@@ -33,7 +33,7 @@ use parking_lot::Mutex;
|
||||
use snappy;
|
||||
use kvdb::DBTransaction;
|
||||
use test_helpers;
|
||||
use crate::spec;
|
||||
use spec;
|
||||
|
||||
const SNAPSHOT_MODE: ::snapshot::PowSnapshot = ::snapshot::PowSnapshot { blocks: 30000, max_restore_blocks: 30000 };
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ use types::{
|
||||
use snapshot::io::{PackedReader, PackedWriter, SnapshotReader, SnapshotWriter};
|
||||
use snapshot::service::{Service, ServiceParams};
|
||||
use snapshot::{chunk_state, chunk_secondary, SnapshotService};
|
||||
use crate::spec;
|
||||
use spec;
|
||||
use test_helpers::{new_db, new_temp_db, generate_dummy_client_with_spec_and_data, restoration_db_handler};
|
||||
|
||||
use parking_lot::Mutex;
|
||||
|
||||
@@ -1,164 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Load chain specifications for all chains supported by the parity-ethereum client.
|
||||
|
||||
macro_rules! bundle_release_spec {
|
||||
($($path: expr => $name: ident), *) => {
|
||||
$(
|
||||
/// Bundled release spec
|
||||
pub fn $name<'a, T: Into<crate::spec::SpecParams<'a>>>(params: T) -> crate::spec::Spec {
|
||||
let params = params.into();
|
||||
crate::spec::Spec::load(
|
||||
params,
|
||||
include_bytes!(concat!("../../res/", $path, ".json")) as &[u8]
|
||||
).expect(concat!("Chain spec ", $path, " is invalid."))
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! bundle_test_spec {
|
||||
($($path: expr => $name: ident), *) => {
|
||||
$(
|
||||
/// Bundled test spec
|
||||
pub fn $name() -> crate::spec::Spec {
|
||||
crate::spec::Spec::load(
|
||||
&::std::env::temp_dir(),
|
||||
include_bytes!(concat!("../../res/", $path, ".json")) as &[u8]
|
||||
).expect(concat!("Chain spec ", $path, " is invalid."))
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! bundle_test_machine {
|
||||
($($path: expr => $name: ident), *) => {
|
||||
$(
|
||||
/// Bundled test spec
|
||||
pub fn $name() -> crate::machine::Machine {
|
||||
crate::spec::Spec::load_machine(
|
||||
include_bytes!(concat!("../../res/", $path, ".json")) as &[u8]
|
||||
).expect(concat!("Chain spec ", $path, " is invalid."))
|
||||
}
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
bundle_release_spec! {
|
||||
"ethereum/callisto" => new_callisto,
|
||||
"ethereum/classic" => new_classic,
|
||||
"ethereum/ellaism" => new_ellaism,
|
||||
"ethereum/expanse" => new_expanse,
|
||||
"ethereum/foundation" => new_foundation,
|
||||
"ethereum/goerli" => new_goerli,
|
||||
"ethereum/kotti" => new_kotti,
|
||||
"ethereum/kovan" => new_kovan,
|
||||
"ethereum/mix" => new_mix,
|
||||
"ethereum/morden" => new_morden,
|
||||
"ethereum/musicoin" => new_musicoin,
|
||||
"ethereum/poacore" => new_poanet,
|
||||
"ethereum/poasokol" => new_sokol,
|
||||
"ethereum/rinkeby" => new_rinkeby,
|
||||
"ethereum/ropsten" => new_ropsten,
|
||||
"ethereum/volta" => new_volta,
|
||||
"ethereum/ewc" => new_ewc
|
||||
}
|
||||
|
||||
bundle_test_spec! {
|
||||
"authority_round" => new_test_round,
|
||||
"authority_round_block_reward_contract" => new_test_round_block_reward_contract,
|
||||
"authority_round_empty_steps" => new_test_round_empty_steps,
|
||||
"constructor" => new_test_constructor,
|
||||
"ethereum/byzantium_test" => new_byzantium_test,
|
||||
"ethereum/constantinople_test" => new_constantinople_test,
|
||||
"ethereum/eip150_test" => new_eip150_test,
|
||||
"ethereum/eip161_test" => new_eip161_test,
|
||||
"ethereum/eip210_test" => new_eip210_test,
|
||||
"ethereum/frontier_like_test" => new_mainnet_like,
|
||||
"ethereum/frontier_test" => new_frontier_test,
|
||||
"ethereum/homestead_test" => new_homestead_test,
|
||||
"ethereum/kovan_wasm_test" => new_kovan_wasm_test,
|
||||
"ethereum/mcip3_test" => new_mcip3_test,
|
||||
"ethereum/morden" => new_morden_test,
|
||||
"ethereum/ropsten" => new_ropsten_test,
|
||||
"ethereum/st_peters_test" => new_constantinople_fix_test,
|
||||
"ethereum/transition_test" => new_transition_test,
|
||||
"instant_seal" => new_instant,
|
||||
"null" => new_null,
|
||||
"null_morden" => new_test,
|
||||
"null_morden_with_reward" => new_test_with_reward,
|
||||
"validator_contract" => new_validator_contract,
|
||||
"validator_multi" => new_validator_multi,
|
||||
"validator_safe_contract" => new_validator_safe_contract
|
||||
}
|
||||
|
||||
bundle_test_machine! {
|
||||
"ethereum/byzantium_test" => new_byzantium_test_machine,
|
||||
"ethereum/constantinople_test" => new_constantinople_test_machine,
|
||||
"ethereum/eip210_test" => new_eip210_test_machine,
|
||||
"ethereum/frontier_test" => new_frontier_test_machine,
|
||||
"ethereum/homestead_test" => new_homestead_test_machine,
|
||||
"ethereum/kovan_wasm_test" => new_kovan_wasm_test_machine,
|
||||
"null_morden" => new_test_machine
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use account_state::State;
|
||||
use ethereum_types::U256;
|
||||
use tempdir::TempDir;
|
||||
use test_helpers::get_temp_state_db;
|
||||
use types::{view, views::BlockView};
|
||||
|
||||
use super::{new_morden, new_foundation};
|
||||
|
||||
#[test]
|
||||
fn ensure_db_good() {
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
let spec = new_morden(&tempdir.path());
|
||||
let engine = &spec.engine;
|
||||
let genesis_header = spec.genesis_header();
|
||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default()).unwrap();
|
||||
let s = State::from_existing(db, genesis_header.state_root().clone(), engine.account_start_nonce(0), Default::default()).unwrap();
|
||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000001".parse().unwrap()).unwrap(), 1u64.into());
|
||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000002".parse().unwrap()).unwrap(), 1u64.into());
|
||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000003".parse().unwrap()).unwrap(), 1u64.into());
|
||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000004".parse().unwrap()).unwrap(), 1u64.into());
|
||||
assert_eq!(s.balance(&"102e61f5d8f9bc71d0ad4a084df4e65e05ce0e1c".parse().unwrap()).unwrap(), U256::from(1u64) << 200);
|
||||
assert_eq!(s.balance(&"0000000000000000000000000000000000000000".parse().unwrap()).unwrap(), 0u64.into());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn morden() {
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
let morden = new_morden(&tempdir.path());
|
||||
|
||||
assert_eq!(morden.state_root, "f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9".parse().unwrap());
|
||||
let genesis = morden.genesis_block();
|
||||
assert_eq!(view!(BlockView, &genesis).header_view().hash(), "0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303".parse().unwrap());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn frontier() {
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
let frontier = new_foundation(&tempdir.path());
|
||||
|
||||
assert_eq!(frontier.state_root, "d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544".parse().unwrap());
|
||||
let genesis = frontier.genesis_block();
|
||||
assert_eq!(view!(BlockView, &genesis).header_view().hash(), "d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3".parse().unwrap());
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
use ethereum_types::{H256, U256, Address};
|
||||
use ethjson;
|
||||
use hash::KECCAK_NULL_RLP;
|
||||
use spec::seal::Seal;
|
||||
|
||||
/// Genesis components.
|
||||
pub struct Genesis {
|
||||
/// Seal.
|
||||
pub seal: Seal,
|
||||
/// Difficulty.
|
||||
pub difficulty: U256,
|
||||
/// Author.
|
||||
pub author: Address,
|
||||
/// Timestamp.
|
||||
pub timestamp: u64,
|
||||
/// Parent hash.
|
||||
pub parent_hash: H256,
|
||||
/// Gas limit.
|
||||
pub gas_limit: U256,
|
||||
/// Transactions root.
|
||||
pub transactions_root: H256,
|
||||
/// Receipts root.
|
||||
pub receipts_root: H256,
|
||||
/// State root.
|
||||
pub state_root: Option<H256>,
|
||||
/// Gas used.
|
||||
pub gas_used: U256,
|
||||
/// Extra data.
|
||||
pub extra_data: Vec<u8>,
|
||||
}
|
||||
|
||||
impl From<ethjson::spec::Genesis> for Genesis {
|
||||
fn from(g: ethjson::spec::Genesis) -> Self {
|
||||
Genesis {
|
||||
seal: From::from(g.seal),
|
||||
difficulty: g.difficulty.into(),
|
||||
author: g.author.map_or_else(Address::zero, Into::into),
|
||||
timestamp: g.timestamp.map_or(0, Into::into),
|
||||
parent_hash: g.parent_hash.map_or_else(H256::zero, Into::into),
|
||||
gas_limit: g.gas_limit.into(),
|
||||
transactions_root: g.transactions_root.map_or_else(|| KECCAK_NULL_RLP.clone(), Into::into),
|
||||
receipts_root: g.receipts_root.map_or_else(|| KECCAK_NULL_RLP.clone(), Into::into),
|
||||
state_root: g.state_root.map(Into::into),
|
||||
gas_used: g.gas_used.map_or_else(U256::zero, Into::into),
|
||||
extra_data: g.extra_data.map_or_else(Vec::new, Into::into),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Blockchain params.
|
||||
|
||||
mod chain;
|
||||
mod genesis;
|
||||
mod seal;
|
||||
mod spec;
|
||||
|
||||
pub use self::chain::*;
|
||||
pub use self::genesis::Genesis;
|
||||
pub use self::spec::{Spec, SpecHardcodedSync, SpecParams, OptimizeFor};
|
||||
@@ -1,120 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Spec seal.
|
||||
|
||||
use rlp::RlpStream;
|
||||
use ethereum_types::{H64, H256, H520};
|
||||
use ethjson;
|
||||
|
||||
/// Classic ethereum seal.
|
||||
pub struct Ethereum {
|
||||
/// Seal nonce.
|
||||
pub nonce: H64,
|
||||
/// Seal mix hash.
|
||||
pub mix_hash: H256,
|
||||
}
|
||||
|
||||
impl Into<Generic> for Ethereum {
|
||||
fn into(self) -> Generic {
|
||||
let mut s = RlpStream::new_list(2);
|
||||
s.append(&self.mix_hash).append(&self.nonce);
|
||||
Generic(s.out())
|
||||
}
|
||||
}
|
||||
|
||||
/// AuthorityRound seal.
|
||||
pub struct AuthorityRound {
|
||||
/// Seal step.
|
||||
pub step: usize,
|
||||
/// Seal signature.
|
||||
pub signature: H520,
|
||||
}
|
||||
|
||||
/// Tendermint seal.
|
||||
pub struct Tendermint {
|
||||
/// Seal round.
|
||||
pub round: usize,
|
||||
/// Proposal seal signature.
|
||||
pub proposal: H520,
|
||||
/// Precommit seal signatures.
|
||||
pub precommits: Vec<H520>,
|
||||
}
|
||||
|
||||
impl Into<Generic> for AuthorityRound {
|
||||
fn into(self) -> Generic {
|
||||
let mut s = RlpStream::new_list(2);
|
||||
s.append(&self.step).append(&self.signature);
|
||||
Generic(s.out())
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Generic> for Tendermint {
|
||||
fn into(self) -> Generic {
|
||||
let mut stream = RlpStream::new_list(3);
|
||||
stream
|
||||
.append(&self.round)
|
||||
.append(&self.proposal)
|
||||
.append_list(&self.precommits);
|
||||
Generic(stream.out())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Generic(pub Vec<u8>);
|
||||
|
||||
/// Genesis seal type.
|
||||
pub enum Seal {
|
||||
/// Classic ethereum seal.
|
||||
Ethereum(Ethereum),
|
||||
/// AuthorityRound seal.
|
||||
AuthorityRound(AuthorityRound),
|
||||
/// Tendermint seal.
|
||||
Tendermint(Tendermint),
|
||||
/// Generic RLP seal.
|
||||
Generic(Generic),
|
||||
}
|
||||
|
||||
impl From<ethjson::spec::Seal> for Seal {
|
||||
fn from(s: ethjson::spec::Seal) -> Self {
|
||||
match s {
|
||||
ethjson::spec::Seal::Ethereum(eth) => Seal::Ethereum(Ethereum {
|
||||
nonce: eth.nonce.into(),
|
||||
mix_hash: eth.mix_hash.into()
|
||||
}),
|
||||
ethjson::spec::Seal::AuthorityRound(ar) => Seal::AuthorityRound(AuthorityRound {
|
||||
step: ar.step.into(),
|
||||
signature: ar.signature.into()
|
||||
}),
|
||||
ethjson::spec::Seal::Tendermint(tender) => Seal::Tendermint(Tendermint {
|
||||
round: tender.round.into(),
|
||||
proposal: tender.proposal.into(),
|
||||
precommits: tender.precommits.into_iter().map(Into::into).collect()
|
||||
}),
|
||||
ethjson::spec::Seal::Generic(g) => Seal::Generic(Generic(g.into())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<Generic> for Seal {
|
||||
fn into(self) -> Generic {
|
||||
match self {
|
||||
Seal::Generic(generic) => generic,
|
||||
Seal::Ethereum(eth) => eth.into(),
|
||||
Seal::AuthorityRound(ar) => ar.into(),
|
||||
Seal::Tendermint(tender) => tender.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,596 +0,0 @@
|
||||
// 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/>.
|
||||
|
||||
//! Parameters for a block chain.
|
||||
|
||||
use std::{
|
||||
collections::BTreeMap,
|
||||
fmt,
|
||||
io::Read,
|
||||
path::Path,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use bytes::Bytes;
|
||||
use ethereum_types::{H256, Bloom, U256, Address};
|
||||
use ethjson;
|
||||
use hash::{KECCAK_NULL_RLP, keccak};
|
||||
use rlp::{Rlp, RlpStream};
|
||||
use types::{
|
||||
BlockNumber,
|
||||
header::Header,
|
||||
encoded,
|
||||
engines::params::CommonParams,
|
||||
errors::EthcoreError as Error,
|
||||
};
|
||||
use vm::{EnvInfo, CallType, ActionValue, ActionParams, ParamsType};
|
||||
|
||||
use builtin::Builtin;
|
||||
use engine::Engine;
|
||||
use clique::Clique;
|
||||
use null_engine::NullEngine;
|
||||
use instant_seal::{InstantSeal, InstantSealParams};
|
||||
use authority_round::AuthorityRound;
|
||||
use basic_authority::BasicAuthority;
|
||||
use ethash_engine::Ethash;
|
||||
use machine::{
|
||||
executive::Executive,
|
||||
machine::Machine,
|
||||
substate::Substate,
|
||||
};
|
||||
use trie_vm_factories::Factories;
|
||||
use pod::PodState;
|
||||
use spec::Genesis;
|
||||
use spec::seal::Generic as GenericSeal;
|
||||
use account_state::{Backend, State, backend::Basic as BasicBackend};
|
||||
use trace::{NoopTracer, NoopVMTracer};
|
||||
|
||||
pub use ethash::OptimizeFor;
|
||||
|
||||
/// Runtime parameters for the spec that are related to how the software should run the chain,
|
||||
/// rather than integral properties of the chain itself.
|
||||
pub struct SpecParams<'a> {
|
||||
/// The path to the folder used to cache nodes. This is typically /tmp/ on Unix-like systems
|
||||
pub cache_dir: &'a Path,
|
||||
/// Whether to run slower at the expense of better memory usage, or run faster while using
|
||||
/// more
|
||||
/// memory. This may get more fine-grained in the future but for now is simply a binary
|
||||
/// option.
|
||||
pub optimization_setting: Option<OptimizeFor>,
|
||||
}
|
||||
|
||||
impl<'a> SpecParams<'a> {
|
||||
/// Create from a cache path, with null values for the other fields
|
||||
pub fn from_path(path: &'a Path) -> Self {
|
||||
SpecParams {
|
||||
cache_dir: path,
|
||||
optimization_setting: None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create from a cache path and an optimization setting
|
||||
pub fn new(path: &'a Path, optimization: OptimizeFor) -> Self {
|
||||
SpecParams {
|
||||
cache_dir: path,
|
||||
optimization_setting: Some(optimization),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: AsRef<Path>> From<&'a T> for SpecParams<'a> {
|
||||
fn from(path: &'a T) -> Self {
|
||||
Self::from_path(path.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
/// given a pre-constructor state, run all the given constructors and produce a new state and
|
||||
/// state root.
|
||||
fn run_constructors<T: Backend>(
|
||||
genesis_state: &PodState,
|
||||
constructors: &[(Address, Bytes)],
|
||||
engine: &dyn Engine,
|
||||
author: Address,
|
||||
timestamp: u64,
|
||||
difficulty: U256,
|
||||
factories: &Factories,
|
||||
mut db: T
|
||||
) -> Result<(H256, T), Error> {
|
||||
let mut root = KECCAK_NULL_RLP;
|
||||
|
||||
// basic accounts in spec.
|
||||
{
|
||||
let mut t = factories.trie.create(db.as_hash_db_mut(), &mut root);
|
||||
|
||||
for (address, account) in genesis_state.get().iter() {
|
||||
t.insert(address.as_bytes(), &account.rlp())?;
|
||||
}
|
||||
}
|
||||
|
||||
for (address, account) in genesis_state.get().iter() {
|
||||
db.note_non_null_account(address);
|
||||
account.insert_additional(
|
||||
&mut *factories.accountdb.create(
|
||||
db.as_hash_db_mut(),
|
||||
keccak(address),
|
||||
),
|
||||
&factories.trie,
|
||||
);
|
||||
}
|
||||
|
||||
let start_nonce = engine.account_start_nonce(0);
|
||||
|
||||
let mut state = State::from_existing(db, root, start_nonce, factories.clone())?;
|
||||
|
||||
// Execute contract constructors.
|
||||
let env_info = EnvInfo {
|
||||
number: 0,
|
||||
author,
|
||||
timestamp,
|
||||
difficulty,
|
||||
last_hashes: Default::default(),
|
||||
gas_used: U256::zero(),
|
||||
gas_limit: U256::max_value(),
|
||||
};
|
||||
|
||||
let from = Address::zero();
|
||||
for &(ref address, ref constructor) in constructors.iter() {
|
||||
trace!(target: "spec", "run_constructors: Creating a contract at {}.", address);
|
||||
trace!(target: "spec", " .. root before = {}", state.root());
|
||||
let params = ActionParams {
|
||||
code_address: address.clone(),
|
||||
code_hash: Some(keccak(constructor)),
|
||||
code_version: U256::zero(),
|
||||
address: address.clone(),
|
||||
sender: from.clone(),
|
||||
origin: from.clone(),
|
||||
gas: U256::max_value(),
|
||||
gas_price: Default::default(),
|
||||
value: ActionValue::Transfer(Default::default()),
|
||||
code: Some(Arc::new(constructor.clone())),
|
||||
data: None,
|
||||
call_type: CallType::None,
|
||||
params_type: ParamsType::Embedded,
|
||||
};
|
||||
|
||||
let mut substate = Substate::new();
|
||||
|
||||
{
|
||||
let machine = engine.machine();
|
||||
let schedule = machine.schedule(env_info.number);
|
||||
let mut exec = Executive::new(&mut state, &env_info, &machine, &schedule);
|
||||
// failing create is not a bug
|
||||
if let Err(e) = exec.create(params, &mut substate, &mut NoopTracer, &mut NoopVMTracer) {
|
||||
warn!(target: "spec", "Genesis constructor execution at {} failed: {}.", address, e);
|
||||
}
|
||||
}
|
||||
|
||||
let _ = state.commit()?;
|
||||
}
|
||||
|
||||
Ok(state.drop())
|
||||
}
|
||||
|
||||
/// Parameters for a block chain; includes both those intrinsic to the design of the
|
||||
/// chain and those to be interpreted by the active chain engine.
|
||||
pub struct Spec {
|
||||
/// User friendly spec name.
|
||||
pub name: String,
|
||||
/// Engine specified by json file.
|
||||
pub engine: Arc<dyn Engine>,
|
||||
/// Name of the subdir inside the main data dir to use for chain data and settings.
|
||||
pub data_dir: String,
|
||||
/// Known nodes on the network in enode format.
|
||||
pub nodes: Vec<String>,
|
||||
/// The genesis block's parent hash field.
|
||||
pub parent_hash: H256,
|
||||
/// The genesis block's author field.
|
||||
pub author: Address,
|
||||
/// The genesis block's difficulty field.
|
||||
pub difficulty: U256,
|
||||
/// The genesis block's gas limit field.
|
||||
pub gas_limit: U256,
|
||||
/// The genesis block's gas used field.
|
||||
pub gas_used: U256,
|
||||
/// The genesis block's timestamp field.
|
||||
pub timestamp: u64,
|
||||
/// Transactions root of the genesis block. Should be KECCAK_NULL_RLP.
|
||||
pub transactions_root: H256,
|
||||
/// Receipts root of the genesis block. Should be KECCAK_NULL_RLP.
|
||||
pub receipts_root: H256,
|
||||
/// The genesis block's extra data field.
|
||||
pub extra_data: Bytes,
|
||||
/// Each seal field, expressed as RLP, concatenated.
|
||||
pub seal_rlp: Bytes,
|
||||
/// Hardcoded synchronization. Allows the light client to immediately jump to a specific block.
|
||||
pub hardcoded_sync: Option<SpecHardcodedSync>,
|
||||
/// Contract constructors to be executed on genesis.
|
||||
pub constructors: Vec<(Address, Bytes)>,
|
||||
/// May be prepopulated if we know this in advance.
|
||||
pub state_root: H256,
|
||||
/// Genesis state as plain old data.
|
||||
pub genesis_state: PodState,
|
||||
}
|
||||
|
||||
/// Part of `Spec`. Describes the hardcoded synchronization parameters.
|
||||
pub struct SpecHardcodedSync {
|
||||
/// Header of the block to jump to for hardcoded sync, and total difficulty.
|
||||
pub header: encoded::Header,
|
||||
/// Total difficulty of the block to jump to.
|
||||
pub total_difficulty: U256,
|
||||
/// List of hardcoded CHTs, in order. If `hardcoded_sync` is set, the CHTs should include the
|
||||
/// header of `hardcoded_sync`.
|
||||
pub chts: Vec<H256>,
|
||||
}
|
||||
|
||||
impl From<ethjson::spec::HardcodedSync> for SpecHardcodedSync {
|
||||
fn from(sync: ethjson::spec::HardcodedSync) -> Self {
|
||||
SpecHardcodedSync {
|
||||
header: encoded::Header::new(sync.header.into()),
|
||||
total_difficulty: sync.total_difficulty.into(),
|
||||
chts: sync.chts.into_iter().map(Into::into).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for SpecHardcodedSync {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
writeln!(f, "{{")?;
|
||||
writeln!(f, r#"header": "{:?},"#, self.header)?;
|
||||
writeln!(f, r#"total_difficulty": "{:?},"#, self.total_difficulty)?;
|
||||
writeln!(f, r#"chts": {:#?}"#, self.chts.iter().map(|x| format!(r#"{}"#, x)).collect::<Vec<_>>())?;
|
||||
writeln!(f, "}}")
|
||||
}
|
||||
}
|
||||
|
||||
/// Load from JSON object.
|
||||
fn load_from(spec_params: SpecParams, s: ethjson::spec::Spec) -> Result<Spec, Error> {
|
||||
let builtins = s.accounts
|
||||
.builtins()
|
||||
.into_iter()
|
||||
.map(|p| (p.0.into(), From::from(p.1)))
|
||||
.collect();
|
||||
let g = Genesis::from(s.genesis);
|
||||
let GenericSeal(seal_rlp) = g.seal.into();
|
||||
let params = CommonParams::from(s.params);
|
||||
|
||||
let hardcoded_sync = s.hardcoded_sync.map(Into::into);
|
||||
|
||||
let engine = Spec::engine(spec_params, s.engine, params, builtins);
|
||||
let author = g.author;
|
||||
let timestamp = g.timestamp;
|
||||
let difficulty = g.difficulty;
|
||||
let constructors: Vec<_> = s.accounts
|
||||
.constructors()
|
||||
.into_iter()
|
||||
.map(|(a, c)| (a.into(), c.into()))
|
||||
.collect();
|
||||
let genesis_state: PodState = s.accounts.into();
|
||||
|
||||
let (state_root, _) = run_constructors(
|
||||
&genesis_state,
|
||||
&constructors,
|
||||
&*engine,
|
||||
author,
|
||||
timestamp,
|
||||
difficulty,
|
||||
&Default::default(),
|
||||
BasicBackend(journaldb::new_memory_db()),
|
||||
)?;
|
||||
|
||||
let s = Spec {
|
||||
engine,
|
||||
name: s.name.clone().into(),
|
||||
data_dir: s.data_dir.unwrap_or(s.name).into(),
|
||||
nodes: s.nodes.unwrap_or_else(Vec::new),
|
||||
parent_hash: g.parent_hash,
|
||||
transactions_root: g.transactions_root,
|
||||
receipts_root: g.receipts_root,
|
||||
author,
|
||||
difficulty,
|
||||
gas_limit: g.gas_limit,
|
||||
gas_used: g.gas_used,
|
||||
timestamp,
|
||||
extra_data: g.extra_data,
|
||||
seal_rlp,
|
||||
hardcoded_sync,
|
||||
constructors,
|
||||
genesis_state,
|
||||
state_root,
|
||||
};
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
impl Spec {
|
||||
// create an instance of an Ethereum state machine, minus consensus logic.
|
||||
fn machine(
|
||||
engine_spec: ðjson::spec::Engine,
|
||||
params: CommonParams,
|
||||
builtins: BTreeMap<Address, Builtin>,
|
||||
) -> Machine {
|
||||
if let ethjson::spec::Engine::Ethash(ref ethash) = *engine_spec {
|
||||
Machine::with_ethash_extensions(params, builtins, ethash.params.clone().into())
|
||||
} else {
|
||||
Machine::regular(params, builtins)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert engine spec into a arc'd Engine of the right underlying type.
|
||||
/// TODO avoid this hard-coded nastiness - use dynamic-linked plugin framework instead.
|
||||
fn engine(
|
||||
spec_params: SpecParams,
|
||||
engine_spec: ethjson::spec::Engine,
|
||||
params: CommonParams,
|
||||
builtins: BTreeMap<Address, Builtin>,
|
||||
) -> Arc<dyn Engine> {
|
||||
let machine = Self::machine(&engine_spec, params, builtins);
|
||||
|
||||
match engine_spec {
|
||||
ethjson::spec::Engine::Null(null) => Arc::new(NullEngine::new(null.params.into(), machine)),
|
||||
ethjson::spec::Engine::Ethash(ethash) => Arc::new(Ethash::new(spec_params.cache_dir, ethash.params.into(), machine, spec_params.optimization_setting)),
|
||||
ethjson::spec::Engine::InstantSeal(Some(instant_seal)) => Arc::new(InstantSeal::new(instant_seal.params.into(), machine)),
|
||||
ethjson::spec::Engine::InstantSeal(None) => Arc::new(InstantSeal::new(InstantSealParams::default(), machine)),
|
||||
ethjson::spec::Engine::BasicAuthority(basic_authority) => Arc::new(BasicAuthority::new(basic_authority.params.into(), machine)),
|
||||
ethjson::spec::Engine::Clique(clique) => Clique::new(clique.params.into(), machine)
|
||||
.expect("Failed to start Clique consensus engine."),
|
||||
ethjson::spec::Engine::AuthorityRound(authority_round) => AuthorityRound::new(authority_round.params.into(), machine)
|
||||
.expect("Failed to start AuthorityRound consensus engine."),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get common blockchain parameters.
|
||||
pub fn params(&self) -> &CommonParams {
|
||||
&self.engine.params()
|
||||
}
|
||||
|
||||
/// Get the configured Network ID.
|
||||
pub fn network_id(&self) -> u64 {
|
||||
self.params().network_id
|
||||
}
|
||||
|
||||
/// Get the chain ID used for signing.
|
||||
pub fn chain_id(&self) -> u64 {
|
||||
self.params().chain_id
|
||||
}
|
||||
|
||||
/// Get the configured subprotocol name.
|
||||
pub fn subprotocol_name(&self) -> String {
|
||||
self.params().subprotocol_name.clone()
|
||||
}
|
||||
|
||||
/// Get the configured network fork block.
|
||||
pub fn fork_block(&self) -> Option<(BlockNumber, H256)> {
|
||||
self.params().fork_block
|
||||
}
|
||||
|
||||
/// Get the header of the genesis block.
|
||||
pub fn genesis_header(&self) -> Header {
|
||||
let mut header: Header = Default::default();
|
||||
header.set_parent_hash(self.parent_hash.clone());
|
||||
header.set_timestamp(self.timestamp);
|
||||
header.set_number(0);
|
||||
header.set_author(self.author.clone());
|
||||
header.set_transactions_root(self.transactions_root.clone());
|
||||
header.set_uncles_hash(keccak(RlpStream::new_list(0).out()));
|
||||
header.set_extra_data(self.extra_data.clone());
|
||||
header.set_state_root(self.state_root);
|
||||
header.set_receipts_root(self.receipts_root.clone());
|
||||
header.set_log_bloom(Bloom::default());
|
||||
header.set_gas_used(self.gas_used.clone());
|
||||
header.set_gas_limit(self.gas_limit.clone());
|
||||
header.set_difficulty(self.difficulty.clone());
|
||||
header.set_seal({
|
||||
let r = Rlp::new(&self.seal_rlp);
|
||||
r.iter().map(|f| f.as_raw().to_vec()).collect()
|
||||
});
|
||||
trace!(target: "spec", "Header hash is {}", header.hash());
|
||||
header
|
||||
}
|
||||
|
||||
/// Compose the genesis block for this chain.
|
||||
pub fn genesis_block(&self) -> Bytes {
|
||||
let empty_list = RlpStream::new_list(0).out();
|
||||
let header = self.genesis_header();
|
||||
let mut ret = RlpStream::new_list(3);
|
||||
ret.append(&header);
|
||||
ret.append_raw(&empty_list, 1);
|
||||
ret.append_raw(&empty_list, 1);
|
||||
ret.out()
|
||||
}
|
||||
|
||||
/// Overwrite the genesis components.
|
||||
pub fn overwrite_genesis_params(&mut self, g: Genesis) {
|
||||
let GenericSeal(seal_rlp) = g.seal.into();
|
||||
self.parent_hash = g.parent_hash;
|
||||
self.transactions_root = g.transactions_root;
|
||||
self.receipts_root = g.receipts_root;
|
||||
self.author = g.author;
|
||||
self.difficulty = g.difficulty;
|
||||
self.gas_limit = g.gas_limit;
|
||||
self.gas_used = g.gas_used;
|
||||
self.timestamp = g.timestamp;
|
||||
self.extra_data = g.extra_data;
|
||||
self.seal_rlp = seal_rlp;
|
||||
}
|
||||
|
||||
/// Alter the value of the genesis state.
|
||||
pub fn set_genesis_state(&mut self, s: PodState) -> Result<(), Error> {
|
||||
self.genesis_state = s;
|
||||
let (root, _) = run_constructors(
|
||||
&self.genesis_state,
|
||||
&self.constructors,
|
||||
&*self.engine,
|
||||
self.author,
|
||||
self.timestamp,
|
||||
self.difficulty,
|
||||
&Default::default(),
|
||||
BasicBackend(journaldb::new_memory_db()),
|
||||
)?;
|
||||
|
||||
self.state_root = root;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Ensure that the given state DB has the trie nodes in for the genesis state.
|
||||
pub fn ensure_db_good<T: Backend>(&self, db: T, factories: &Factories) -> Result<T, Error> {
|
||||
if db.as_hash_db().contains(&self.state_root, hash_db::EMPTY_PREFIX) {
|
||||
return Ok(db);
|
||||
}
|
||||
|
||||
// TODO: could optimize so we don't re-run, but `ensure_db_good` is barely ever
|
||||
// called anyway.
|
||||
let (root, db) = run_constructors(
|
||||
&self.genesis_state,
|
||||
&self.constructors,
|
||||
&*self.engine,
|
||||
self.author,
|
||||
self.timestamp,
|
||||
self.difficulty,
|
||||
factories,
|
||||
db
|
||||
)?;
|
||||
|
||||
assert_eq!(root, self.state_root, "Spec's state root has not been precomputed correctly.");
|
||||
Ok(db)
|
||||
}
|
||||
|
||||
/// Loads just the state machine from a json file.
|
||||
pub fn load_machine<R: Read>(reader: R) -> Result<Machine, Error> {
|
||||
ethjson::spec::Spec::load(reader)
|
||||
.map_err(|e| Error::Msg(e.to_string()))
|
||||
.map(|s| {
|
||||
let builtins = s.accounts.builtins().into_iter().map(|p| (p.0.into(), From::from(p.1))).collect();
|
||||
let params = CommonParams::from(s.params);
|
||||
Spec::machine(&s.engine, params, builtins)
|
||||
})
|
||||
}
|
||||
|
||||
/// Loads spec from json file. Provide factories for executing contracts and ensuring
|
||||
/// storage goes to the right place.
|
||||
pub fn load<'a, T: Into<SpecParams<'a>>, R: Read>(params: T, reader: R) -> Result<Self, Error> {
|
||||
ethjson::spec::Spec::load(reader)
|
||||
.map_err(|e| Error::Msg(e.to_string()))
|
||||
.and_then(|x| load_from(params.into(), x))
|
||||
}
|
||||
|
||||
/// initialize genesis epoch data, using in-memory database for
|
||||
/// constructor.
|
||||
pub fn genesis_epoch_data(&self) -> Result<Vec<u8>, String> {
|
||||
use types::transaction::{Action, Transaction};
|
||||
|
||||
let genesis = self.genesis_header();
|
||||
|
||||
let factories = Default::default();
|
||||
let mut db = journaldb::new(
|
||||
Arc::new(kvdb_memorydb::create(0)),
|
||||
journaldb::Algorithm::Archive,
|
||||
None,
|
||||
);
|
||||
|
||||
self.ensure_db_good(BasicBackend(db.as_hash_db_mut()), &factories)
|
||||
.map_err(|e| format!("Unable to initialize genesis state: {}", e))?;
|
||||
|
||||
let call = |a, d| {
|
||||
let mut db = db.boxed_clone();
|
||||
let env_info = ::evm::EnvInfo {
|
||||
number: 0,
|
||||
author: *genesis.author(),
|
||||
timestamp: genesis.timestamp(),
|
||||
difficulty: *genesis.difficulty(),
|
||||
gas_limit: U256::max_value(),
|
||||
last_hashes: Arc::new(Vec::new()),
|
||||
gas_used: 0.into(),
|
||||
};
|
||||
|
||||
let from = Address::zero();
|
||||
let tx = Transaction {
|
||||
nonce: self.engine.account_start_nonce(0),
|
||||
action: Action::Call(a),
|
||||
gas: U256::max_value(),
|
||||
gas_price: U256::default(),
|
||||
value: U256::default(),
|
||||
data: d,
|
||||
}.fake_sign(from);
|
||||
|
||||
let res = ::executive_state::prove_transaction_virtual(
|
||||
db.as_hash_db_mut(),
|
||||
*genesis.state_root(),
|
||||
&tx,
|
||||
self.engine.machine(),
|
||||
&env_info,
|
||||
factories.clone(),
|
||||
);
|
||||
|
||||
res.map(|(out, proof)| {
|
||||
(out, proof.into_iter().map(|x| x.into_vec()).collect())
|
||||
}).ok_or_else(|| "Failed to prove call: insufficient state".into())
|
||||
};
|
||||
|
||||
self.engine.genesis_epoch_data(&genesis, &call)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use account_state::State;
|
||||
use test_helpers::get_temp_state_db;
|
||||
use tempdir::TempDir;
|
||||
use types::view;
|
||||
use types::views::BlockView;
|
||||
use std::str::FromStr;
|
||||
use crate::spec;
|
||||
|
||||
#[test]
|
||||
fn test_load_empty() {
|
||||
let tempdir = TempDir::new("").unwrap();
|
||||
assert!(Spec::load(&tempdir.path(), &[] as &[u8]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_chain() {
|
||||
let test_spec = spec::new_test();
|
||||
|
||||
assert_eq!(
|
||||
test_spec.state_root,
|
||||
H256::from_str("f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9").unwrap()
|
||||
);
|
||||
let genesis = test_spec.genesis_block();
|
||||
assert_eq!(
|
||||
view!(BlockView, &genesis).header_view().hash(),
|
||||
H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn genesis_constructor() {
|
||||
let _ = ::env_logger::try_init();
|
||||
let spec = spec::new_test_constructor();
|
||||
let db = spec.ensure_db_good(get_temp_state_db(), &Default::default())
|
||||
.unwrap();
|
||||
let state = State::from_existing(
|
||||
db.boxed_clone(),
|
||||
spec.state_root,
|
||||
spec.engine.account_start_nonce(0),
|
||||
Default::default(),
|
||||
).unwrap();
|
||||
let expected = H256::from_str("0000000000000000000000000000000000000000000000000000000000000001").unwrap();
|
||||
let address = Address::from_str("0000000000000000000000000000000000001337").unwrap();
|
||||
|
||||
assert_eq!(state.storage_at(&address, &H256::zero()).unwrap(), expected);
|
||||
assert_eq!(state.balance(&address).unwrap(), 1.into());
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ use types::{
|
||||
|
||||
use client::{Client, ClientConfig, PrepareOpenBlock, ImportSealedBlock};
|
||||
use client_traits::{BlockInfo, BlockChainClient, BlockChainReset, ChainInfo, ImportBlock};
|
||||
use crate::spec;
|
||||
use spec;
|
||||
use machine::executive::{Executive, TransactOptions};
|
||||
use miner::{Miner, PendingOrdering, MinerService};
|
||||
use account_state::{State, CleanupMode, backend};
|
||||
|
||||
@@ -21,7 +21,7 @@ use hash::keccak;
|
||||
use block::*;
|
||||
use ethereum_types::{U256, Address};
|
||||
use io::*;
|
||||
use crate::spec;
|
||||
use spec;
|
||||
use test_helpers::get_temp_state_db;
|
||||
use client::{Client, ClientConfig};
|
||||
use client_traits::{BlockChainClient, ImportBlock};
|
||||
|
||||
@@ -16,20 +16,26 @@
|
||||
|
||||
//! Block verification utilities.
|
||||
|
||||
use call_contract::CallContract;
|
||||
use client_traits::BlockInfo;
|
||||
|
||||
mod verification;
|
||||
mod verifier;
|
||||
pub mod queue;
|
||||
mod canon_verifier;
|
||||
mod noop_verifier;
|
||||
|
||||
pub use self::verification::*;
|
||||
pub use self::verification::FullFamilyParams;
|
||||
pub use self::verifier::Verifier;
|
||||
pub use self::canon_verifier::CanonVerifier;
|
||||
pub use self::noop_verifier::NoopVerifier;
|
||||
pub use self::queue::{BlockQueue, Config as QueueConfig, VerificationQueue, QueueInfo};
|
||||
pub use self::queue::{BlockQueue, Config as QueueConfig};
|
||||
|
||||
use call_contract::CallContract;
|
||||
use client_traits::BlockInfo;
|
||||
use self::verification::{
|
||||
verify_block_basic,
|
||||
verify_block_unordered,
|
||||
verify_header_params,
|
||||
};
|
||||
use self::canon_verifier::CanonVerifier;
|
||||
use self::noop_verifier::NoopVerifier;
|
||||
|
||||
/// Verifier type.
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
|
||||
@@ -29,12 +29,13 @@ use io::*;
|
||||
use engine::Engine;
|
||||
use client::ClientIoMessage;
|
||||
use len_caching_lock::LenCachingMutex;
|
||||
use types::errors::{BlockError, EthcoreError as Error, ImportError};
|
||||
use types::{
|
||||
errors::{BlockError, EthcoreError as Error, ImportError},
|
||||
verification::VerificationQueueInfo as QueueInfo,
|
||||
};
|
||||
|
||||
use self::kind::{BlockLike, Kind};
|
||||
|
||||
pub use types::verification::VerificationQueueInfo as QueueInfo;
|
||||
|
||||
pub mod kind;
|
||||
|
||||
const MIN_MEM_LIMIT: usize = 16384;
|
||||
@@ -743,7 +744,7 @@ mod tests {
|
||||
view,
|
||||
views::BlockView,
|
||||
};
|
||||
use crate::spec;
|
||||
use spec;
|
||||
|
||||
// create a test block queue.
|
||||
// auto_scaling enables verifier adjustment.
|
||||
|
||||
@@ -372,7 +372,7 @@ mod tests {
|
||||
use hash::keccak;
|
||||
use engine::Engine;
|
||||
use ethkey::{Random, Generator};
|
||||
use crate::spec;
|
||||
use spec;
|
||||
use test_helpers::{create_test_block_with_data, create_test_block};
|
||||
use types::{
|
||||
encoded,
|
||||
|
||||
Reference in New Issue
Block a user