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
@@ -31,7 +31,7 @@ use unexpected::{Mismatch, OutOfBounds};
|
||||
|
||||
use basic_types::{LogBloom, Seal};
|
||||
use vm::{EnvInfo, LastHashes};
|
||||
use engines::Engine;
|
||||
use engines::EthEngine;
|
||||
use error::{Error, BlockError, TransactionError};
|
||||
use factory::Factories;
|
||||
use header::Header;
|
||||
@@ -97,6 +97,7 @@ pub struct ExecutedBlock {
|
||||
transactions_set: HashSet<H256>,
|
||||
state: State<StateDB>,
|
||||
traces: Option<Vec<Vec<FlatTrace>>>,
|
||||
last_hashes: Arc<LastHashes>,
|
||||
}
|
||||
|
||||
/// A set of references to `ExecutedBlock` fields that are publicly accessible.
|
||||
@@ -115,6 +116,17 @@ pub struct BlockRefMut<'a> {
|
||||
pub traces: &'a mut Option<Vec<Vec<FlatTrace>>>,
|
||||
}
|
||||
|
||||
impl<'a> BlockRefMut<'a> {
|
||||
/// Add traces if tracing is enabled.
|
||||
pub fn push_traces(&mut self, tracer: ::trace::ExecutiveTracer) {
|
||||
use trace::Tracer;
|
||||
|
||||
if let Some(ref mut traces) = self.traces.as_mut() {
|
||||
traces.push(tracer.drain())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A set of immutable references to `ExecutedBlock` fields that are publicly accessible.
|
||||
pub struct BlockRef<'a> {
|
||||
/// Block header.
|
||||
@@ -133,7 +145,7 @@ pub struct BlockRef<'a> {
|
||||
|
||||
impl ExecutedBlock {
|
||||
/// Create a new block from the given `state`.
|
||||
fn new(state: State<StateDB>, tracing: bool) -> ExecutedBlock {
|
||||
fn new(state: State<StateDB>, last_hashes: Arc<LastHashes>, tracing: bool) -> ExecutedBlock {
|
||||
ExecutedBlock {
|
||||
header: Default::default(),
|
||||
transactions: Default::default(),
|
||||
@@ -142,6 +154,7 @@ impl ExecutedBlock {
|
||||
transactions_set: Default::default(),
|
||||
state: state,
|
||||
traces: if tracing {Some(Vec::new())} else {None},
|
||||
last_hashes: last_hashes,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -168,6 +181,20 @@ impl ExecutedBlock {
|
||||
traces: &self.traces,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the environment info concerning this block.
|
||||
pub fn env_info(&self) -> EnvInfo {
|
||||
// TODO: memoise.
|
||||
EnvInfo {
|
||||
number: self.header.number(),
|
||||
author: self.header.author().clone(),
|
||||
timestamp: self.header.timestamp(),
|
||||
difficulty: self.header.difficulty().clone(),
|
||||
last_hashes: self.last_hashes.clone(),
|
||||
gas_used: self.receipts.last().map_or(U256::zero(), |r| r.gas_used),
|
||||
gas_limit: self.header.gas_limit().clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for a object that is a `ExecutedBlock`.
|
||||
@@ -216,14 +243,33 @@ impl IsBlock for ExecutedBlock {
|
||||
fn block(&self) -> &ExecutedBlock { self }
|
||||
}
|
||||
|
||||
impl ::parity_machine::LiveBlock for ExecutedBlock {
|
||||
type Header = Header;
|
||||
|
||||
fn header(&self) -> &Header {
|
||||
&self.header
|
||||
}
|
||||
|
||||
fn uncles(&self) -> &[Header] {
|
||||
&self.uncles
|
||||
}
|
||||
}
|
||||
|
||||
impl ::parity_machine::Transactions for ExecutedBlock {
|
||||
type Transaction = SignedTransaction;
|
||||
|
||||
fn transactions(&self) -> &[SignedTransaction] {
|
||||
&self.transactions
|
||||
}
|
||||
}
|
||||
|
||||
/// Block that is ready for transactions to be added.
|
||||
///
|
||||
/// It's a bit like a Vec<Transaction>, except that whenever a transaction is pushed, we execute it and
|
||||
/// maintain the system `state()`. We also archive execution receipts in preparation for later block creation.
|
||||
pub struct OpenBlock<'x> {
|
||||
block: ExecutedBlock,
|
||||
engine: &'x Engine,
|
||||
last_hashes: Arc<LastHashes>,
|
||||
engine: &'x EthEngine,
|
||||
}
|
||||
|
||||
/// Just like `OpenBlock`, except that we've applied `Engine::on_close_block`, finished up the non-seal header fields,
|
||||
@@ -234,7 +280,6 @@ pub struct OpenBlock<'x> {
|
||||
pub struct ClosedBlock {
|
||||
block: ExecutedBlock,
|
||||
uncle_bytes: Bytes,
|
||||
last_hashes: Arc<LastHashes>,
|
||||
unclosed_state: State<StateDB>,
|
||||
}
|
||||
|
||||
@@ -259,7 +304,7 @@ impl<'x> OpenBlock<'x> {
|
||||
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||
/// Create a new `OpenBlock` ready for transaction pushing.
|
||||
pub fn new(
|
||||
engine: &'x Engine,
|
||||
engine: &'x EthEngine,
|
||||
factories: Factories,
|
||||
tracing: bool,
|
||||
db: StateDB,
|
||||
@@ -273,9 +318,8 @@ impl<'x> OpenBlock<'x> {
|
||||
let number = parent.number() + 1;
|
||||
let state = State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(number), factories)?;
|
||||
let mut r = OpenBlock {
|
||||
block: ExecutedBlock::new(state, tracing),
|
||||
block: ExecutedBlock::new(state, last_hashes, tracing),
|
||||
engine: engine,
|
||||
last_hashes: last_hashes.clone(),
|
||||
};
|
||||
|
||||
r.block.header.set_parent_hash(parent.hash());
|
||||
@@ -287,8 +331,12 @@ impl<'x> OpenBlock<'x> {
|
||||
|
||||
let gas_floor_target = cmp::max(gas_range_target.0, engine.params().min_gas_limit);
|
||||
let gas_ceil_target = cmp::max(gas_range_target.1, gas_floor_target);
|
||||
engine.populate_from_parent(&mut r.block.header, parent, gas_floor_target, gas_ceil_target);
|
||||
engine.on_new_block(&mut r.block, last_hashes, is_epoch_begin)?;
|
||||
|
||||
engine.machine().populate_from_parent(&mut r.block.header, parent, gas_floor_target, gas_ceil_target);
|
||||
engine.populate_from_parent(&mut r.block.header, parent);
|
||||
|
||||
engine.machine().on_new_block(&mut r.block)?;
|
||||
engine.on_new_block(&mut r.block, is_epoch_begin)?;
|
||||
|
||||
Ok(r)
|
||||
}
|
||||
@@ -343,16 +391,7 @@ impl<'x> OpenBlock<'x> {
|
||||
|
||||
/// Get the environment info concerning this block.
|
||||
pub fn env_info(&self) -> EnvInfo {
|
||||
// TODO: memoise.
|
||||
EnvInfo {
|
||||
number: self.block.header.number(),
|
||||
author: self.block.header.author().clone(),
|
||||
timestamp: self.block.header.timestamp(),
|
||||
difficulty: self.block.header.difficulty().clone(),
|
||||
last_hashes: self.last_hashes.clone(),
|
||||
gas_used: self.block.receipts.last().map_or(U256::zero(), |r| r.gas_used),
|
||||
gas_limit: self.block.header.gas_limit().clone(),
|
||||
}
|
||||
self.block.env_info()
|
||||
}
|
||||
|
||||
/// Push a transaction into the block.
|
||||
@@ -365,7 +404,7 @@ impl<'x> OpenBlock<'x> {
|
||||
|
||||
let env_info = self.env_info();
|
||||
// info!("env_info says gas_used={}", env_info.gas_used);
|
||||
match self.block.state.apply(&env_info, self.engine, &t, self.block.traces.is_some()) {
|
||||
match self.block.state.apply(&env_info, self.engine.machine(), &t, self.block.traces.is_some()) {
|
||||
Ok(outcome) => {
|
||||
self.block.transactions_set.insert(h.unwrap_or_else(||t.hash()));
|
||||
self.block.transactions.push(t.into());
|
||||
@@ -418,7 +457,6 @@ impl<'x> OpenBlock<'x> {
|
||||
ClosedBlock {
|
||||
block: s.block,
|
||||
uncle_bytes: uncle_bytes,
|
||||
last_hashes: s.last_hashes,
|
||||
unclosed_state: unclosed_state,
|
||||
}
|
||||
}
|
||||
@@ -485,14 +523,13 @@ impl ClosedBlock {
|
||||
}
|
||||
|
||||
/// Given an engine reference, reopen the `ClosedBlock` into an `OpenBlock`.
|
||||
pub fn reopen(self, engine: &Engine) -> OpenBlock {
|
||||
pub fn reopen(self, engine: &EthEngine) -> OpenBlock {
|
||||
// revert rewards (i.e. set state back at last transaction's state).
|
||||
let mut block = self.block;
|
||||
block.state = self.unclosed_state;
|
||||
OpenBlock {
|
||||
block: block,
|
||||
engine: engine,
|
||||
last_hashes: self.last_hashes,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -504,7 +541,7 @@ impl LockedBlock {
|
||||
/// Provide a valid seal in order to turn this into a `SealedBlock`.
|
||||
///
|
||||
/// NOTE: This does not check the validity of `seal` with the engine.
|
||||
pub fn seal(self, engine: &Engine, seal: Vec<Bytes>) -> Result<SealedBlock, BlockError> {
|
||||
pub fn seal(self, engine: &EthEngine, seal: Vec<Bytes>) -> Result<SealedBlock, BlockError> {
|
||||
let mut s = self;
|
||||
if seal.len() != engine.seal_fields() {
|
||||
return Err(BlockError::InvalidSealArity(Mismatch{expected: engine.seal_fields(), found: seal.len()}));
|
||||
@@ -518,12 +555,14 @@ impl LockedBlock {
|
||||
/// Returns the `ClosedBlock` back again if the seal is no good.
|
||||
pub fn try_seal(
|
||||
self,
|
||||
engine: &Engine,
|
||||
engine: &EthEngine,
|
||||
seal: Vec<Bytes>,
|
||||
) -> Result<SealedBlock, (Error, LockedBlock)> {
|
||||
let mut s = self;
|
||||
s.block.header.set_seal(seal);
|
||||
match engine.verify_block_seal(&s.block.header) {
|
||||
|
||||
// TODO: passing state context to avoid engines owning it?
|
||||
match engine.verify_local_seal(&s.block.header) {
|
||||
Err(e) => Err((e, s)),
|
||||
_ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }),
|
||||
}
|
||||
@@ -575,7 +614,7 @@ pub fn enact(
|
||||
header: &Header,
|
||||
transactions: &[SignedTransaction],
|
||||
uncles: &[Header],
|
||||
engine: &Engine,
|
||||
engine: &EthEngine,
|
||||
tracing: bool,
|
||||
db: StateDB,
|
||||
parent: &Header,
|
||||
@@ -647,7 +686,7 @@ fn push_transactions(block: &mut OpenBlock, transactions: &[SignedTransaction])
|
||||
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||
pub fn enact_verified(
|
||||
block: &PreverifiedBlock,
|
||||
engine: &Engine,
|
||||
engine: &EthEngine,
|
||||
tracing: bool,
|
||||
db: StateDB,
|
||||
parent: &Header,
|
||||
@@ -675,7 +714,7 @@ pub fn enact_verified(
|
||||
mod tests {
|
||||
use tests::helpers::*;
|
||||
use super::*;
|
||||
use engines::Engine;
|
||||
use engines::EthEngine;
|
||||
use vm::LastHashes;
|
||||
use error::Error;
|
||||
use header::Header;
|
||||
@@ -690,7 +729,7 @@ mod tests {
|
||||
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||
fn enact_bytes(
|
||||
block_bytes: &[u8],
|
||||
engine: &Engine,
|
||||
engine: &EthEngine,
|
||||
tracing: bool,
|
||||
db: StateDB,
|
||||
parent: &Header,
|
||||
@@ -737,7 +776,7 @@ mod tests {
|
||||
#[cfg_attr(feature="dev", allow(too_many_arguments))]
|
||||
fn enact_and_seal(
|
||||
block_bytes: &[u8],
|
||||
engine: &Engine,
|
||||
engine: &EthEngine,
|
||||
tracing: bool,
|
||||
db: StateDB,
|
||||
parent: &Header,
|
||||
|
||||
Reference in New Issue
Block a user