openethereum/ethcore/src/engines/mod.rs

435 lines
17 KiB
Rust
Raw Normal View History

// Copyright 2015-2017 Parity Technologies (UK) Ltd.
2016-02-05 13:40:41 +01:00
// This file is part of Parity.
// Parity 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 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. If not, see <http://www.gnu.org/licenses/>.
//! Consensus engine specification and basic implementations.
2016-09-08 12:12:24 +02:00
mod authority_round;
mod basic_authority;
mod instant_seal;
mod null_engine;
mod signer;
2016-08-23 12:58:40 +02:00
mod tendermint;
mod transition;
mod validator_set;
mod vote_collector;
pub mod epoch;
2016-09-08 12:12:24 +02:00
pub use self::authority_round::AuthorityRound;
pub use self::basic_authority::BasicAuthority;
pub use self::epoch::{EpochVerifier, Transition as EpochTransition};
pub use self::instant_seal::InstantSeal;
pub use self::null_engine::NullEngine;
2016-08-23 12:58:40 +02:00
pub use self::tendermint::Tendermint;
2016-05-16 18:16:56 +02:00
2017-07-29 21:56:42 +02:00
use std::sync::{Weak, Arc};
2017-07-29 17:12:07 +02:00
use std::collections::{BTreeMap, HashMap};
use std::fmt;
2017-04-11 17:07:04 +02:00
use self::epoch::PendingTransition;
use account_provider::AccountProvider;
use builtin::Builtin;
use vm::{EnvInfo, Schedule, CreateContractAddress};
use error::Error;
use header::{Header, BlockNumber};
2017-04-19 20:31:53 +02:00
use snapshot::SnapshotComponents;
use spec::CommonParams;
use transaction::{UnverifiedTransaction, SignedTransaction};
2017-04-11 17:07:04 +02:00
use ethkey::Signature;
use parity_machine::{Machine, LocalizedMachine as Localized};
2017-09-04 16:36:49 +02:00
use bigint::prelude::U256;
use bigint::hash::H256;
use semantic_version::SemanticVersion;
2017-04-11 17:07:04 +02:00
use util::*;
use unexpected::{Mismatch, OutOfBounds};
use bytes::Bytes;
/// Default EIP-210 contrat code.
/// As defined in https://github.com/ethereum/EIPs/pull/210
pub const DEFAULT_BLOCKHASH_CONTRACT: &'static str = "73fffffffffffffffffffffffffffffffffffffffe33141561006a5760014303600035610100820755610100810715156100455760003561010061010083050761010001555b6201000081071515610064576000356101006201000083050761020001555b5061013e565b4360003512151561008457600060405260206040f361013d565b61010060003543031315156100a857610100600035075460605260206060f361013c565b6101006000350715156100c55762010000600035430313156100c8565b60005b156100ea576101006101006000350507610100015460805260206080f361013b565b620100006000350715156101095763010000006000354303131561010c565b60005b1561012f57610100620100006000350507610200015460a052602060a0f361013a565b600060c052602060c0f35b5b5b5b5b";
2016-08-24 15:55:47 +02:00
/// Voting errors.
#[derive(Debug)]
pub enum EngineError {
/// Signature or author field does not belong to an authority.
2016-12-08 12:03:34 +01:00
NotAuthorized(Address),
2016-11-29 13:51:27 +01:00
/// The same author issued different votes at the same step.
2016-12-08 12:03:34 +01:00
DoubleVote(Address),
2016-11-29 13:51:27 +01:00
/// The received block is from an incorrect proposer.
2016-12-08 12:03:34 +01:00
NotProposer(Mismatch<Address>),
2016-08-24 15:55:47 +02:00
/// Message was not expected.
2016-08-26 19:27:50 +02:00
UnexpectedMessage,
2016-12-02 14:32:00 +01:00
/// Seal field has an unexpected size.
BadSealFieldSize(OutOfBounds<usize>),
2017-04-12 18:55:38 +02:00
/// Validation proof insufficient.
InsufficientProof(String),
/// Failed system call.
FailedSystemCall(String),
/// Malformed consensus message.
MalformedMessage(String),
/// Requires client ref, but none registered.
RequiresClient,
2016-11-29 13:51:27 +01:00
}
impl fmt::Display for EngineError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::EngineError::*;
let msg = match *self {
DoubleVote(ref address) => format!("Author {} issued too many blocks.", address),
NotProposer(ref mis) => format!("Author is not a current proposer: {}", mis),
NotAuthorized(ref address) => format!("Signer {} is not authorized.", address),
UnexpectedMessage => "This Engine should not be fed messages.".into(),
2016-12-02 14:32:00 +01:00
BadSealFieldSize(ref oob) => format!("Seal field has an unexpected length: {}", oob),
2017-04-12 18:55:38 +02:00
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"),
2016-11-29 13:51:27 +01:00
};
f.write_fmt(format_args!("Engine error ({})", msg))
}
2016-08-24 15:55:47 +02:00
}
2016-12-08 12:03:34 +01:00
/// Seal type.
#[derive(Debug, PartialEq, Eq)]
pub enum Seal {
/// Proposal seal; should be broadcasted, but not inserted into blockchain.
Proposal(Vec<Bytes>),
/// Regular block seal; should be part of the blockchain.
Regular(Vec<Bytes>),
/// Engine does generate seal for this block right now.
None,
}
/// Type alias for a function we can get headers by hash through.
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<M: Machine>: Send + Sync {
/// Generate a proof, given the state.
// 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, machine: &M, proof: &[u8]) -> Result<(), String>;
}
/// Proof generated on epoch change.
pub enum Proof<M: Machine> {
/// Known proof (extracted from signal)
Known(Vec<u8>),
/// State dependent proof.
WithState(Arc<StateDependentProof<M>>),
}
/// Generated epoch verifier.
pub enum ConstructedVerifier<'a, M: Machine> {
/// Fully trusted verifier.
Trusted(Box<EpochVerifier<M>>),
/// Verifier unconfirmed. Check whether given finality proof finalizes given hash
/// under previous epoch.
Unconfirmed(Box<EpochVerifier<M>>, &'a [u8], H256),
/// Error constructing verifier.
Err(Error),
}
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<M>>, Error> {
match self {
ConstructedVerifier::Trusted(v) | ConstructedVerifier::Unconfirmed(v, _, _) => Ok(v),
ConstructedVerifier::Err(e) => Err(e),
}
}
}
2017-04-11 17:07:04 +02:00
2017-04-18 14:19:10 +02:00
/// Results of a query of whether an epoch change occurred at the given block.
pub enum EpochChange<M: Machine> {
2017-04-12 14:41:19 +02:00
/// Cannot determine until more data is passed.
Unsure(M::AuxiliaryRequest),
2017-04-18 14:19:10 +02:00
/// No epoch change.
2017-04-12 14:41:19 +02:00
No,
/// The epoch will change, with proof.
Yes(Proof<M>),
2017-04-12 14:41:19 +02:00
}
/// 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<M: Machine>: Sync + Send {
/// The name of this engine.
fn name(&self) -> &str;
/// The version of this engine. Should be of the form
2015-12-20 16:12:53 +01:00
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.
2016-01-10 14:05:39 +01:00
fn seal_fields(&self) -> usize { 0 }
/// Additional engine-specific information for the user/developer concerning `header`.
fn extra_info(&self, _header: &M::Header) -> BTreeMap<String, String> { BTreeMap::new() }
/// Additional information.
fn additional_params(&self) -> HashMap<String, String> { HashMap::new() }
2016-02-02 23:43:29 +01:00
/// Maximum number of uncles a block is allowed to declare.
2016-01-10 14:05:39 +01:00
fn maximum_uncle_count(&self) -> usize { 2 }
/// The number of generations back that uncles can be.
fn maximum_uncle_age(&self) -> usize { 6 }
2016-02-02 23:43:29 +01:00
/// 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 M::LiveBlock,
_epoch_begin: bool,
) -> Result<(), M::Error> {
Ok(())
}
2016-02-02 23:43:29 +01:00
/// Block transformation functions, after the transactions.
fn on_close_block(&self, _block: &mut M::LiveBlock) -> Result<(), M::Error> {
2017-08-10 12:36:29 +02:00
Ok(())
}
2017-02-20 16:35:53 +01:00
/// None means that it requires external input (e.g. PoW) to seal a block.
/// 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.
///
/// 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 }
2015-12-20 16:12:53 +01:00
/// 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 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 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.
/// 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<'a>(&self, _header: &M::Header, _state: &<M as Localized<'a>>::StateContext) -> Result<Vec<u8>, String> { Ok(Vec::new()) }
2017-04-12 14:41:19 +02:00
/// 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 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.
///
2017-04-18 14:19:10 +02:00
/// Should not interact with state.
fn signals_epoch_end<'a>(&self, _header: &M::Header, _aux: <M as Localized<'a>>::AuxiliaryData)
-> EpochChange<M>
2017-04-12 14:41:19 +02:00
{
2017-04-18 14:19:10 +02:00
EpochChange::No
2017-04-11 17:07:04 +02:00
}
/// Whether a block is the end of an epoch.
///
/// This either means that an immediate transition occurs or a block signalling transition
/// has reached finality. The `Headers` given are not guaranteed to return any blocks
/// from any epoch other than the current.
///
/// Return optional transition proof.
fn is_epoch_end(
&self,
_chain_head: &M::Header,
_chain: &Headers<M::Header>,
_transition_store: &PendingTransitionStore,
) -> Option<Vec<u8>> {
None
}
/// Create an epoch verifier from validation proof and a flag indicating
/// whether finality is required.
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.
fn populate_from_parent(&self, _header: &mut M::Header, _parent: &M::Header) { }
2016-08-19 17:18:30 +02:00
/// Handle any potential consensus messages;
/// updating consensus state and potentially issuing a new one.
fn handle_message(&self, _message: &[u8]) -> Result<(), EngineError> { Err(EngineError::UnexpectedMessage) }
2015-12-23 12:56:38 +01:00
2016-12-08 12:03:34 +01:00
/// 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: &M::Header) -> bool { false }
2016-12-08 12:03:34 +01:00
2016-12-05 18:08:16 +01:00
/// Register an account which signs consensus messages.
fn set_signer(&self, _account_provider: Arc<AccountProvider>, _address: Address, _password: String) {}
2016-12-05 18:08:16 +01:00
/// 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, potentially querying the state and sending messages.
fn register_client(&self, _client: Weak<M::EngineClient>) {}
2016-12-06 19:23:15 +01:00
/// Trigger next step of the consensus engine.
fn step(&self) {}
/// Stops any services that the may hold the Engine and makes it safe to drop.
fn stop(&self) {}
2017-04-19 20:31:53 +02:00
/// Create a factory for building snapshot chunks and restoring from them.
/// Returning `None` indicates that this engine doesn't support snapshot creation.
fn snapshot_components(&self) -> Option<Box<SnapshotComponents>> {
None
}
2017-05-05 16:00:40 +02:00
/// Whether this engine supports warp sync.
fn supports_warp(&self) -> bool {
self.snapshot_components().is_some()
}
}
/// 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)
}
2017-05-05 16:00:40 +02:00
/// Returns new contract address generation scheme at given block number.
fn create_address_scheme(&self, number: BlockNumber) -> CreateContractAddress {
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()
2017-05-05 16:00:40 +02:00
}
}
// convenience wrappers for existing functions.
impl<T> EthEngine for T where T: Engine<::machine::EthereumMachine> { }
/// Common engine utilities
pub mod common {
use block::ExecutedBlock;
use error::Error;
use trace::{Tracer, ExecutiveTracer, RewardType};
use state::CleanupMode;
2017-09-04 16:36:49 +02:00
use bigint::prelude::U256;
/// Give reward and trace.
pub fn bestow_block_reward(block: &mut ExecutedBlock, reward: U256) -> Result<(), Error> {
2017-08-30 14:37:02 +02:00
let fields = block.fields_mut();
// Bestow 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(move |mut traces| {
2017-08-30 14:37:02 +02:00
let mut tracer = ExecutiveTracer::default();
tracer.trace_reward(block_author, reward, RewardType::Block);
2017-08-30 14:37:02 +02:00
traces.push(tracer.drain())
});
// Commit state so that we can actually figure out the state root.
if let Err(ref e) = res {
warn!("Encountered error on bestowing reward: {}", e);
}
res
}
}