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
@@ -27,8 +27,8 @@ use futures::Future;
|
||||
use native_contracts::ValidatorReport as Provider;
|
||||
|
||||
use client::EngineClient;
|
||||
use engines::{Call, Engine};
|
||||
use header::{Header, BlockNumber};
|
||||
use machine::{AuxiliaryData, Call, EthereumMachine};
|
||||
|
||||
use super::{ValidatorSet, SimpleList, SystemCall};
|
||||
use super::safe_contract::ValidatorSafeContract;
|
||||
@@ -91,14 +91,13 @@ impl ValidatorSet for ValidatorContract {
|
||||
&self,
|
||||
first: bool,
|
||||
header: &Header,
|
||||
block: Option<&[u8]>,
|
||||
receipts: Option<&[::receipt::Receipt]>,
|
||||
) -> ::engines::EpochChange {
|
||||
self.validators.signals_epoch_end(first, header, block, receipts)
|
||||
aux: AuxiliaryData,
|
||||
) -> ::engines::EpochChange<EthereumMachine> {
|
||||
self.validators.signals_epoch_end(first, header, aux)
|
||||
}
|
||||
|
||||
fn epoch_set(&self, first: bool, engine: &Engine, number: BlockNumber, proof: &[u8]) -> Result<(SimpleList, Option<H256>), ::error::Error> {
|
||||
self.validators.epoch_set(first, engine, number, proof)
|
||||
fn epoch_set(&self, first: bool, machine: &EthereumMachine, number: BlockNumber, proof: &[u8]) -> Result<(SimpleList, Option<H256>), ::error::Error> {
|
||||
self.validators.epoch_set(first, machine, number, proof)
|
||||
}
|
||||
|
||||
fn contains_with_caller(&self, bh: &H256, address: &Address, caller: &Call) -> bool {
|
||||
@@ -182,7 +181,7 @@ mod tests {
|
||||
header.set_parent_hash(client.chain_info().best_block_hash);
|
||||
|
||||
// `reportBenign` when the designated proposer releases block from the future (bad clock).
|
||||
assert!(client.engine().verify_block_external(&header, None).is_err());
|
||||
assert!(client.engine().verify_block_external(&header).is_err());
|
||||
// Seal a block.
|
||||
client.engine().step();
|
||||
assert_eq!(client.chain_info().best_block_number, 1);
|
||||
@@ -190,7 +189,7 @@ mod tests {
|
||||
assert_eq!(client.call_contract(BlockId::Latest, validator_contract, "d8f2e0bf".from_hex().unwrap()).unwrap().to_hex(), "0000000000000000000000007d577a597b2742b498cb5cf0c26cdcd726d39e6e");
|
||||
// Simulate a misbehaving validator by handling a double proposal.
|
||||
let header = client.best_block_header().decode();
|
||||
assert!(client.engine().verify_block_family(&header, &header, None).is_err());
|
||||
assert!(client.engine().verify_block_family(&header, &header).is_err());
|
||||
// Seal a block.
|
||||
client.engine().step();
|
||||
client.engine().step();
|
||||
|
||||
@@ -31,6 +31,7 @@ use bytes::Bytes;
|
||||
use ethjson::spec::ValidatorSet as ValidatorSpec;
|
||||
use client::EngineClient;
|
||||
use header::{Header, BlockNumber};
|
||||
use machine::{AuxiliaryData, Call, EthereumMachine};
|
||||
|
||||
#[cfg(test)]
|
||||
pub use self::test::TestSet;
|
||||
@@ -39,8 +40,6 @@ use self::contract::ValidatorContract;
|
||||
use self::safe_contract::ValidatorSafeContract;
|
||||
use self::multi::Multi;
|
||||
|
||||
use super::{Call, Engine};
|
||||
|
||||
/// A system-calling closure. Enacts calls on a block's state from the system address.
|
||||
pub type SystemCall<'a> = FnMut(Address, Bytes) -> Result<Bytes, String> + 'a;
|
||||
|
||||
@@ -113,9 +112,8 @@ pub trait ValidatorSet: Send + Sync {
|
||||
&self,
|
||||
first: bool,
|
||||
header: &Header,
|
||||
block: Option<&[u8]>,
|
||||
receipts: Option<&[::receipt::Receipt]>,
|
||||
) -> ::engines::EpochChange;
|
||||
aux: AuxiliaryData,
|
||||
) -> ::engines::EpochChange<EthereumMachine>;
|
||||
|
||||
/// Recover the validator set from the given proof, the block number, and
|
||||
/// whether this header is first in its set.
|
||||
@@ -125,7 +123,7 @@ pub trait ValidatorSet: Send + Sync {
|
||||
///
|
||||
/// Returns the set, along with a flag indicating whether finality of a specific
|
||||
/// hash should be proven.
|
||||
fn epoch_set(&self, first: bool, engine: &Engine, number: BlockNumber, proof: &[u8])
|
||||
fn epoch_set(&self, first: bool, machine: &EthereumMachine, number: BlockNumber, proof: &[u8])
|
||||
-> Result<(SimpleList, Option<H256>), ::error::Error>;
|
||||
|
||||
/// Checks if a given address is a validator, with the given function
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Weak;
|
||||
use engines::{Call, Engine};
|
||||
use bigint::hash::H256;
|
||||
use parking_lot::RwLock;
|
||||
use util::Address;
|
||||
@@ -26,6 +25,7 @@ use bytes::Bytes;
|
||||
use ids::BlockId;
|
||||
use header::{BlockNumber, Header};
|
||||
use client::EngineClient;
|
||||
use machine::{AuxiliaryData, Call, EthereumMachine};
|
||||
use super::{SystemCall, ValidatorSet};
|
||||
|
||||
type BlockNumberLookup = Box<Fn(BlockId) -> Result<BlockNumber, String> + Send + Sync + 'static>;
|
||||
@@ -93,20 +93,20 @@ impl ValidatorSet for Multi {
|
||||
set.is_epoch_end(first, chain_head)
|
||||
}
|
||||
|
||||
fn signals_epoch_end(&self, _first: bool, header: &Header, block: Option<&[u8]>, receipts: Option<&[::receipt::Receipt]>)
|
||||
-> ::engines::EpochChange
|
||||
fn signals_epoch_end(&self, _first: bool, header: &Header, aux: AuxiliaryData)
|
||||
-> ::engines::EpochChange<EthereumMachine>
|
||||
{
|
||||
let (set_block, set) = self.correct_set_by_number(header.number());
|
||||
let first = set_block == header.number();
|
||||
|
||||
set.signals_epoch_end(first, header, block, receipts)
|
||||
set.signals_epoch_end(first, header, aux)
|
||||
}
|
||||
|
||||
fn epoch_set(&self, _first: bool, engine: &Engine, number: BlockNumber, proof: &[u8]) -> Result<(super::SimpleList, Option<H256>), ::error::Error> {
|
||||
fn epoch_set(&self, _first: bool, machine: &EthereumMachine, number: BlockNumber, proof: &[u8]) -> Result<(super::SimpleList, Option<H256>), ::error::Error> {
|
||||
let (set_block, set) = self.correct_set_by_number(number);
|
||||
let first = set_block == number;
|
||||
|
||||
set.epoch_set(first, engine, number, proof)
|
||||
set.epoch_set(first, machine, number, proof)
|
||||
}
|
||||
|
||||
fn contains_with_caller(&self, bh: &H256, address: &Address, caller: &Call) -> bool {
|
||||
@@ -227,7 +227,7 @@ mod tests {
|
||||
let mut header = Header::new();
|
||||
header.set_number(499);
|
||||
|
||||
match multi.signals_epoch_end(false, &header, None, None) {
|
||||
match multi.signals_epoch_end(false, &header, Default::default()) {
|
||||
EpochChange::No => {},
|
||||
_ => panic!("Expected no epoch signal change."),
|
||||
}
|
||||
@@ -235,7 +235,7 @@ mod tests {
|
||||
|
||||
header.set_number(500);
|
||||
|
||||
match multi.signals_epoch_end(false, &header, None, None) {
|
||||
match multi.signals_epoch_end(false, &header, Default::default()) {
|
||||
EpochChange::No => {},
|
||||
_ => panic!("Expected no epoch signal change."),
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ use rlp::{UntrustedRlp, RlpStream};
|
||||
|
||||
use basic_types::LogBloom;
|
||||
use client::EngineClient;
|
||||
use engines::{Call, Engine};
|
||||
use machine::{AuxiliaryData, Call, EthereumMachine, AuxiliaryRequest};
|
||||
use header::Header;
|
||||
use ids::BlockId;
|
||||
use log_entry::LogEntry;
|
||||
@@ -58,19 +58,19 @@ struct StateProof {
|
||||
provider: Provider,
|
||||
}
|
||||
|
||||
impl ::engines::StateDependentProof for StateProof {
|
||||
impl ::engines::StateDependentProof<EthereumMachine> for StateProof {
|
||||
fn generate_proof(&self, caller: &Call) -> Result<Vec<u8>, String> {
|
||||
prove_initial(&self.provider, &*self.header.lock(), caller)
|
||||
}
|
||||
|
||||
fn check_proof(&self, engine: &Engine, proof: &[u8]) -> Result<(), String> {
|
||||
fn check_proof(&self, machine: &EthereumMachine, proof: &[u8]) -> Result<(), String> {
|
||||
let (header, state_items) = decode_first_proof(&UntrustedRlp::new(proof))
|
||||
.map_err(|e| format!("proof incorrectly encoded: {}", e))?;
|
||||
if &header != &*self.header.lock(){
|
||||
return Err("wrong header in proof".into());
|
||||
}
|
||||
|
||||
check_first_proof(engine, &self.provider, header, &state_items).map(|_| ())
|
||||
check_first_proof(machine, &self.provider, header, &state_items).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -94,7 +94,7 @@ fn encode_first_proof(header: &Header, state_items: &[Vec<u8>]) -> Bytes {
|
||||
}
|
||||
|
||||
// check a first proof: fetch the validator set at the given block.
|
||||
fn check_first_proof(engine: &Engine, provider: &Provider, old_header: Header, state_items: &[DBValue])
|
||||
fn check_first_proof(machine: &EthereumMachine, provider: &Provider, old_header: Header, state_items: &[DBValue])
|
||||
-> Result<Vec<Address>, String>
|
||||
{
|
||||
use transaction::{Action, Transaction};
|
||||
@@ -117,12 +117,12 @@ fn check_first_proof(engine: &Engine, provider: &Provider, old_header: Header, s
|
||||
gas_used: 0.into(),
|
||||
};
|
||||
|
||||
// check state proof using given engine.
|
||||
// check state proof using given machine.
|
||||
let number = old_header.number();
|
||||
provider.get_validators(move |a, d| {
|
||||
let from = Address::default();
|
||||
let tx = Transaction {
|
||||
nonce: engine.account_start_nonce(number),
|
||||
nonce: machine.account_start_nonce(number),
|
||||
action: Action::Call(a),
|
||||
gas: PROVIDED_GAS.into(),
|
||||
gas_price: U256::default(),
|
||||
@@ -134,7 +134,7 @@ fn check_first_proof(engine: &Engine, provider: &Provider, old_header: Header, s
|
||||
state_items,
|
||||
*old_header.state_root(),
|
||||
&tx,
|
||||
engine,
|
||||
machine,
|
||||
&env_info,
|
||||
);
|
||||
|
||||
@@ -336,9 +336,11 @@ impl ValidatorSet for ValidatorSafeContract {
|
||||
None // no immediate transitions to contract.
|
||||
}
|
||||
|
||||
fn signals_epoch_end(&self, first: bool, header: &Header, _block: Option<&[u8]>, receipts: Option<&[Receipt]>)
|
||||
-> ::engines::EpochChange
|
||||
fn signals_epoch_end(&self, first: bool, header: &Header, aux: AuxiliaryData)
|
||||
-> ::engines::EpochChange<EthereumMachine>
|
||||
{
|
||||
let receipts = aux.receipts;
|
||||
|
||||
// transition to the first block of a contract requires finality but has no log event.
|
||||
if first {
|
||||
debug!(target: "engine", "signalling transition to fresh contract.");
|
||||
@@ -358,7 +360,7 @@ impl ValidatorSet for ValidatorSafeContract {
|
||||
trace!(target: "engine", "detected epoch change event bloom");
|
||||
|
||||
match receipts {
|
||||
None => ::engines::EpochChange::Unsure(::engines::Unsure::NeedsReceipts),
|
||||
None => ::engines::EpochChange::Unsure(AuxiliaryRequest::Receipts),
|
||||
Some(receipts) => match self.extract_from_event(bloom, header, receipts) {
|
||||
None => ::engines::EpochChange::No,
|
||||
Some(list) => {
|
||||
@@ -372,7 +374,7 @@ impl ValidatorSet for ValidatorSafeContract {
|
||||
}
|
||||
}
|
||||
|
||||
fn epoch_set(&self, first: bool, engine: &Engine, _number: ::header::BlockNumber, proof: &[u8])
|
||||
fn epoch_set(&self, first: bool, machine: &EthereumMachine, _number: ::header::BlockNumber, proof: &[u8])
|
||||
-> Result<(SimpleList, Option<H256>), ::error::Error>
|
||||
{
|
||||
let rlp = UntrustedRlp::new(proof);
|
||||
@@ -383,7 +385,7 @@ impl ValidatorSet for ValidatorSafeContract {
|
||||
let (old_header, state_items) = decode_first_proof(&rlp)?;
|
||||
let number = old_header.number();
|
||||
let old_hash = old_header.hash();
|
||||
let addresses = check_first_proof(engine, &self.provider, old_header, &state_items)
|
||||
let addresses = check_first_proof(machine, &self.provider, old_header, &state_items)
|
||||
.map_err(::engines::EngineError::InsufficientProof)?;
|
||||
|
||||
trace!(target: "engine", "extracted epoch set at #{}: {} addresses",
|
||||
@@ -561,7 +563,8 @@ mod tests {
|
||||
#[test]
|
||||
fn detects_bloom() {
|
||||
use header::Header;
|
||||
use engines::{EpochChange, Unsure};
|
||||
use engines::EpochChange;
|
||||
use machine::AuxiliaryRequest;
|
||||
use log_entry::LogEntry;
|
||||
|
||||
let client = generate_dummy_client_with_spec_and_accounts(Spec::new_validator_safe_contract, None);
|
||||
@@ -581,7 +584,7 @@ mod tests {
|
||||
};
|
||||
|
||||
new_header.set_log_bloom(event.bloom());
|
||||
match engine.signals_epoch_end(&new_header, None, None) {
|
||||
match engine.signals_epoch_end(&new_header, Default::default()) {
|
||||
EpochChange::No => {},
|
||||
_ => panic!("Expected bloom to be unrecognized."),
|
||||
};
|
||||
@@ -590,8 +593,8 @@ mod tests {
|
||||
event.topics.push(last_hash);
|
||||
new_header.set_log_bloom(event.bloom());
|
||||
|
||||
match engine.signals_epoch_end(&new_header, None, None) {
|
||||
EpochChange::Unsure(Unsure::NeedsReceipts) => {},
|
||||
match engine.signals_epoch_end(&new_header, Default::default()) {
|
||||
EpochChange::Unsure(AuxiliaryRequest::Receipts) => {},
|
||||
_ => panic!("Expected bloom to be recognized."),
|
||||
};
|
||||
}
|
||||
@@ -607,7 +610,7 @@ mod tests {
|
||||
let mut new_header = Header::default();
|
||||
new_header.set_number(0); // so the validator set doesn't look for a log
|
||||
|
||||
match engine.signals_epoch_end(&new_header, None, None) {
|
||||
match engine.signals_epoch_end(&new_header, Default::default()) {
|
||||
EpochChange::Yes(Proof::WithState(_)) => {},
|
||||
_ => panic!("Expected state to be required to prove initial signal"),
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ use heapsize::HeapSizeOf;
|
||||
use bigint::hash::H256;
|
||||
use util::Address;
|
||||
|
||||
use engines::{Call, Engine};
|
||||
use machine::{AuxiliaryData, Call, EthereumMachine};
|
||||
use header::{BlockNumber, Header};
|
||||
use super::ValidatorSet;
|
||||
|
||||
@@ -76,13 +76,13 @@ impl ValidatorSet for SimpleList {
|
||||
}
|
||||
}
|
||||
|
||||
fn signals_epoch_end(&self, _: bool, _: &Header, _: Option<&[u8]>, _: Option<&[::receipt::Receipt]>)
|
||||
-> ::engines::EpochChange
|
||||
fn signals_epoch_end(&self, _: bool, _: &Header, _: AuxiliaryData)
|
||||
-> ::engines::EpochChange<EthereumMachine>
|
||||
{
|
||||
::engines::EpochChange::No
|
||||
}
|
||||
|
||||
fn epoch_set(&self, _first: bool, _: &Engine, _: BlockNumber, _: &[u8]) -> Result<(SimpleList, Option<H256>), ::error::Error> {
|
||||
fn epoch_set(&self, _first: bool, _: &EthereumMachine, _: BlockNumber, _: &[u8]) -> Result<(SimpleList, Option<H256>), ::error::Error> {
|
||||
Ok((self.clone(), None))
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ use bigint::hash::H256;
|
||||
use util::Address;
|
||||
use bytes::Bytes;
|
||||
|
||||
use engines::{Call, Engine};
|
||||
use machine::{AuxiliaryData, Call, EthereumMachine};
|
||||
use header::{Header, BlockNumber};
|
||||
use super::{ValidatorSet, SimpleList};
|
||||
|
||||
@@ -58,13 +58,13 @@ impl ValidatorSet for TestSet {
|
||||
|
||||
fn is_epoch_end(&self, _first: bool, _chain_head: &Header) -> Option<Vec<u8>> { None }
|
||||
|
||||
fn signals_epoch_end(&self, _: bool, _: &Header, _: Option<&[u8]>, _: Option<&[::receipt::Receipt]>)
|
||||
-> ::engines::EpochChange
|
||||
fn signals_epoch_end(&self, _: bool, _: &Header, _: AuxiliaryData)
|
||||
-> ::engines::EpochChange<EthereumMachine>
|
||||
{
|
||||
::engines::EpochChange::No
|
||||
}
|
||||
|
||||
fn epoch_set(&self, _: bool, _: &Engine, _: BlockNumber, _: &[u8]) -> Result<(SimpleList, Option<H256>), ::error::Error> {
|
||||
fn epoch_set(&self, _: bool, _: &EthereumMachine, _: BlockNumber, _: &[u8]) -> Result<(SimpleList, Option<H256>), ::error::Error> {
|
||||
Ok((self.validator.clone(), None))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user