engine changes
This commit is contained in:
parent
7723d6281b
commit
2d8a8bd3e5
@ -26,7 +26,7 @@ use util::error::{Mismatch, OutOfBounds};
|
|||||||
|
|
||||||
use basic_types::{LogBloom, Seal};
|
use basic_types::{LogBloom, Seal};
|
||||||
use env_info::{EnvInfo, LastHashes};
|
use env_info::{EnvInfo, LastHashes};
|
||||||
use engines::{Engine, ValidationProof};
|
use engines::Engine;
|
||||||
use error::{Error, BlockError, TransactionError};
|
use error::{Error, BlockError, TransactionError};
|
||||||
use factory::Factories;
|
use factory::Factories;
|
||||||
use header::Header;
|
use header::Header;
|
||||||
@ -488,11 +488,10 @@ impl LockedBlock {
|
|||||||
self,
|
self,
|
||||||
engine: &Engine,
|
engine: &Engine,
|
||||||
seal: Vec<Bytes>,
|
seal: Vec<Bytes>,
|
||||||
proof: Option<ValidationProof>,
|
|
||||||
) -> Result<SealedBlock, (Error, LockedBlock)> {
|
) -> Result<SealedBlock, (Error, LockedBlock)> {
|
||||||
let mut s = self;
|
let mut s = self;
|
||||||
s.block.header.set_seal(seal);
|
s.block.header.set_seal(seal);
|
||||||
match engine.verify_block_seal(&s.block.header, proof) {
|
match engine.verify_block_seal(&s.block.header) {
|
||||||
Err(e) => Err((e, s)),
|
Err(e) => Err((e, s)),
|
||||||
_ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }),
|
_ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }),
|
||||||
}
|
}
|
||||||
|
@ -464,14 +464,14 @@ mod tests {
|
|||||||
|
|
||||||
engine.set_signer(tap.clone(), addr1, "1".into());
|
engine.set_signer(tap.clone(), addr1, "1".into());
|
||||||
if let Seal::Regular(seal) = engine.generate_seal(b1.block()) {
|
if let Seal::Regular(seal) = engine.generate_seal(b1.block()) {
|
||||||
assert!(b1.clone().try_seal(engine, seal, None).is_ok());
|
assert!(b1.clone().try_seal(engine, seal).is_ok());
|
||||||
// Second proposal is forbidden.
|
// Second proposal is forbidden.
|
||||||
assert!(engine.generate_seal(b1.block()) == Seal::None);
|
assert!(engine.generate_seal(b1.block()) == Seal::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.set_signer(tap, addr2, "2".into());
|
engine.set_signer(tap, addr2, "2".into());
|
||||||
if let Seal::Regular(seal) = engine.generate_seal(b2.block()) {
|
if let Seal::Regular(seal) = engine.generate_seal(b2.block()) {
|
||||||
assert!(b2.clone().try_seal(engine, seal, None).is_ok());
|
assert!(b2.clone().try_seal(engine, seal).is_ok());
|
||||||
// Second proposal is forbidden.
|
// Second proposal is forbidden.
|
||||||
assert!(engine.generate_seal(b2.block()) == Seal::None);
|
assert!(engine.generate_seal(b2.block()) == Seal::None);
|
||||||
}
|
}
|
||||||
|
@ -258,7 +258,7 @@ mod tests {
|
|||||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
|
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let b = b.close_and_lock();
|
let b = b.close_and_lock();
|
||||||
if let Seal::Regular(seal) = engine.generate_seal(b.block()) {
|
if let Seal::Regular(seal) = engine.generate_seal(b.block()) {
|
||||||
assert!(b.try_seal(engine, seal, None).is_ok());
|
assert!(b.try_seal(engine, seal).is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,7 +89,7 @@ mod tests {
|
|||||||
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, Address::default(), (3141562.into(), 31415620.into()), vec![]).unwrap();
|
||||||
let b = b.close_and_lock();
|
let b = b.close_and_lock();
|
||||||
if let Seal::Regular(seal) = engine.generate_seal(b.block()) {
|
if let Seal::Regular(seal) = engine.generate_seal(b.block()) {
|
||||||
assert!(b.try_seal(engine, seal, None).is_ok());
|
assert!(b.try_seal(engine, seal).is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,6 +44,7 @@ use evm::Schedule;
|
|||||||
use header::Header;
|
use header::Header;
|
||||||
use spec::CommonParams;
|
use spec::CommonParams;
|
||||||
use transaction::{UnverifiedTransaction, SignedTransaction};
|
use transaction::{UnverifiedTransaction, SignedTransaction};
|
||||||
|
use receipt::Receipt;
|
||||||
|
|
||||||
use ethkey::Signature;
|
use ethkey::Signature;
|
||||||
use util::*;
|
use util::*;
|
||||||
@ -61,8 +62,6 @@ pub enum EngineError {
|
|||||||
UnexpectedMessage,
|
UnexpectedMessage,
|
||||||
/// Seal field has an unexpected size.
|
/// Seal field has an unexpected size.
|
||||||
BadSealFieldSize(OutOfBounds<usize>),
|
BadSealFieldSize(OutOfBounds<usize>),
|
||||||
/// Needs a validation proof for the given block hash before verification can continue.
|
|
||||||
NeedsValidationProof(H256),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for EngineError {
|
impl fmt::Display for EngineError {
|
||||||
@ -74,7 +73,6 @@ impl fmt::Display for EngineError {
|
|||||||
NotAuthorized(ref address) => format!("Signer {} is not authorized.", address),
|
NotAuthorized(ref address) => format!("Signer {} is not authorized.", address),
|
||||||
UnexpectedMessage => "This Engine should not be fed messages.".into(),
|
UnexpectedMessage => "This Engine should not be fed messages.".into(),
|
||||||
BadSealFieldSize(ref oob) => format!("Seal field has an unexpected length: {}", oob),
|
BadSealFieldSize(ref oob) => format!("Seal field has an unexpected length: {}", oob),
|
||||||
NeedsValidationProof(ref hash) => format!("Needs validation proof of block {} to verify seal.", hash),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
f.write_fmt(format_args!("Engine error ({})", msg))
|
f.write_fmt(format_args!("Engine error ({})", msg))
|
||||||
@ -92,12 +90,29 @@ pub enum Seal {
|
|||||||
None,
|
None,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A validation proof, required for validation of a block header.
|
|
||||||
pub type ValidationProof = Vec<DBValue>;
|
|
||||||
|
|
||||||
/// Type alias for a function we can make calls through synchronously.
|
/// Type alias for a function we can make calls through synchronously.
|
||||||
pub type Call = Fn(Address, Bytes) -> Result<Bytes, String>;
|
pub type Call = Fn(Address, Bytes) -> Result<Bytes, String>;
|
||||||
|
|
||||||
|
/// Results of a query of whether a validation proof is necessary at a block.
|
||||||
|
pub enum RequiresProof {
|
||||||
|
/// Cannot determine until more data is passed.
|
||||||
|
Unsure(Unsure),
|
||||||
|
/// Validation proof not required.
|
||||||
|
No,
|
||||||
|
/// Validation proof required.
|
||||||
|
Yes,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// More data required to determine if a validation proof is required.
|
||||||
|
pub enum Unsure {
|
||||||
|
/// Needs the body.
|
||||||
|
NeedsBody,
|
||||||
|
/// Needs the receipts.
|
||||||
|
NeedsReceipts,
|
||||||
|
/// Needs both body and receipts.
|
||||||
|
NeedsBoth,
|
||||||
|
}
|
||||||
|
|
||||||
/// A consensus mechanism for the chain. Generally either proof-of-work or proof-of-stake-based.
|
/// 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.
|
/// Provides hooks into each of the major parts of block import.
|
||||||
pub trait Engine : Sync + Send {
|
pub trait Engine : Sync + Send {
|
||||||
@ -191,23 +206,22 @@ pub trait Engine : Sync + Send {
|
|||||||
/// Verify the seal of a block. This is an auxilliary method that actually just calls other `verify_` methods
|
/// 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
|
/// 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.
|
/// methods are needed for an Engine, this may be overridden.
|
||||||
fn verify_block_seal(&self, header: &Header, _proof: Option<ValidationProof>) -> Result<(), Error> {
|
fn verify_block_seal(&self, header: &Header) -> Result<(), Error> {
|
||||||
self.verify_block_basic(header, None).and_then(|_| self.verify_block_unordered(header, None))
|
self.verify_block_basic(header, None).and_then(|_| self.verify_block_unordered(header, None))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Generate a validation proof for the given block header.
|
/// Re-do all verification for a header with the given contract-calling interface
|
||||||
///
|
///
|
||||||
/// All values queried during execution of given will go into the proof.
|
/// This will be used to generate proofs of validation as well as verify them.
|
||||||
/// This may only be called for blocks indicated in "needs validation proof"
|
fn verify_with_state(&self, _header: &Header, _call: &Call) -> Result<(), Error> {
|
||||||
/// errors.
|
Ok(())
|
||||||
///
|
}
|
||||||
/// Engines which don't draw consensus information from the state (e.g. PoW)
|
|
||||||
/// don't need to change anything here.
|
/// Whether a proof is required for the given header.
|
||||||
///
|
fn proof_required(&self, _header: Header, _block: Option<&[u8]>, _receipts: Option<&[Receipt]>)
|
||||||
/// Engines which do draw consensus information from the state may only do so
|
-> RequiresProof
|
||||||
/// here.
|
{
|
||||||
fn generate_validation_proof(&self, header: &Header, _call: &Call) -> ValidationProof {
|
RequiresProof::No
|
||||||
ValidationProof::default()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Populate a header's fields based on its parent's header.
|
/// Populate a header's fields based on its parent's header.
|
||||||
|
@ -864,7 +864,7 @@ mod tests {
|
|||||||
let proposer = insert_and_register(&tap, spec.engine.as_ref(), "1");
|
let proposer = insert_and_register(&tap, spec.engine.as_ref(), "1");
|
||||||
|
|
||||||
let (b, seal) = propose_default(&spec, proposer);
|
let (b, seal) = propose_default(&spec, proposer);
|
||||||
assert!(b.lock().try_seal(spec.engine.as_ref(), seal, None).is_ok());
|
assert!(b.lock().try_seal(spec.engine.as_ref(), seal).is_ok());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -25,15 +25,12 @@ use std::sync::Weak;
|
|||||||
use util::{Address, H256};
|
use util::{Address, H256};
|
||||||
use ethjson::spec::ValidatorSet as ValidatorSpec;
|
use ethjson::spec::ValidatorSet as ValidatorSpec;
|
||||||
use client::Client;
|
use client::Client;
|
||||||
use receipt::Receipt;
|
|
||||||
|
|
||||||
use self::simple_list::SimpleList;
|
use self::simple_list::SimpleList;
|
||||||
use self::contract::ValidatorContract;
|
use self::contract::ValidatorContract;
|
||||||
use self::safe_contract::ValidatorSafeContract;
|
use self::safe_contract::ValidatorSafeContract;
|
||||||
use self::multi::Multi;
|
use self::multi::Multi;
|
||||||
|
|
||||||
pub type Call = Fn(Address, Vec<u8>) -> Result<Vec<u8>, String>;
|
|
||||||
|
|
||||||
/// Creates a validator set from spec.
|
/// Creates a validator set from spec.
|
||||||
pub fn new_validator_set(spec: ValidatorSpec) -> Box<ValidatorSet> {
|
pub fn new_validator_set(spec: ValidatorSpec) -> Box<ValidatorSet> {
|
||||||
match spec {
|
match spec {
|
||||||
@ -48,10 +45,6 @@ pub fn new_validator_set(spec: ValidatorSpec) -> Box<ValidatorSet> {
|
|||||||
|
|
||||||
/// A validator set.
|
/// A validator set.
|
||||||
pub trait ValidatorSet: Send + Sync {
|
pub trait ValidatorSet: Send + Sync {
|
||||||
/// Get this validator set as a flexible validator set.
|
|
||||||
/// Returning `None` indicates this is only usable for
|
|
||||||
/// full nodes.
|
|
||||||
fn as_memoized(&self) -> Option<&Memoized> { None }
|
|
||||||
/// Checks if a given address is a validator.
|
/// Checks if a given address is a validator.
|
||||||
fn contains(&self, parent_block_hash: &H256, address: &Address) -> bool;
|
fn contains(&self, parent_block_hash: &H256, address: &Address) -> bool;
|
||||||
/// Draws an validator nonce modulo number of validators.
|
/// Draws an validator nonce modulo number of validators.
|
||||||
@ -65,35 +58,3 @@ pub trait ValidatorSet: Send + Sync {
|
|||||||
/// Allows blockchain state access.
|
/// Allows blockchain state access.
|
||||||
fn register_contract(&self, _client: Weak<Client>) {}
|
fn register_contract(&self, _client: Weak<Client>) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A flexible validator set can track its changes.
|
|
||||||
pub trait FlexibleValidatorSet: Send + Sync {
|
|
||||||
/// Whether a validator set may have changed at this header.
|
|
||||||
fn has_possibly_changed(&self, header: &Header) -> bool;
|
|
||||||
|
|
||||||
/// Whether a validator set has changed at this header, given the block receipts.
|
|
||||||
/// Called after `has_possibly_changed`.
|
|
||||||
/// `Some` indicates the validator set has changed at this header and the new
|
|
||||||
/// expected validator set.
|
|
||||||
/// `None` indicates no change.
|
|
||||||
fn has_changed(&self, header: &Header, receipts: &[Receipt]) -> Option<SimpleList>;
|
|
||||||
|
|
||||||
/// Fetch validators at a block synchronously.
|
|
||||||
fn fetch_validators(&self, header: &Header, call: &Call) -> Result<SimpleList, String>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A memoized flexible validator set
|
|
||||||
pub struct Memoized {
|
|
||||||
inner: Box<FlexibleValidatorSet>,
|
|
||||||
memo: Mutex<(SimpleList, (H256, u64))>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Memoized {
|
|
||||||
/// Denote that the
|
|
||||||
pub fn use_memo_at(&self, list: SimpleList)
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ValidatorSet for Memoized {
|
|
||||||
fn as_memoized(&self) -> Option<&Memoized> { Some(self) }
|
|
||||||
}
|
|
||||||
|
|
||||||
|
@ -55,7 +55,7 @@ impl Multi {
|
|||||||
) {
|
) {
|
||||||
Ok((block, set)) => {
|
Ok((block, set)) => {
|
||||||
trace!(target: "engine", "Multi ValidatorSet retrieved for block {}.", block);
|
trace!(target: "engine", "Multi ValidatorSet retrieved for block {}.", block);
|
||||||
Some(&*set)
|
Some(&**set)
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!(target: "engine", "ValidatorSet could not be recovered: {}", e);
|
debug!(target: "engine", "ValidatorSet could not be recovered: {}", e);
|
||||||
@ -66,21 +66,6 @@ impl Multi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ValidatorSet for Multi {
|
impl ValidatorSet for Multi {
|
||||||
fn has_possibly_changed(&self, header: &Header) -> bool {
|
|
||||||
// if the sets are the same for each header, compare those.
|
|
||||||
// otherwise, the sets have almost certainly changed.
|
|
||||||
match (self.correct_set(&header.hash()), self.correct_set(header.parent_hash())) {
|
|
||||||
(Some(a), Some(b)) if a as *const _ == b as *const _ => { a.has_possibly_changed(header) },
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn has_changed(&self, header: &Header, receipts: &[Receipt]) -> Option<Vec<Address>> {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fetch(&self) ->
|
|
||||||
|
|
||||||
fn contains(&self, bh: &H256, address: &Address) -> bool {
|
fn contains(&self, bh: &H256, address: &Address) -> bool {
|
||||||
self.correct_set(bh).map_or(false, |set| set.contains(bh, address))
|
self.correct_set(bh).map_or(false, |set| set.contains(bh, address))
|
||||||
}
|
}
|
||||||
|
@ -1133,7 +1133,7 @@ impl MinerService for Miner {
|
|||||||
|b| &b.hash() == &block_hash
|
|b| &b.hash() == &block_hash
|
||||||
) {
|
) {
|
||||||
trace!(target: "miner", "Submitted block {}={}={} with seal {:?}", block_hash, b.hash(), b.header().bare_hash(), seal);
|
trace!(target: "miner", "Submitted block {}={}={} with seal {:?}", block_hash, b.hash(), b.header().bare_hash(), seal);
|
||||||
b.lock().try_seal(&*self.engine, seal, None).or_else(|(e, _)| {
|
b.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| {
|
||||||
warn!(target: "miner", "Mined solution rejected: {}", e);
|
warn!(target: "miner", "Mined solution rejected: {}", e);
|
||||||
Err(Error::PowInvalid)
|
Err(Error::PowInvalid)
|
||||||
})
|
})
|
||||||
|
@ -567,7 +567,7 @@ pub fn verify_old_block(rng: &mut OsRng, header: &Header, engine: &Engine, chain
|
|||||||
if always || rng.gen::<f32>() <= POW_VERIFY_RATE {
|
if always || rng.gen::<f32>() <= POW_VERIFY_RATE {
|
||||||
match chain.block_header(header.parent_hash()) {
|
match chain.block_header(header.parent_hash()) {
|
||||||
Some(parent) => engine.verify_block_family(header, &parent, body),
|
Some(parent) => engine.verify_block_family(header, &parent, body),
|
||||||
None => engine.verify_block_seal(header, None), // TODO: fetch validation proof as necessary.
|
None => engine.verify_block_seal(header), // TODO: fetch validation proof as necessary.
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
engine.verify_block_basic(header, body)
|
engine.verify_block_basic(header, body)
|
||||||
|
Loading…
Reference in New Issue
Block a user