skeleton for proof checking
This commit is contained in:
parent
ec922ee5e4
commit
34a1512ff0
@ -25,7 +25,7 @@ use rlp::{UntrustedRlp, encode};
|
||||
use account_provider::AccountProvider;
|
||||
use block::*;
|
||||
use spec::CommonParams;
|
||||
use engines::{Engine, Seal, EngineError};
|
||||
use engines::{Call, Engine, Seal, EngineError};
|
||||
use header::Header;
|
||||
use error::{Error, TransactionError, BlockError};
|
||||
use evm::Schedule;
|
||||
@ -358,6 +358,18 @@ impl Engine for AuthorityRound {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// the proofs we need just allow us to get the full validator set.
|
||||
fn prove_with_caller(&self, header: &Header, caller: &Call) -> Result<Bytes, Error> {
|
||||
self.validators.generate_proof(header, caller)
|
||||
.map_err(|e| EngineError::InsufficientProof(e).into())
|
||||
}
|
||||
|
||||
fn proof_required(&self, header: &Header, block: Option<&[u8]>, receipts: Option<&[::receipt::Receipt]>)
|
||||
-> super::RequiresProof
|
||||
{
|
||||
self.validators.proof_required(header, block, receipts)
|
||||
}
|
||||
|
||||
fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> result::Result<(), Error> {
|
||||
t.check_low_s()?;
|
||||
|
||||
|
@ -23,7 +23,7 @@ use account_provider::AccountProvider;
|
||||
use block::*;
|
||||
use builtin::Builtin;
|
||||
use spec::CommonParams;
|
||||
use engines::{Engine, Seal};
|
||||
use engines::{Engine, EngineError, Seal, Call, RequiresProof};
|
||||
use env_info::EnvInfo;
|
||||
use error::{BlockError, Error};
|
||||
use evm::Schedule;
|
||||
@ -51,8 +51,7 @@ impl From<ethjson::spec::BasicAuthorityParams> for BasicAuthorityParams {
|
||||
}
|
||||
}
|
||||
|
||||
/// Engine using `BasicAuthority` proof-of-work consensus algorithm, suitable for Ethereum
|
||||
/// mainnet chains in the Olympic, Frontier and Homestead eras.
|
||||
/// Engine using `BasicAuthority`, trivial proof-of-authority consensus.
|
||||
pub struct BasicAuthority {
|
||||
params: CommonParams,
|
||||
gas_limit_bound_divisor: U256,
|
||||
@ -139,6 +138,7 @@ impl Engine for BasicAuthority {
|
||||
|
||||
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
||||
use rlp::UntrustedRlp;
|
||||
|
||||
// Check if the signature belongs to a validator, can depend on parent state.
|
||||
let sig = UntrustedRlp::new(&header.seal()[0]).as_val::<H520>()?;
|
||||
let signer = public_to_address(&recover(&sig.into(), &header.bare_hash())?);
|
||||
@ -164,6 +164,18 @@ impl Engine for BasicAuthority {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// the proofs we need just allow us to get the full validator set.
|
||||
fn prove_with_caller(&self, header: &Header, caller: &Call) -> Result<Bytes, Error> {
|
||||
self.validators.generate_proof(header, caller)
|
||||
.map_err(|e| EngineError::InsufficientProof(e).into())
|
||||
}
|
||||
|
||||
fn proof_required(&self, header: &Header, block: Option<&[u8]>, receipts: Option<&[::receipt::Receipt]>)
|
||||
-> RequiresProof
|
||||
{
|
||||
self.validators.proof_required(header, block, receipts)
|
||||
}
|
||||
|
||||
fn register_client(&self, client: Weak<Client>) {
|
||||
self.validators.register_contract(client);
|
||||
}
|
||||
|
@ -62,6 +62,8 @@ pub enum EngineError {
|
||||
UnexpectedMessage,
|
||||
/// Seal field has an unexpected size.
|
||||
BadSealFieldSize(OutOfBounds<usize>),
|
||||
/// Validation proof insufficient.
|
||||
InsufficientProof(String),
|
||||
}
|
||||
|
||||
impl fmt::Display for EngineError {
|
||||
@ -73,6 +75,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),
|
||||
InsufficientProof(ref msg) => format!("Insufficient validation proof: {}", msg),
|
||||
};
|
||||
|
||||
f.write_fmt(format_args!("Engine error ({})", msg))
|
||||
@ -99,8 +102,9 @@ pub enum RequiresProof {
|
||||
Unsure(Unsure),
|
||||
/// Validation proof not required.
|
||||
No,
|
||||
/// Validation proof required.
|
||||
Yes,
|
||||
/// Validation proof required, and the expected output
|
||||
/// if it can be recovered.
|
||||
Yes(Option<Bytes>),
|
||||
}
|
||||
|
||||
/// More data required to determine if a validation proof is required.
|
||||
@ -213,12 +217,15 @@ pub trait Engine : Sync + Send {
|
||||
/// Re-do all verification for a header with the given contract-calling interface
|
||||
///
|
||||
/// This will be used to generate proofs of validation as well as verify them.
|
||||
fn verify_with_state(&self, _header: &Header, _call: &Call) -> Result<(), Error> {
|
||||
Ok(())
|
||||
/// Must be called on blocks that have already passed basic verification.
|
||||
///
|
||||
/// Return the "validation proof" generated.
|
||||
fn prove_with_caller(&self, _header: &Header, _caller: &Call) -> Result<Bytes, Error> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
/// Whether a proof is required for the given header.
|
||||
fn proof_required(&self, _header: Header, _block: Option<&[u8]>, _receipts: Option<&[Receipt]>)
|
||||
fn proof_required(&self, _header: &Header, _block: Option<&[u8]>, _receipts: Option<&[Receipt]>)
|
||||
-> RequiresProof
|
||||
{
|
||||
RequiresProof::No
|
||||
|
@ -25,6 +25,7 @@ use native_contracts::ValidatorReport as Provider;
|
||||
|
||||
use client::{Client, BlockChainClient};
|
||||
use engines::Call;
|
||||
use header::Header;
|
||||
|
||||
use super::ValidatorSet;
|
||||
use super::safe_contract::ValidatorSafeContract;
|
||||
@ -65,6 +66,16 @@ impl ValidatorSet for ValidatorContract {
|
||||
self.validators.default_caller(id)
|
||||
}
|
||||
|
||||
fn proof_required(&self, header: &Header, block: Option<&[u8]>, receipts: Option<&[::receipt::Receipt]>)
|
||||
-> ::engines::RequiresProof
|
||||
{
|
||||
self.validators.proof_required(header, block, receipts)
|
||||
}
|
||||
|
||||
fn generate_proof(&self, header: &Header, caller: &Call) -> Result<Vec<u8>, String> {
|
||||
self.validators.generate_proof(header, caller)
|
||||
}
|
||||
|
||||
fn contains_with_caller(&self, bh: &H256, address: &Address, caller: &Call) -> bool {
|
||||
self.validators.contains_with_caller(bh, address, caller)
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ use ids::BlockId;
|
||||
use util::{Address, H256};
|
||||
use ethjson::spec::ValidatorSet as ValidatorSpec;
|
||||
use client::Client;
|
||||
use header::Header;
|
||||
|
||||
use self::simple_list::SimpleList;
|
||||
use self::contract::ValidatorContract;
|
||||
@ -47,9 +48,10 @@ pub fn new_validator_set(spec: ValidatorSpec) -> Box<ValidatorSet> {
|
||||
}
|
||||
|
||||
/// A validator set.
|
||||
// TODO [keorn]: remove internal callers.
|
||||
pub trait ValidatorSet: Send + Sync {
|
||||
/// Get the default "Call" helper, for use in general operation.
|
||||
// TODO [keorn]: this is a hack intended to migrate off of
|
||||
// a strict dependency on state always being available.
|
||||
fn default_caller(&self, block_id: BlockId) -> Box<Call>;
|
||||
|
||||
/// Checks if a given address is a validator,
|
||||
@ -63,12 +65,31 @@ pub trait ValidatorSet: Send + Sync {
|
||||
let default = self.default_caller(BlockId::Hash(*parent));
|
||||
self.get_with_caller(parent, nonce, &*default)
|
||||
}
|
||||
|
||||
/// Returns the current number of validators.
|
||||
fn count(&self, parent: &H256) -> usize {
|
||||
let default = self.default_caller(BlockId::Hash(*parent));
|
||||
self.count_with_caller(parent, &*default)
|
||||
}
|
||||
|
||||
/// Whether a validation proof is required at the given block.
|
||||
/// Usually indicates that the validator set changed at the given block.
|
||||
///
|
||||
/// Should not inspect state! This is used in situations where
|
||||
/// state is not generally available.
|
||||
///
|
||||
/// Return `Ok` with a flag indicating whether it changed at the given header,
|
||||
/// or `Unsure` indicating a need for more information.
|
||||
///
|
||||
/// This may or may not be called in a loop.
|
||||
fn proof_required(&self, header: &Header, block: Option<&[u8]>, receipts: Option<&[::receipt::Receipt]>)
|
||||
-> super::RequiresProof;
|
||||
|
||||
/// Generate a validation proof at the given header.
|
||||
/// Must interact with state only through the given caller!
|
||||
/// Otherwise, generated proofs may be wrong.
|
||||
fn generate_proof(&self, header: &Header, caller: &Call) -> Result<Vec<u8>, String>;
|
||||
|
||||
/// Checks if a given address is a validator, with the given function
|
||||
/// for executing synchronous calls to contracts.
|
||||
fn contains_with_caller(&self, parent_block_hash: &H256, address: &Address, caller: &Call) -> bool;
|
||||
|
@ -18,10 +18,10 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Weak;
|
||||
use engines::Call;
|
||||
use engines::{Call, RequiresProof};
|
||||
use util::{H256, Address, RwLock};
|
||||
use ids::BlockId;
|
||||
use header::BlockNumber;
|
||||
use header::{BlockNumber, Header};
|
||||
use client::{Client, BlockChainClient};
|
||||
use super::ValidatorSet;
|
||||
|
||||
@ -42,21 +42,9 @@ impl Multi {
|
||||
}
|
||||
|
||||
fn correct_set(&self, id: BlockId) -> Option<&ValidatorSet> {
|
||||
match self
|
||||
.block_number
|
||||
.read()(id)
|
||||
.map(|parent_block| self
|
||||
.sets
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|&(block, _)| *block <= parent_block + 1)
|
||||
.expect("constructor validation ensures that there is at least one validator set for block 0;
|
||||
block 0 is less than any uint;
|
||||
qed")
|
||||
) {
|
||||
Ok((block, set)) => {
|
||||
trace!(target: "engine", "Multi ValidatorSet retrieved for block {}.", block);
|
||||
Some(&**set)
|
||||
match self.block_number.read()(id).map(|parent_block| self.correct_set_by_number(parent_block)) {
|
||||
Ok(set) => {
|
||||
Some(set)
|
||||
},
|
||||
Err(e) => {
|
||||
debug!(target: "engine", "ValidatorSet could not be recovered: {}", e);
|
||||
@ -64,6 +52,18 @@ impl Multi {
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
fn correct_set_by_number(&self, parent_block: BlockNumber) -> &ValidatorSet {
|
||||
let (block, set) = self.sets.iter()
|
||||
.rev()
|
||||
.find(|&(block, _)| *block <= parent_block + 1)
|
||||
.expect("constructor validation ensures that there is at least one validator set for block 0;
|
||||
block 0 is less than any uint;
|
||||
qed");
|
||||
|
||||
trace!(target: "engine", "Multi ValidatorSet retrieved for block {}.", block);
|
||||
&**set
|
||||
}
|
||||
}
|
||||
|
||||
impl ValidatorSet for Multi {
|
||||
@ -72,6 +72,16 @@ impl ValidatorSet for Multi {
|
||||
.unwrap_or(Box::new(|_, _| Err("No validator set for given ID.".into())))
|
||||
}
|
||||
|
||||
fn proof_required(&self, header: &Header, block: Option<&[u8]>, receipts: Option<&[::receipt::Receipt]>)
|
||||
-> RequiresProof
|
||||
{
|
||||
self.correct_set_by_number(header.number()).proof_required(header, block, receipts)
|
||||
}
|
||||
|
||||
fn generate_proof(&self, header: &Header, caller: &Call) -> Result<Vec<u8>, String> {
|
||||
self.correct_set_by_number(header.number()).generate_proof(header, caller)
|
||||
}
|
||||
|
||||
fn contains_with_caller(&self, bh: &H256, address: &Address, caller: &Call) -> bool {
|
||||
self.correct_set(BlockId::Hash(*bh))
|
||||
.map_or(false, |set| set.contains_with_caller(bh, address, caller))
|
||||
|
@ -26,6 +26,7 @@ use util::cache::MemoryLruCache;
|
||||
use engines::Call;
|
||||
use types::ids::BlockId;
|
||||
use client::{Client, BlockChainClient};
|
||||
use header::Header;
|
||||
|
||||
use super::ValidatorSet;
|
||||
use super::simple_list::SimpleList;
|
||||
@ -74,6 +75,19 @@ impl ValidatorSet for ValidatorSafeContract {
|
||||
.and_then(|c| c.call_contract(id, addr, data)))
|
||||
}
|
||||
|
||||
fn proof_required(&self, header: &Header, block: Option<&[u8]>, receipts: Option<&[::receipt::Receipt]>)
|
||||
-> ::engines::RequiresProof
|
||||
{
|
||||
// TODO: check blooms first and then logs for the
|
||||
// ValidatorsChanged([parent_hash, nonce], new_validators) log event.
|
||||
::engines::RequiresProof::No
|
||||
}
|
||||
|
||||
fn generate_proof(&self, header: &Header, caller: &Call) -> Result<Vec<u8>, String> {
|
||||
self.get_list(caller).map(|list| ::rlp::encode_list(&list.into_inner()).to_vec())
|
||||
.ok_or_else(|| "Caller insufficient to get validator list.".into())
|
||||
}
|
||||
|
||||
fn contains_with_caller(&self, block_hash: &H256, address: &Address, caller: &Call) -> bool {
|
||||
let mut guard = self.validators.write();
|
||||
let maybe_existing = guard
|
||||
|
@ -19,6 +19,7 @@
|
||||
use util::{H256, Address, HeapSizeOf};
|
||||
|
||||
use engines::Call;
|
||||
use header::Header;
|
||||
use super::ValidatorSet;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Default)]
|
||||
@ -27,11 +28,17 @@ pub struct SimpleList {
|
||||
}
|
||||
|
||||
impl SimpleList {
|
||||
/// Create a new `SimpleList`.
|
||||
pub fn new(validators: Vec<Address>) -> Self {
|
||||
SimpleList {
|
||||
validators: validators,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert into inner representation.
|
||||
pub fn into_inner(self) -> Vec<Address> {
|
||||
self.validators
|
||||
}
|
||||
}
|
||||
|
||||
impl HeapSizeOf for SimpleList {
|
||||
@ -45,6 +52,16 @@ impl ValidatorSet for SimpleList {
|
||||
Box::new(|_, _| Err("Simple list doesn't require calls.".into()))
|
||||
}
|
||||
|
||||
fn proof_required(&self, _header: &Header, _block: Option<&[u8]>, _receipts: Option<&[::receipt::Receipt]>)
|
||||
-> ::engines::RequiresProof
|
||||
{
|
||||
::engines::RequiresProof::No
|
||||
}
|
||||
|
||||
fn generate_proof(&self, _header: &Header, _caller: &Call) -> Result<Vec<u8>, String> {
|
||||
Ok(Vec::new())
|
||||
}
|
||||
|
||||
fn contains_with_caller(&self, _bh: &H256, address: &Address, _: &Call) -> bool {
|
||||
self.validators.contains(address)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user