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 account_provider::AccountProvider;
|
||||||
use block::*;
|
use block::*;
|
||||||
use spec::CommonParams;
|
use spec::CommonParams;
|
||||||
use engines::{Engine, Seal, EngineError};
|
use engines::{Call, Engine, Seal, EngineError};
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use error::{Error, TransactionError, BlockError};
|
use error::{Error, TransactionError, BlockError};
|
||||||
use evm::Schedule;
|
use evm::Schedule;
|
||||||
@ -358,6 +358,18 @@ impl Engine for AuthorityRound {
|
|||||||
Ok(())
|
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> {
|
fn verify_transaction_basic(&self, t: &UnverifiedTransaction, header: &Header) -> result::Result<(), Error> {
|
||||||
t.check_low_s()?;
|
t.check_low_s()?;
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ use account_provider::AccountProvider;
|
|||||||
use block::*;
|
use block::*;
|
||||||
use builtin::Builtin;
|
use builtin::Builtin;
|
||||||
use spec::CommonParams;
|
use spec::CommonParams;
|
||||||
use engines::{Engine, Seal};
|
use engines::{Engine, EngineError, Seal, Call, RequiresProof};
|
||||||
use env_info::EnvInfo;
|
use env_info::EnvInfo;
|
||||||
use error::{BlockError, Error};
|
use error::{BlockError, Error};
|
||||||
use evm::Schedule;
|
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
|
/// Engine using `BasicAuthority`, trivial proof-of-authority consensus.
|
||||||
/// mainnet chains in the Olympic, Frontier and Homestead eras.
|
|
||||||
pub struct BasicAuthority {
|
pub struct BasicAuthority {
|
||||||
params: CommonParams,
|
params: CommonParams,
|
||||||
gas_limit_bound_divisor: U256,
|
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> {
|
fn verify_block_family(&self, header: &Header, parent: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
||||||
use rlp::UntrustedRlp;
|
use rlp::UntrustedRlp;
|
||||||
|
|
||||||
// Check if the signature belongs to a validator, can depend on parent state.
|
// Check if the signature belongs to a validator, can depend on parent state.
|
||||||
let sig = UntrustedRlp::new(&header.seal()[0]).as_val::<H520>()?;
|
let sig = UntrustedRlp::new(&header.seal()[0]).as_val::<H520>()?;
|
||||||
let signer = public_to_address(&recover(&sig.into(), &header.bare_hash())?);
|
let signer = public_to_address(&recover(&sig.into(), &header.bare_hash())?);
|
||||||
@ -164,6 +164,18 @@ impl Engine for BasicAuthority {
|
|||||||
Ok(())
|
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>) {
|
fn register_client(&self, client: Weak<Client>) {
|
||||||
self.validators.register_contract(client);
|
self.validators.register_contract(client);
|
||||||
}
|
}
|
||||||
|
@ -62,6 +62,8 @@ pub enum EngineError {
|
|||||||
UnexpectedMessage,
|
UnexpectedMessage,
|
||||||
/// Seal field has an unexpected size.
|
/// Seal field has an unexpected size.
|
||||||
BadSealFieldSize(OutOfBounds<usize>),
|
BadSealFieldSize(OutOfBounds<usize>),
|
||||||
|
/// Validation proof insufficient.
|
||||||
|
InsufficientProof(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for EngineError {
|
impl fmt::Display for EngineError {
|
||||||
@ -73,6 +75,7 @@ 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),
|
||||||
|
InsufficientProof(ref msg) => format!("Insufficient validation proof: {}", msg),
|
||||||
};
|
};
|
||||||
|
|
||||||
f.write_fmt(format_args!("Engine error ({})", msg))
|
f.write_fmt(format_args!("Engine error ({})", msg))
|
||||||
@ -99,8 +102,9 @@ pub enum RequiresProof {
|
|||||||
Unsure(Unsure),
|
Unsure(Unsure),
|
||||||
/// Validation proof not required.
|
/// Validation proof not required.
|
||||||
No,
|
No,
|
||||||
/// Validation proof required.
|
/// Validation proof required, and the expected output
|
||||||
Yes,
|
/// if it can be recovered.
|
||||||
|
Yes(Option<Bytes>),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// More data required to determine if a validation proof is required.
|
/// 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
|
/// 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.
|
/// 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> {
|
/// Must be called on blocks that have already passed basic verification.
|
||||||
Ok(())
|
///
|
||||||
|
/// 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.
|
/// 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
|
||||||
{
|
{
|
||||||
RequiresProof::No
|
RequiresProof::No
|
||||||
|
@ -25,6 +25,7 @@ use native_contracts::ValidatorReport as Provider;
|
|||||||
|
|
||||||
use client::{Client, BlockChainClient};
|
use client::{Client, BlockChainClient};
|
||||||
use engines::Call;
|
use engines::Call;
|
||||||
|
use header::Header;
|
||||||
|
|
||||||
use super::ValidatorSet;
|
use super::ValidatorSet;
|
||||||
use super::safe_contract::ValidatorSafeContract;
|
use super::safe_contract::ValidatorSafeContract;
|
||||||
@ -65,6 +66,16 @@ impl ValidatorSet for ValidatorContract {
|
|||||||
self.validators.default_caller(id)
|
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 {
|
fn contains_with_caller(&self, bh: &H256, address: &Address, caller: &Call) -> bool {
|
||||||
self.validators.contains_with_caller(bh, address, caller)
|
self.validators.contains_with_caller(bh, address, caller)
|
||||||
}
|
}
|
||||||
|
@ -26,6 +26,7 @@ use ids::BlockId;
|
|||||||
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 header::Header;
|
||||||
|
|
||||||
use self::simple_list::SimpleList;
|
use self::simple_list::SimpleList;
|
||||||
use self::contract::ValidatorContract;
|
use self::contract::ValidatorContract;
|
||||||
@ -47,9 +48,10 @@ pub fn new_validator_set(spec: ValidatorSpec) -> Box<ValidatorSet> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A validator set.
|
/// A validator set.
|
||||||
// TODO [keorn]: remove internal callers.
|
|
||||||
pub trait ValidatorSet: Send + Sync {
|
pub trait ValidatorSet: Send + Sync {
|
||||||
/// Get the default "Call" helper, for use in general operation.
|
/// 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>;
|
fn default_caller(&self, block_id: BlockId) -> Box<Call>;
|
||||||
|
|
||||||
/// Checks if a given address is a validator,
|
/// 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));
|
let default = self.default_caller(BlockId::Hash(*parent));
|
||||||
self.get_with_caller(parent, nonce, &*default)
|
self.get_with_caller(parent, nonce, &*default)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the current number of validators.
|
/// Returns the current number of validators.
|
||||||
fn count(&self, parent: &H256) -> usize {
|
fn count(&self, parent: &H256) -> usize {
|
||||||
let default = self.default_caller(BlockId::Hash(*parent));
|
let default = self.default_caller(BlockId::Hash(*parent));
|
||||||
self.count_with_caller(parent, &*default)
|
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
|
/// Checks if a given address is a validator, with the given function
|
||||||
/// for executing synchronous calls to contracts.
|
/// for executing synchronous calls to contracts.
|
||||||
fn contains_with_caller(&self, parent_block_hash: &H256, address: &Address, caller: &Call) -> bool;
|
fn contains_with_caller(&self, parent_block_hash: &H256, address: &Address, caller: &Call) -> bool;
|
||||||
|
@ -18,10 +18,10 @@
|
|||||||
|
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::Weak;
|
use std::sync::Weak;
|
||||||
use engines::Call;
|
use engines::{Call, RequiresProof};
|
||||||
use util::{H256, Address, RwLock};
|
use util::{H256, Address, RwLock};
|
||||||
use ids::BlockId;
|
use ids::BlockId;
|
||||||
use header::BlockNumber;
|
use header::{BlockNumber, Header};
|
||||||
use client::{Client, BlockChainClient};
|
use client::{Client, BlockChainClient};
|
||||||
use super::ValidatorSet;
|
use super::ValidatorSet;
|
||||||
|
|
||||||
@ -42,21 +42,9 @@ impl Multi {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn correct_set(&self, id: BlockId) -> Option<&ValidatorSet> {
|
fn correct_set(&self, id: BlockId) -> Option<&ValidatorSet> {
|
||||||
match self
|
match self.block_number.read()(id).map(|parent_block| self.correct_set_by_number(parent_block)) {
|
||||||
.block_number
|
Ok(set) => {
|
||||||
.read()(id)
|
Some(set)
|
||||||
.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)
|
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
debug!(target: "engine", "ValidatorSet could not be recovered: {}", 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 {
|
impl ValidatorSet for Multi {
|
||||||
@ -72,6 +72,16 @@ impl ValidatorSet for Multi {
|
|||||||
.unwrap_or(Box::new(|_, _| Err("No validator set for given ID.".into())))
|
.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 {
|
fn contains_with_caller(&self, bh: &H256, address: &Address, caller: &Call) -> bool {
|
||||||
self.correct_set(BlockId::Hash(*bh))
|
self.correct_set(BlockId::Hash(*bh))
|
||||||
.map_or(false, |set| set.contains_with_caller(bh, address, caller))
|
.map_or(false, |set| set.contains_with_caller(bh, address, caller))
|
||||||
|
@ -26,6 +26,7 @@ use util::cache::MemoryLruCache;
|
|||||||
use engines::Call;
|
use engines::Call;
|
||||||
use types::ids::BlockId;
|
use types::ids::BlockId;
|
||||||
use client::{Client, BlockChainClient};
|
use client::{Client, BlockChainClient};
|
||||||
|
use header::Header;
|
||||||
|
|
||||||
use super::ValidatorSet;
|
use super::ValidatorSet;
|
||||||
use super::simple_list::SimpleList;
|
use super::simple_list::SimpleList;
|
||||||
@ -74,6 +75,19 @@ impl ValidatorSet for ValidatorSafeContract {
|
|||||||
.and_then(|c| c.call_contract(id, addr, data)))
|
.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 {
|
fn contains_with_caller(&self, block_hash: &H256, address: &Address, caller: &Call) -> bool {
|
||||||
let mut guard = self.validators.write();
|
let mut guard = self.validators.write();
|
||||||
let maybe_existing = guard
|
let maybe_existing = guard
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
use util::{H256, Address, HeapSizeOf};
|
use util::{H256, Address, HeapSizeOf};
|
||||||
|
|
||||||
use engines::Call;
|
use engines::Call;
|
||||||
|
use header::Header;
|
||||||
use super::ValidatorSet;
|
use super::ValidatorSet;
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Eq, Default)]
|
#[derive(Debug, PartialEq, Eq, Default)]
|
||||||
@ -27,11 +28,17 @@ pub struct SimpleList {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SimpleList {
|
impl SimpleList {
|
||||||
|
/// Create a new `SimpleList`.
|
||||||
pub fn new(validators: Vec<Address>) -> Self {
|
pub fn new(validators: Vec<Address>) -> Self {
|
||||||
SimpleList {
|
SimpleList {
|
||||||
validators: validators,
|
validators: validators,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convert into inner representation.
|
||||||
|
pub fn into_inner(self) -> Vec<Address> {
|
||||||
|
self.validators
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HeapSizeOf for SimpleList {
|
impl HeapSizeOf for SimpleList {
|
||||||
@ -45,6 +52,16 @@ impl ValidatorSet for SimpleList {
|
|||||||
Box::new(|_, _| Err("Simple list doesn't require calls.".into()))
|
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 {
|
fn contains_with_caller(&self, _bh: &H256, address: &Address, _: &Call) -> bool {
|
||||||
self.validators.contains(address)
|
self.validators.contains(address)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user