skeleton for proof checking

This commit is contained in:
Robert Habermeier
2017-04-12 18:55:38 +02:00
parent ec922ee5e4
commit 34a1512ff0
8 changed files with 131 additions and 27 deletions

View File

@@ -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)
}

View File

@@ -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;

View File

@@ -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))

View File

@@ -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

View File

@@ -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)
}