From a254b2098fd029ee03724e3898a69562e2787bcb Mon Sep 17 00:00:00 2001 From: Robert Habermeier Date: Tue, 11 Apr 2017 17:07:04 +0200 Subject: [PATCH] more useful Engine::verify_seal --- ethcore/src/block.rs | 11 +++++--- ethcore/src/engines/authority_round.rs | 4 +-- ethcore/src/engines/basic_authority.rs | 2 +- ethcore/src/engines/instant_seal.rs | 2 +- ethcore/src/engines/mod.rs | 36 ++++++++++++++++++++++---- ethcore/src/engines/tendermint/mod.rs | 2 +- ethcore/src/miner/miner.rs | 2 +- ethcore/src/snapshot/mod.rs | 2 +- 8 files changed, 46 insertions(+), 15 deletions(-) diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 12e77d41b..6ec2584ec 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -26,7 +26,7 @@ use util::error::{Mismatch, OutOfBounds}; use basic_types::{LogBloom, Seal}; use env_info::{EnvInfo, LastHashes}; -use engines::Engine; +use engines::{Engine, ValidationProof}; use error::{Error, BlockError, TransactionError}; use factory::Factories; use header::Header; @@ -484,10 +484,15 @@ impl LockedBlock { /// Provide a valid seal in order to turn this into a `SealedBlock`. /// This does check the validity of `seal` with the engine. /// Returns the `ClosedBlock` back again if the seal is no good. - pub fn try_seal(self, engine: &Engine, seal: Vec) -> Result { + pub fn try_seal( + self, + engine: &Engine, + seal: Vec, + proof: Option, + ) -> Result { let mut s = self; s.block.header.set_seal(seal); - match engine.verify_block_seal(&s.block.header) { + match engine.verify_block_seal(&s.block.header, proof) { Err(e) => Err((e, s)), _ => Ok(SealedBlock { block: s.block, uncle_bytes: s.uncle_bytes }), } diff --git a/ethcore/src/engines/authority_round.rs b/ethcore/src/engines/authority_round.rs index e6cbdb531..acc276d21 100644 --- a/ethcore/src/engines/authority_round.rs +++ b/ethcore/src/engines/authority_round.rs @@ -464,14 +464,14 @@ mod tests { engine.set_signer(tap.clone(), addr1, "1".into()); if let Seal::Regular(seal) = engine.generate_seal(b1.block()) { - assert!(b1.clone().try_seal(engine, seal).is_ok()); + assert!(b1.clone().try_seal(engine, seal, None).is_ok()); // Second proposal is forbidden. assert!(engine.generate_seal(b1.block()) == Seal::None); } engine.set_signer(tap, addr2, "2".into()); if let Seal::Regular(seal) = engine.generate_seal(b2.block()) { - assert!(b2.clone().try_seal(engine, seal).is_ok()); + assert!(b2.clone().try_seal(engine, seal, None).is_ok()); // Second proposal is forbidden. assert!(engine.generate_seal(b2.block()) == Seal::None); } diff --git a/ethcore/src/engines/basic_authority.rs b/ethcore/src/engines/basic_authority.rs index e5a53d4e9..fe27994e4 100644 --- a/ethcore/src/engines/basic_authority.rs +++ b/ethcore/src/engines/basic_authority.rs @@ -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 = b.close_and_lock(); if let Seal::Regular(seal) = engine.generate_seal(b.block()) { - assert!(b.try_seal(engine, seal).is_ok()); + assert!(b.try_seal(engine, seal, None).is_ok()); } } diff --git a/ethcore/src/engines/instant_seal.rs b/ethcore/src/engines/instant_seal.rs index 45bede9f4..5d05dd83f 100644 --- a/ethcore/src/engines/instant_seal.rs +++ b/ethcore/src/engines/instant_seal.rs @@ -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 = b.close_and_lock(); if let Seal::Regular(seal) = engine.generate_seal(b.block()) { - assert!(b.try_seal(engine, seal).is_ok()); + assert!(b.try_seal(engine, seal, None).is_ok()); } } diff --git a/ethcore/src/engines/mod.rs b/ethcore/src/engines/mod.rs index 438b9bda0..76a0d790b 100644 --- a/ethcore/src/engines/mod.rs +++ b/ethcore/src/engines/mod.rs @@ -33,18 +33,20 @@ pub use self::authority_round::AuthorityRound; pub use self::tendermint::Tendermint; use std::sync::Weak; -use util::*; -use ethkey::Signature; + use account_provider::AccountProvider; use block::ExecutedBlock; use builtin::Builtin; +use client::Client; use env_info::EnvInfo; use error::{Error, TransactionError}; -use spec::CommonParams; use evm::Schedule; use header::Header; +use spec::CommonParams; use transaction::{UnverifiedTransaction, SignedTransaction}; -use client::Client; + +use ethkey::Signature; +use util::*; /// Voting errors. #[derive(Debug)] @@ -59,6 +61,8 @@ pub enum EngineError { UnexpectedMessage, /// Seal field has an unexpected size. BadSealFieldSize(OutOfBounds), + /// Needs a validation proof for the given block hash before verification can continue. + NeedsValidationProof(H256), } impl fmt::Display for EngineError { @@ -70,6 +74,7 @@ impl fmt::Display for EngineError { NotAuthorized(ref address) => format!("Signer {} is not authorized.", address), UnexpectedMessage => "This Engine should not be fed messages.".into(), 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)) @@ -87,6 +92,12 @@ pub enum Seal { None, } +/// A validation proof, required for validation of a block header. +pub type ValidationProof = Vec; + +/// Type alias for a function we can make calls through synchronously. +pub type Call = Fn(Address, Bytes) -> Result; + /// 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 { @@ -180,10 +191,25 @@ pub trait Engine : Sync + Send { /// 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> { + fn verify_block_seal(&self, header: &Header, _proof: Option) -> Result<(), Error> { self.verify_block_basic(header, None).and_then(|_| self.verify_block_unordered(header, None)) } + /// Generate a validation proof for the given block header. + /// + /// All values queried during execution of given will go into the proof. + /// This may only be called for blocks indicated in "needs validation proof" + /// errors. + /// + /// Engines which don't draw consensus information from the state (e.g. PoW) + /// don't need to change anything here. + /// + /// Engines which do draw consensus information from the state may only do so + /// here. + fn generate_validation_proof(&self, _call: &Call) -> ValidationProof { + ValidationProof::default() + } + /// 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. diff --git a/ethcore/src/engines/tendermint/mod.rs b/ethcore/src/engines/tendermint/mod.rs index 8c8094117..e88803ce2 100644 --- a/ethcore/src/engines/tendermint/mod.rs +++ b/ethcore/src/engines/tendermint/mod.rs @@ -864,7 +864,7 @@ mod tests { let proposer = insert_and_register(&tap, spec.engine.as_ref(), "1"); let (b, seal) = propose_default(&spec, proposer); - assert!(b.lock().try_seal(spec.engine.as_ref(), seal).is_ok()); + assert!(b.lock().try_seal(spec.engine.as_ref(), seal, None).is_ok()); } #[test] diff --git a/ethcore/src/miner/miner.rs b/ethcore/src/miner/miner.rs index ac1695b52..8337ef2d8 100644 --- a/ethcore/src/miner/miner.rs +++ b/ethcore/src/miner/miner.rs @@ -1133,7 +1133,7 @@ impl MinerService for Miner { |b| &b.hash() == &block_hash ) { trace!(target: "miner", "Submitted block {}={}={} with seal {:?}", block_hash, b.hash(), b.header().bare_hash(), seal); - b.lock().try_seal(&*self.engine, seal).or_else(|(e, _)| { + b.lock().try_seal(&*self.engine, seal, None).or_else(|(e, _)| { warn!(target: "miner", "Mined solution rejected: {}", e); Err(Error::PowInvalid) }) diff --git a/ethcore/src/snapshot/mod.rs b/ethcore/src/snapshot/mod.rs index 69dbc943d..0ef263476 100644 --- a/ethcore/src/snapshot/mod.rs +++ b/ethcore/src/snapshot/mod.rs @@ -567,7 +567,7 @@ pub fn verify_old_block(rng: &mut OsRng, header: &Header, engine: &Engine, chain if always || rng.gen::() <= POW_VERIFY_RATE { match chain.block_header(header.parent_hash()) { Some(parent) => engine.verify_block_family(header, &parent, body), - None => engine.verify_block_seal(header), + None => engine.verify_block_seal(header, None), // TODO: fetch validation proof as necessary. } } else { engine.verify_block_basic(header, body)