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:
committed by
Gav Wood
parent
d8af9f4e7b
commit
bc167a211b
@@ -42,18 +42,16 @@ use std::fmt;
|
||||
use self::epoch::PendingTransition;
|
||||
|
||||
use account_provider::AccountProvider;
|
||||
use block::ExecutedBlock;
|
||||
use builtin::Builtin;
|
||||
use client::EngineClient;
|
||||
use vm::{EnvInfo, LastHashes, Schedule, CreateContractAddress};
|
||||
use vm::{EnvInfo, Schedule, CreateContractAddress};
|
||||
use error::Error;
|
||||
use header::{Header, BlockNumber};
|
||||
use receipt::Receipt;
|
||||
use snapshot::SnapshotComponents;
|
||||
use spec::CommonParams;
|
||||
use transaction::{UnverifiedTransaction, SignedTransaction};
|
||||
|
||||
use ethkey::Signature;
|
||||
use parity_machine::{Machine, LocalizedMachine as Localized};
|
||||
use bigint::prelude::U256;
|
||||
use bigint::hash::H256;
|
||||
use semantic_version::SemanticVersion;
|
||||
@@ -82,6 +80,8 @@ pub enum EngineError {
|
||||
InsufficientProof(String),
|
||||
/// Failed system call.
|
||||
FailedSystemCall(String),
|
||||
/// Malformed consensus message.
|
||||
MalformedMessage(String),
|
||||
/// Requires client ref, but none registered.
|
||||
RequiresClient,
|
||||
}
|
||||
@@ -97,6 +97,7 @@ impl fmt::Display for EngineError {
|
||||
BadSealFieldSize(ref oob) => format!("Seal field has an unexpected length: {}", oob),
|
||||
InsufficientProof(ref msg) => format!("Insufficient validation proof: {}", msg),
|
||||
FailedSystemCall(ref msg) => format!("Failed to make system call: {}", msg),
|
||||
MalformedMessage(ref msg) => format!("Received malformed consensus message: {}", msg),
|
||||
RequiresClient => format!("Call requires client but none registered"),
|
||||
};
|
||||
|
||||
@@ -115,49 +116,46 @@ pub enum Seal {
|
||||
None,
|
||||
}
|
||||
|
||||
/// Type alias for a function we can make calls through synchronously.
|
||||
/// Returns the call result and state proof for each call.
|
||||
pub type Call<'a> = Fn(Address, Bytes) -> Result<(Bytes, Vec<Vec<u8>>), String> + 'a;
|
||||
|
||||
/// Type alias for a function we can get headers by hash through.
|
||||
pub type Headers<'a> = Fn(H256) -> Option<Header> + 'a;
|
||||
pub type Headers<'a, H> = Fn(H256) -> Option<H> + 'a;
|
||||
|
||||
/// Type alias for a function we can query pending transitions by block hash through.
|
||||
pub type PendingTransitionStore<'a> = Fn(H256) -> Option<PendingTransition> + 'a;
|
||||
|
||||
/// Proof dependent on state.
|
||||
pub trait StateDependentProof: Send + Sync {
|
||||
pub trait StateDependentProof<M: Machine>: Send + Sync {
|
||||
/// Generate a proof, given the state.
|
||||
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String>;
|
||||
// TODO: make this into an &M::StateContext
|
||||
fn generate_proof<'a>(&self, state: &<M as Localized<'a>>::StateContext) -> Result<Vec<u8>, String>;
|
||||
/// Check a proof generated elsewhere (potentially by a peer).
|
||||
// `engine` needed to check state proofs, while really this should
|
||||
// just be state machine params.
|
||||
fn check_proof(&self, engine: &Engine, proof: &[u8]) -> Result<(), String>;
|
||||
fn check_proof(&self, machine: &M, proof: &[u8]) -> Result<(), String>;
|
||||
}
|
||||
|
||||
/// Proof generated on epoch change.
|
||||
pub enum Proof {
|
||||
pub enum Proof<M: Machine> {
|
||||
/// Known proof (extracted from signal)
|
||||
Known(Vec<u8>),
|
||||
/// State dependent proof.
|
||||
WithState(Arc<StateDependentProof>),
|
||||
WithState(Arc<StateDependentProof<M>>),
|
||||
}
|
||||
|
||||
/// Generated epoch verifier.
|
||||
pub enum ConstructedVerifier<'a> {
|
||||
pub enum ConstructedVerifier<'a, M: Machine> {
|
||||
/// Fully trusted verifier.
|
||||
Trusted(Box<EpochVerifier>),
|
||||
Trusted(Box<EpochVerifier<M>>),
|
||||
/// Verifier unconfirmed. Check whether given finality proof finalizes given hash
|
||||
/// under previous epoch.
|
||||
Unconfirmed(Box<EpochVerifier>, &'a [u8], H256),
|
||||
Unconfirmed(Box<EpochVerifier<M>>, &'a [u8], H256),
|
||||
/// Error constructing verifier.
|
||||
Err(Error),
|
||||
}
|
||||
|
||||
impl<'a> ConstructedVerifier<'a> {
|
||||
impl<'a, M: Machine> ConstructedVerifier<'a, M> {
|
||||
/// Convert to a result, indicating that any necessary confirmation has been done
|
||||
/// already.
|
||||
pub fn known_confirmed(self) -> Result<Box<EpochVerifier>, Error> {
|
||||
pub fn known_confirmed(self) -> Result<Box<EpochVerifier<M>>, Error> {
|
||||
match self {
|
||||
ConstructedVerifier::Trusted(v) | ConstructedVerifier::Unconfirmed(v, _, _) => Ok(v),
|
||||
ConstructedVerifier::Err(e) => Err(e),
|
||||
@@ -166,84 +164,53 @@ impl<'a> ConstructedVerifier<'a> {
|
||||
}
|
||||
|
||||
/// Results of a query of whether an epoch change occurred at the given block.
|
||||
pub enum EpochChange {
|
||||
pub enum EpochChange<M: Machine> {
|
||||
/// Cannot determine until more data is passed.
|
||||
Unsure(Unsure),
|
||||
Unsure(M::AuxiliaryRequest),
|
||||
/// No epoch change.
|
||||
No,
|
||||
/// The epoch will change, with proof.
|
||||
Yes(Proof),
|
||||
}
|
||||
|
||||
/// More data required to determine if an epoch change occurred at a given block.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Unsure {
|
||||
/// Needs the body.
|
||||
NeedsBody,
|
||||
/// Needs the receipts.
|
||||
NeedsReceipts,
|
||||
/// Needs both body and receipts.
|
||||
NeedsBoth,
|
||||
Yes(Proof<M>),
|
||||
}
|
||||
|
||||
/// A consensus mechanism for the chain. Generally either proof-of-work or proof-of-stake-based.
|
||||
/// Provides hooks into each of the major parts of block import.
|
||||
pub trait Engine : Sync + Send {
|
||||
pub trait Engine<M: Machine>: Sync + Send {
|
||||
/// The name of this engine.
|
||||
fn name(&self) -> &str;
|
||||
/// The version of this engine. Should be of the form
|
||||
fn version(&self) -> SemanticVersion { SemanticVersion::new(0, 0, 0) }
|
||||
|
||||
/// Get access to the underlying state machine.
|
||||
// TODO: decouple.
|
||||
fn machine(&self) -> &M;
|
||||
|
||||
/// The number of additional header fields required for this engine.
|
||||
fn seal_fields(&self) -> usize { 0 }
|
||||
|
||||
/// Additional engine-specific information for the user/developer concerning `header`.
|
||||
fn extra_info(&self, _header: &Header) -> BTreeMap<String, String> { BTreeMap::new() }
|
||||
fn extra_info(&self, _header: &M::Header) -> BTreeMap<String, String> { BTreeMap::new() }
|
||||
|
||||
/// Additional information.
|
||||
fn additional_params(&self) -> HashMap<String, String> { HashMap::new() }
|
||||
|
||||
/// Get the general parameters of the chain.
|
||||
fn params(&self) -> &CommonParams;
|
||||
|
||||
/// Get the EVM schedule for the given `block_number`.
|
||||
fn schedule(&self, block_number: BlockNumber) -> Schedule {
|
||||
self.params().schedule(block_number)
|
||||
}
|
||||
|
||||
/// Builtin-contracts we would like to see in the chain.
|
||||
/// (In principle these are just hints for the engine since that has the last word on them.)
|
||||
fn builtins(&self) -> &BTreeMap<Address, Builtin>;
|
||||
|
||||
/// Some intrinsic operation parameters; by default they take their value from the `spec()`'s `engine_params`.
|
||||
fn maximum_extra_data_size(&self) -> usize { self.params().maximum_extra_data_size }
|
||||
/// Maximum number of uncles a block is allowed to declare.
|
||||
fn maximum_uncle_count(&self) -> usize { 2 }
|
||||
/// The number of generations back that uncles can be.
|
||||
fn maximum_uncle_age(&self) -> usize { 6 }
|
||||
/// The nonce with which accounts begin at given block.
|
||||
fn account_start_nonce(&self, block: u64) -> U256 {
|
||||
if block >= self.params().dust_protection_transition {
|
||||
U256::from(self.params().nonce_cap_increment) * U256::from(block)
|
||||
} else {
|
||||
self.params().account_start_nonce
|
||||
}
|
||||
}
|
||||
|
||||
/// Block transformation functions, before the transactions.
|
||||
/// `epoch_begin` set to true if this block kicks off an epoch.
|
||||
fn on_new_block(
|
||||
&self,
|
||||
block: &mut ExecutedBlock,
|
||||
last_hashes: Arc<LastHashes>,
|
||||
_block: &mut M::LiveBlock,
|
||||
_epoch_begin: bool,
|
||||
) -> Result<(), Error> {
|
||||
let parent_hash = block.fields().header.parent_hash().clone();
|
||||
common::push_last_hash(block, last_hashes, self, &parent_hash)
|
||||
) -> Result<(), M::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Block transformation functions, after the transactions.
|
||||
fn on_close_block(&self, _block: &mut ExecutedBlock) -> Result<(), Error> {
|
||||
fn on_close_block(&self, _block: &mut M::LiveBlock) -> Result<(), M::Error> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -251,68 +218,57 @@ pub trait Engine : Sync + Send {
|
||||
/// Some(true) means the engine is currently prime for seal generation (i.e. node is the current validator).
|
||||
/// Some(false) means that the node might seal internally but is not qualified now.
|
||||
fn seals_internally(&self) -> Option<bool> { None }
|
||||
|
||||
/// Attempt to seal the block internally.
|
||||
///
|
||||
/// If `Some` is returned, then you get a valid seal.
|
||||
///
|
||||
/// This operation is synchronous and may (quite reasonably) not be available, in which None will
|
||||
/// be returned.
|
||||
fn generate_seal(&self, _block: &ExecutedBlock) -> Seal { Seal::None }
|
||||
///
|
||||
/// It is fine to require access to state or a full client for this function, since
|
||||
/// light clients do not generate seals.
|
||||
fn generate_seal(&self, _block: &M::LiveBlock) -> Seal { Seal::None }
|
||||
|
||||
/// Phase 1 quick block verification. Only does checks that are cheap. `block` (the header's full block)
|
||||
/// may be provided for additional checks. Returns either a null `Ok` or a general error detailing the problem with import.
|
||||
fn verify_block_basic(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { Ok(()) }
|
||||
/// Verify a locally-generated seal of a header.
|
||||
///
|
||||
/// If this engine seals internally,
|
||||
/// no checks have to be done here, since all internally generated seals
|
||||
/// should be valid.
|
||||
///
|
||||
/// Externally-generated seals (e.g. PoW) will need to be checked for validity.
|
||||
///
|
||||
/// It is fine to require access to state or a full client for this function, since
|
||||
/// light clients do not generate seals.
|
||||
fn verify_local_seal(&self, header: &M::Header) -> Result<(), M::Error>;
|
||||
|
||||
/// Phase 2 verification. Perform costly checks such as transaction signatures. `block` (the header's full block)
|
||||
/// may be provided for additional checks. Returns either a null `Ok` or a general error detailing the problem with import.
|
||||
fn verify_block_unordered(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { Ok(()) }
|
||||
/// Phase 1 quick block verification. Only does checks that are cheap. Returns either a null `Ok` or a general error detailing the problem with import.
|
||||
fn verify_block_basic(&self, _header: &M::Header) -> Result<(), M::Error> { Ok(()) }
|
||||
|
||||
/// Phase 3 verification. Check block information against parent and uncles. `block` (the header's full block)
|
||||
/// may be provided for additional checks. Returns either a null `Ok` or a general error detailing the problem with import.
|
||||
fn verify_block_family(&self, _header: &Header, _parent: &Header, _block: Option<&[u8]>) -> Result<(), Error> { Ok(()) }
|
||||
/// Phase 2 verification. Perform costly checks such as transaction signatures. Returns either a null `Ok` or a general error detailing the problem with import.
|
||||
fn verify_block_unordered(&self, _header: &M::Header) -> Result<(), M::Error> { Ok(()) }
|
||||
|
||||
/// Phase 3 verification. Check block information against parent. Returns either a null `Ok` or a general error detailing the problem with import.
|
||||
fn verify_block_family(&self, _header: &M::Header, _parent: &M::Header) -> Result<(), Error> { Ok(()) }
|
||||
|
||||
/// Phase 4 verification. Verify block header against potentially external data.
|
||||
fn verify_block_external(&self, _header: &Header, _block: Option<&[u8]>) -> Result<(), Error> { Ok(()) }
|
||||
|
||||
/// Additional verification for transactions in blocks.
|
||||
// TODO: Add flags for which bits of the transaction to check.
|
||||
// TODO: consider including State in the params.
|
||||
fn verify_transaction_basic(&self, t: &UnverifiedTransaction, _header: &Header) -> Result<(), Error> {
|
||||
t.verify_basic(true, Some(self.params().chain_id), true)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Verify a particular transaction is valid.
|
||||
fn verify_transaction(&self, t: UnverifiedTransaction, _header: &Header) -> Result<SignedTransaction, Error> {
|
||||
SignedTransaction::new(t)
|
||||
}
|
||||
|
||||
/// The network ID that transactions should be signed with.
|
||||
fn signing_chain_id(&self, _env_info: &EnvInfo) -> Option<u64> {
|
||||
Some(self.params().chain_id)
|
||||
}
|
||||
|
||||
/// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods
|
||||
/// to get the job done. By default it must pass `verify_basic` and `verify_block_unordered`. If more or fewer
|
||||
/// methods are needed for an Engine, this may be overridden.
|
||||
fn verify_block_seal(&self, header: &Header) -> Result<(), Error> {
|
||||
self.verify_block_basic(header, None).and_then(|_| self.verify_block_unordered(header, None))
|
||||
}
|
||||
/// Should only be called when `register_client` has been called previously.
|
||||
fn verify_block_external(&self, _header: &M::Header) -> Result<(), Error> { Ok(()) }
|
||||
|
||||
/// Genesis epoch data.
|
||||
fn genesis_epoch_data(&self, _header: &Header, _call: &Call) -> Result<Vec<u8>, String> { Ok(Vec::new()) }
|
||||
fn genesis_epoch_data<'a>(&self, _header: &M::Header, _state: &<M as Localized<'a>>::StateContext) -> Result<Vec<u8>, String> { Ok(Vec::new()) }
|
||||
|
||||
/// Whether an epoch change is signalled at the given header but will require finality.
|
||||
/// If a change can be enacted immediately then return `No` from this function but
|
||||
/// `Yes` from `is_epoch_end`.
|
||||
///
|
||||
/// If the block or receipts are required, return `Unsure` and the function will be
|
||||
/// If auxiliary data of the block is required, return an auxiliary request and the function will be
|
||||
/// called again with them.
|
||||
/// Return `Yes` or `No` when the answer is definitively known.
|
||||
///
|
||||
/// Should not interact with state.
|
||||
fn signals_epoch_end(&self, _header: &Header, _block: Option<&[u8]>, _receipts: Option<&[Receipt]>)
|
||||
-> EpochChange
|
||||
fn signals_epoch_end<'a>(&self, _header: &M::Header, _aux: <M as Localized<'a>>::AuxiliaryData)
|
||||
-> EpochChange<M>
|
||||
{
|
||||
EpochChange::No
|
||||
}
|
||||
@@ -326,8 +282,8 @@ pub trait Engine : Sync + Send {
|
||||
/// Return optional transition proof.
|
||||
fn is_epoch_end(
|
||||
&self,
|
||||
_chain_head: &Header,
|
||||
_chain: &Headers,
|
||||
_chain_head: &M::Header,
|
||||
_chain: &Headers<M::Header>,
|
||||
_transition_store: &PendingTransitionStore,
|
||||
) -> Option<Vec<u8>> {
|
||||
None
|
||||
@@ -335,35 +291,21 @@ pub trait Engine : Sync + Send {
|
||||
|
||||
/// Create an epoch verifier from validation proof and a flag indicating
|
||||
/// whether finality is required.
|
||||
fn epoch_verifier<'a>(&self, _header: &Header, _proof: &'a [u8]) -> ConstructedVerifier<'a> {
|
||||
fn epoch_verifier<'a>(&self, _header: &M::Header, _proof: &'a [u8]) -> ConstructedVerifier<'a, M> {
|
||||
ConstructedVerifier::Trusted(Box::new(self::epoch::NoOp))
|
||||
}
|
||||
|
||||
/// Populate a header's fields based on its parent's header.
|
||||
/// Usually implements the chain scoring rule based on weight.
|
||||
/// The gas floor target must not be lower than the engine's minimum gas limit.
|
||||
fn populate_from_parent(&self, header: &mut Header, parent: &Header, _gas_floor_target: U256, _gas_ceil_target: U256) {
|
||||
header.set_difficulty(parent.difficulty().clone());
|
||||
header.set_gas_limit(parent.gas_limit().clone());
|
||||
}
|
||||
fn populate_from_parent(&self, _header: &mut M::Header, _parent: &M::Header) { }
|
||||
|
||||
/// Handle any potential consensus messages;
|
||||
/// updating consensus state and potentially issuing a new one.
|
||||
fn handle_message(&self, _message: &[u8]) -> Result<(), Error> { Err(EngineError::UnexpectedMessage.into()) }
|
||||
|
||||
/// Attempt to get a handle to a built-in contract.
|
||||
/// Only returns references to activated built-ins.
|
||||
// TODO: builtin contract routing - to do this properly, it will require removing the built-in configuration-reading logic
|
||||
// from Spec into here and removing the Spec::builtins field.
|
||||
fn builtin(&self, a: &Address, block_number: ::header::BlockNumber) -> Option<&Builtin> {
|
||||
self.builtins()
|
||||
.get(a)
|
||||
.and_then(|b| if b.is_active(block_number) { Some(b) } else { None })
|
||||
}
|
||||
fn handle_message(&self, _message: &[u8]) -> Result<(), EngineError> { Err(EngineError::UnexpectedMessage) }
|
||||
|
||||
/// Find out if the block is a proposal block and should not be inserted into the DB.
|
||||
/// Takes a header of a fully verified block.
|
||||
fn is_proposal(&self, _verified_header: &Header) -> bool { false }
|
||||
fn is_proposal(&self, _verified_header: &M::Header) -> bool { false }
|
||||
|
||||
/// Register an account which signs consensus messages.
|
||||
fn set_signer(&self, _account_provider: Arc<AccountProvider>, _address: Address, _password: String) {}
|
||||
@@ -371,8 +313,8 @@ pub trait Engine : Sync + Send {
|
||||
/// Sign using the EngineSigner, to be used for consensus tx signing.
|
||||
fn sign(&self, _hash: H256) -> Result<Signature, Error> { unimplemented!() }
|
||||
|
||||
/// Add Client which can be used for sealing, querying the state and sending messages.
|
||||
fn register_client(&self, _client: Weak<EngineClient>) {}
|
||||
/// Add Client which can be used for sealing, potentially querying the state and sending messages.
|
||||
fn register_client(&self, _client: Weak<M::EngineClient>) {}
|
||||
|
||||
/// Trigger next step of the consensus engine.
|
||||
fn step(&self) {}
|
||||
@@ -390,118 +332,96 @@ pub trait Engine : Sync + Send {
|
||||
fn supports_warp(&self) -> bool {
|
||||
self.snapshot_components().is_some()
|
||||
}
|
||||
}
|
||||
|
||||
/// If this engine supports wasm contracts.
|
||||
fn supports_wasm(&self) -> bool {
|
||||
self.params().wasm
|
||||
/// Common type alias for an engine coupled with an Ethereum-like state machine.
|
||||
// TODO: make this a _trait_ alias when those exist.
|
||||
// fortunately the effect is largely the same since engines are mostly used
|
||||
// via trait objects.
|
||||
pub trait EthEngine: Engine<::machine::EthereumMachine> {
|
||||
/// Get the general parameters of the chain.
|
||||
fn params(&self) -> &CommonParams {
|
||||
self.machine().params()
|
||||
}
|
||||
|
||||
/// Get the EVM schedule for the given block number.
|
||||
fn schedule(&self, block_number: BlockNumber) -> Schedule {
|
||||
self.machine().schedule(block_number)
|
||||
}
|
||||
|
||||
/// Builtin-contracts for the chain..
|
||||
fn builtins(&self) -> &BTreeMap<Address, Builtin> {
|
||||
self.machine().builtins()
|
||||
}
|
||||
|
||||
/// Attempt to get a handle to a built-in contract.
|
||||
/// Only returns references to activated built-ins.
|
||||
fn builtin(&self, a: &Address, block_number: BlockNumber) -> Option<&Builtin> {
|
||||
self.machine().builtin(a, block_number)
|
||||
}
|
||||
|
||||
/// Some intrinsic operation parameters; by default they take their value from the `spec()`'s `engine_params`.
|
||||
fn maximum_extra_data_size(&self) -> usize {
|
||||
self.machine().maximum_extra_data_size()
|
||||
}
|
||||
|
||||
/// The nonce with which accounts begin at given block.
|
||||
fn account_start_nonce(&self, block: u64) -> U256 {
|
||||
self.machine().account_start_nonce(block)
|
||||
}
|
||||
|
||||
/// The network ID that transactions should be signed with.
|
||||
fn signing_chain_id(&self, env_info: &EnvInfo) -> Option<u64> {
|
||||
self.machine().signing_chain_id(env_info)
|
||||
}
|
||||
|
||||
/// Returns new contract address generation scheme at given block number.
|
||||
fn create_address_scheme(&self, number: BlockNumber) -> CreateContractAddress {
|
||||
if number >= self.params().eip86_transition {
|
||||
CreateContractAddress::FromCodeHash
|
||||
} else {
|
||||
CreateContractAddress::FromSenderAndNonce
|
||||
}
|
||||
self.machine().create_address_scheme(number)
|
||||
}
|
||||
|
||||
/// Verify a particular transaction is valid.
|
||||
fn verify_transaction_unordered(&self, t: UnverifiedTransaction, header: &Header) -> Result<SignedTransaction, Error> {
|
||||
self.machine().verify_transaction_unordered(t, header)
|
||||
}
|
||||
|
||||
/// Additional verification for transactions in blocks.
|
||||
// TODO: Add flags for which bits of the transaction to check.
|
||||
// TODO: consider including State in the params.
|
||||
fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> Result<(), Error> {
|
||||
self.machine().verify_transaction_basic(t, header)
|
||||
}
|
||||
|
||||
/// If this machine supports wasm.
|
||||
fn supports_wasm(&self) -> bool {
|
||||
self.machine().supports_wasm()
|
||||
}
|
||||
}
|
||||
|
||||
// convenience wrappers for existing functions.
|
||||
impl<T> EthEngine for T where T: Engine<::machine::EthereumMachine> { }
|
||||
|
||||
/// Common engine utilities
|
||||
pub mod common {
|
||||
use std::sync::Arc;
|
||||
use block::ExecutedBlock;
|
||||
use error::Error;
|
||||
use transaction::SYSTEM_ADDRESS;
|
||||
use executive::Executive;
|
||||
use vm::{CallType, ActionParams, ActionValue, EnvInfo, LastHashes};
|
||||
use trace::{NoopTracer, NoopVMTracer, Tracer, ExecutiveTracer, RewardType};
|
||||
use state::Substate;
|
||||
use trace::{Tracer, ExecutiveTracer, RewardType};
|
||||
use state::CleanupMode;
|
||||
|
||||
use bigint::prelude::U256;
|
||||
use bigint::hash::H256;
|
||||
use util::*;
|
||||
use bytes::{Bytes, BytesRef};
|
||||
use super::Engine;
|
||||
|
||||
/// Execute a call as the system address.
|
||||
pub fn execute_as_system<E: Engine + ?Sized>(
|
||||
block: &mut ExecutedBlock,
|
||||
last_hashes: Arc<LastHashes>,
|
||||
engine: &E,
|
||||
contract_address: Address,
|
||||
gas: U256,
|
||||
data: Option<Bytes>,
|
||||
) -> Result<Bytes, Error> {
|
||||
let env_info = {
|
||||
let header = block.fields().header;
|
||||
EnvInfo {
|
||||
number: header.number(),
|
||||
author: header.author().clone(),
|
||||
timestamp: header.timestamp(),
|
||||
difficulty: header.difficulty().clone(),
|
||||
last_hashes: last_hashes,
|
||||
gas_used: U256::zero(),
|
||||
gas_limit: gas,
|
||||
}
|
||||
};
|
||||
|
||||
let mut state = block.fields_mut().state;
|
||||
let params = ActionParams {
|
||||
code_address: contract_address.clone(),
|
||||
address: contract_address.clone(),
|
||||
sender: SYSTEM_ADDRESS.clone(),
|
||||
origin: SYSTEM_ADDRESS.clone(),
|
||||
gas: gas,
|
||||
gas_price: 0.into(),
|
||||
value: ActionValue::Transfer(0.into()),
|
||||
code: state.code(&contract_address)?,
|
||||
code_hash: Some(state.code_hash(&contract_address)?),
|
||||
data: data,
|
||||
call_type: CallType::Call,
|
||||
};
|
||||
let mut ex = Executive::new(&mut state, &env_info, engine);
|
||||
let mut substate = Substate::new();
|
||||
let mut output = Vec::new();
|
||||
if let Err(e) = ex.call(params, &mut substate, BytesRef::Flexible(&mut output), &mut NoopTracer, &mut NoopVMTracer) {
|
||||
warn!("Encountered error on making system call: {}", e);
|
||||
}
|
||||
|
||||
Ok(output)
|
||||
}
|
||||
|
||||
/// Push last known block hash to the state.
|
||||
pub fn push_last_hash<E: Engine + ?Sized>(block: &mut ExecutedBlock, last_hashes: Arc<LastHashes>, engine: &E, hash: &H256) -> Result<(), Error> {
|
||||
if block.fields().header.number() == engine.params().eip210_transition {
|
||||
let state = block.fields_mut().state;
|
||||
state.init_code(&engine.params().eip210_contract_address, engine.params().eip210_contract_code.clone())?;
|
||||
}
|
||||
if block.fields().header.number() >= engine.params().eip210_transition {
|
||||
let _ = execute_as_system(
|
||||
block,
|
||||
last_hashes,
|
||||
engine,
|
||||
engine.params().eip210_contract_address,
|
||||
engine.params().eip210_contract_gas,
|
||||
Some(hash.to_vec()),
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Trace rewards on closing block
|
||||
pub fn bestow_block_reward<E: Engine + ?Sized>(block: &mut ExecutedBlock, engine: &E) -> Result<(), Error> {
|
||||
/// Give reward and trace.
|
||||
pub fn bestow_block_reward(block: &mut ExecutedBlock, reward: U256) -> Result<(), Error> {
|
||||
let fields = block.fields_mut();
|
||||
// Bestow block reward
|
||||
let reward = engine.params().block_reward;
|
||||
let res = fields.state.add_balance(fields.header.author(), &reward, CleanupMode::NoEmpty)
|
||||
.map_err(::error::Error::from)
|
||||
.and_then(|_| fields.state.commit());
|
||||
|
||||
let block_author = fields.header.author().clone();
|
||||
fields.traces.as_mut().map(|mut traces| {
|
||||
fields.traces.as_mut().map(move |mut traces| {
|
||||
let mut tracer = ExecutiveTracer::default();
|
||||
tracer.trace_reward(block_author, engine.params().block_reward, RewardType::Block);
|
||||
tracer.trace_reward(block_author, reward, RewardType::Block);
|
||||
traces.push(tracer.drain())
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user