supply optional call context to validator sets
This commit is contained in:
parent
0f80c57dca
commit
ec922ee5e4
@ -18,12 +18,14 @@
|
||||
/// It can also report validators for misbehaviour with two levels: `reportMalicious` and `reportBenign`.
|
||||
|
||||
use std::sync::Weak;
|
||||
use futures::Future;
|
||||
use util::*;
|
||||
use client::{Client, BlockChainClient};
|
||||
|
||||
use futures::Future;
|
||||
use native_contracts::ValidatorReport as Provider;
|
||||
|
||||
use client::{Client, BlockChainClient};
|
||||
use engines::Call;
|
||||
|
||||
use super::ValidatorSet;
|
||||
use super::safe_contract::ValidatorSafeContract;
|
||||
|
||||
@ -48,7 +50,7 @@ impl ValidatorContract {
|
||||
// could be `impl Trait`.
|
||||
// note: dispatches transactions to network as well as execute.
|
||||
// TODO [keorn]: Make more general.
|
||||
fn transact(&self) -> Box<Fn(Address, Vec<u8>) -> Result<Vec<u8>, String>> {
|
||||
fn transact(&self) -> Box<Call> {
|
||||
let client = self.client.read().clone();
|
||||
Box::new(move |a, d| client.as_ref()
|
||||
.and_then(Weak::upgrade)
|
||||
@ -59,16 +61,20 @@ impl ValidatorContract {
|
||||
}
|
||||
|
||||
impl ValidatorSet for ValidatorContract {
|
||||
fn contains(&self, bh: &H256, address: &Address) -> bool {
|
||||
self.validators.contains(bh, address)
|
||||
fn default_caller(&self, id: ::ids::BlockId) -> Box<Call> {
|
||||
self.validators.default_caller(id)
|
||||
}
|
||||
|
||||
fn get(&self, bh: &H256, nonce: usize) -> Address {
|
||||
self.validators.get(bh, nonce)
|
||||
fn contains_with_caller(&self, bh: &H256, address: &Address, caller: &Call) -> bool {
|
||||
self.validators.contains_with_caller(bh, address, caller)
|
||||
}
|
||||
|
||||
fn count(&self, bh: &H256) -> usize {
|
||||
self.validators.count(bh)
|
||||
fn get_with_caller(&self, bh: &H256, nonce: usize, caller: &Call) -> Address {
|
||||
self.validators.get_with_caller(bh, nonce, caller)
|
||||
}
|
||||
|
||||
fn count_with_caller(&self, bh: &H256, caller: &Call) -> usize {
|
||||
self.validators.count_with_caller(bh, caller)
|
||||
}
|
||||
|
||||
fn report_malicious(&self, address: &Address) {
|
||||
|
@ -22,6 +22,7 @@ mod contract;
|
||||
mod multi;
|
||||
|
||||
use std::sync::Weak;
|
||||
use ids::BlockId;
|
||||
use util::{Address, H256};
|
||||
use ethjson::spec::ValidatorSet as ValidatorSpec;
|
||||
use client::Client;
|
||||
@ -31,6 +32,8 @@ use self::contract::ValidatorContract;
|
||||
use self::safe_contract::ValidatorSafeContract;
|
||||
use self::multi::Multi;
|
||||
|
||||
use super::Call;
|
||||
|
||||
/// Creates a validator set from spec.
|
||||
pub fn new_validator_set(spec: ValidatorSpec) -> Box<ValidatorSet> {
|
||||
match spec {
|
||||
@ -44,13 +47,39 @@ pub fn new_validator_set(spec: ValidatorSpec) -> Box<ValidatorSet> {
|
||||
}
|
||||
|
||||
/// A validator set.
|
||||
// TODO [keorn]: remove internal callers.
|
||||
pub trait ValidatorSet: Send + Sync {
|
||||
/// Checks if a given address is a validator.
|
||||
fn contains(&self, parent_block_hash: &H256, address: &Address) -> bool;
|
||||
/// Get the default "Call" helper, for use in general operation.
|
||||
fn default_caller(&self, block_id: BlockId) -> Box<Call>;
|
||||
|
||||
/// Checks if a given address is a validator,
|
||||
/// using underlying, default call mechanism.
|
||||
fn contains(&self, parent: &H256, address: &Address) -> bool {
|
||||
let default = self.default_caller(BlockId::Hash(*parent));
|
||||
self.contains_with_caller(parent, address, &*default)
|
||||
}
|
||||
/// Draws an validator nonce modulo number of validators.
|
||||
fn get(&self, parent_block_hash: &H256, nonce: usize) -> Address;
|
||||
fn get(&self, parent: &H256, nonce: usize) -> Address {
|
||||
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_block_hash: &H256) -> usize;
|
||||
fn count(&self, parent: &H256) -> usize {
|
||||
let default = self.default_caller(BlockId::Hash(*parent));
|
||||
self.count_with_caller(parent, &*default)
|
||||
}
|
||||
|
||||
/// 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;
|
||||
|
||||
/// Draws an validator nonce modulo number of validators.
|
||||
///
|
||||
fn get_with_caller(&self, parent_block_hash: &H256, nonce: usize, caller: &Call) -> Address;
|
||||
|
||||
/// Returns the current number of validators.
|
||||
fn count_with_caller(&self, parent_block_hash: &H256, caller: &Call) -> usize;
|
||||
|
||||
/// Notifies about malicious behaviour.
|
||||
fn report_malicious(&self, _validator: &Address) {}
|
||||
/// Notifies about benign misbehaviour.
|
||||
|
@ -18,13 +18,14 @@
|
||||
|
||||
use std::collections::BTreeMap;
|
||||
use std::sync::Weak;
|
||||
use engines::Call;
|
||||
use util::{H256, Address, RwLock};
|
||||
use ids::BlockId;
|
||||
use header::BlockNumber;
|
||||
use client::{Client, BlockChainClient};
|
||||
use super::ValidatorSet;
|
||||
|
||||
type BlockNumberLookup = Box<Fn(&H256) -> Result<BlockNumber, String> + Send + Sync + 'static>;
|
||||
type BlockNumberLookup = Box<Fn(BlockId) -> Result<BlockNumber, String> + Send + Sync + 'static>;
|
||||
|
||||
pub struct Multi {
|
||||
sets: BTreeMap<BlockNumber, Box<ValidatorSet>>,
|
||||
@ -40,10 +41,10 @@ impl Multi {
|
||||
}
|
||||
}
|
||||
|
||||
fn correct_set(&self, bh: &H256) -> Option<&ValidatorSet> {
|
||||
fn correct_set(&self, id: BlockId) -> Option<&ValidatorSet> {
|
||||
match self
|
||||
.block_number
|
||||
.read()(bh)
|
||||
.read()(id)
|
||||
.map(|parent_block| self
|
||||
.sets
|
||||
.iter()
|
||||
@ -66,16 +67,24 @@ impl Multi {
|
||||
}
|
||||
|
||||
impl ValidatorSet for Multi {
|
||||
fn contains(&self, bh: &H256, address: &Address) -> bool {
|
||||
self.correct_set(bh).map_or(false, |set| set.contains(bh, address))
|
||||
fn default_caller(&self, block_id: BlockId) -> Box<Call> {
|
||||
self.correct_set(block_id).map(|set| set.default_caller(block_id))
|
||||
.unwrap_or(Box::new(|_, _| Err("No validator set for given ID.".into())))
|
||||
}
|
||||
|
||||
fn get(&self, bh: &H256, nonce: usize) -> Address {
|
||||
self.correct_set(bh).map_or_else(Default::default, |set| set.get(bh, nonce))
|
||||
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))
|
||||
}
|
||||
|
||||
fn count(&self, bh: &H256) -> usize {
|
||||
self.correct_set(bh).map_or_else(usize::max_value, |set| set.count(bh))
|
||||
fn get_with_caller(&self, bh: &H256, nonce: usize, caller: &Call) -> Address {
|
||||
self.correct_set(BlockId::Hash(*bh))
|
||||
.map_or_else(Default::default, |set| set.get_with_caller(bh, nonce, caller))
|
||||
}
|
||||
|
||||
fn count_with_caller(&self, bh: &H256, caller: &Call) -> usize {
|
||||
self.correct_set(BlockId::Hash(*bh))
|
||||
.map_or_else(usize::max_value, |set| set.count_with_caller(bh, caller))
|
||||
}
|
||||
|
||||
fn report_malicious(&self, validator: &Address) {
|
||||
@ -94,10 +103,10 @@ impl ValidatorSet for Multi {
|
||||
for set in self.sets.values() {
|
||||
set.register_contract(client.clone());
|
||||
}
|
||||
*self.block_number.write() = Box::new(move |hash| client
|
||||
*self.block_number.write() = Box::new(move |id| client
|
||||
.upgrade()
|
||||
.ok_or("No client!".into())
|
||||
.and_then(|c| c.block_number(BlockId::Hash(*hash)).ok_or("Unknown block".into())));
|
||||
.and_then(|c| c.block_number(id).ok_or("Unknown block".into())));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,6 +23,7 @@ use native_contracts::ValidatorSet as Provider;
|
||||
use util::*;
|
||||
use util::cache::MemoryLruCache;
|
||||
|
||||
use engines::Call;
|
||||
use types::ids::BlockId;
|
||||
use client::{Client, BlockChainClient};
|
||||
|
||||
@ -49,17 +50,9 @@ impl ValidatorSafeContract {
|
||||
}
|
||||
}
|
||||
|
||||
fn do_call(&self, id: BlockId) -> Box<Fn(Address, Vec<u8>) -> Result<Vec<u8>, String>> {
|
||||
let client = self.client.read().clone();
|
||||
Box::new(move |addr, data| client.as_ref()
|
||||
.and_then(Weak::upgrade)
|
||||
.ok_or("No client!".into())
|
||||
.and_then(|c| c.call_contract(id, addr, data)))
|
||||
}
|
||||
|
||||
/// Queries the state and gets the set of validators.
|
||||
fn get_list(&self, block_hash: H256) -> Option<SimpleList> {
|
||||
match self.provider.get_validators(&*self.do_call(BlockId::Hash(block_hash))).wait() {
|
||||
fn get_list(&self, caller: &Call) -> Option<SimpleList> {
|
||||
match self.provider.get_validators(caller).wait() {
|
||||
Ok(new) => {
|
||||
debug!(target: "engine", "Set of validators obtained: {:?}", new);
|
||||
Some(SimpleList::new(new))
|
||||
@ -73,14 +66,22 @@ impl ValidatorSafeContract {
|
||||
}
|
||||
|
||||
impl ValidatorSet for ValidatorSafeContract {
|
||||
fn contains(&self, block_hash: &H256, address: &Address) -> bool {
|
||||
fn default_caller(&self, id: BlockId) -> Box<Call> {
|
||||
let client = self.client.read().clone();
|
||||
Box::new(move |addr, data| client.as_ref()
|
||||
.and_then(Weak::upgrade)
|
||||
.ok_or("No client!".into())
|
||||
.and_then(|c| c.call_contract(id, addr, data)))
|
||||
}
|
||||
|
||||
fn contains_with_caller(&self, block_hash: &H256, address: &Address, caller: &Call) -> bool {
|
||||
let mut guard = self.validators.write();
|
||||
let maybe_existing = guard
|
||||
.get_mut(block_hash)
|
||||
.map(|list| list.contains(block_hash, address));
|
||||
maybe_existing
|
||||
.unwrap_or_else(|| self
|
||||
.get_list(block_hash.clone())
|
||||
.get_list(caller)
|
||||
.map_or(false, |list| {
|
||||
let contains = list.contains(block_hash, address);
|
||||
guard.insert(block_hash.clone(), list);
|
||||
@ -88,14 +89,14 @@ impl ValidatorSet for ValidatorSafeContract {
|
||||
}))
|
||||
}
|
||||
|
||||
fn get(&self, block_hash: &H256, nonce: usize) -> Address {
|
||||
fn get_with_caller(&self, block_hash: &H256, nonce: usize, caller: &Call) -> Address {
|
||||
let mut guard = self.validators.write();
|
||||
let maybe_existing = guard
|
||||
.get_mut(block_hash)
|
||||
.map(|list| list.get(block_hash, nonce));
|
||||
maybe_existing
|
||||
.unwrap_or_else(|| self
|
||||
.get_list(block_hash.clone())
|
||||
.get_list(caller)
|
||||
.map_or_else(Default::default, |list| {
|
||||
let address = list.get(block_hash, nonce);
|
||||
guard.insert(block_hash.clone(), list);
|
||||
@ -103,14 +104,14 @@ impl ValidatorSet for ValidatorSafeContract {
|
||||
}))
|
||||
}
|
||||
|
||||
fn count(&self, block_hash: &H256) -> usize {
|
||||
fn count_with_caller(&self, block_hash: &H256, caller: &Call) -> usize {
|
||||
let mut guard = self.validators.write();
|
||||
let maybe_existing = guard
|
||||
.get_mut(block_hash)
|
||||
.map(|list| list.count(block_hash));
|
||||
maybe_existing
|
||||
.unwrap_or_else(|| self
|
||||
.get_list(block_hash.clone())
|
||||
.get_list(caller)
|
||||
.map_or_else(usize::max_value, |list| {
|
||||
let address = list.count(block_hash);
|
||||
guard.insert(block_hash.clone(), list);
|
||||
|
@ -17,6 +17,8 @@
|
||||
/// Preconfigured validator list.
|
||||
|
||||
use util::{H256, Address, HeapSizeOf};
|
||||
|
||||
use engines::Call;
|
||||
use super::ValidatorSet;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Default)]
|
||||
@ -39,16 +41,20 @@ impl HeapSizeOf for SimpleList {
|
||||
}
|
||||
|
||||
impl ValidatorSet for SimpleList {
|
||||
fn contains(&self, _bh: &H256, address: &Address) -> bool {
|
||||
fn default_caller(&self, _block_id: ::ids::BlockId) -> Box<Call> {
|
||||
Box::new(|_, _| Err("Simple list doesn't require calls.".into()))
|
||||
}
|
||||
|
||||
fn contains_with_caller(&self, _bh: &H256, address: &Address, _: &Call) -> bool {
|
||||
self.validators.contains(address)
|
||||
}
|
||||
|
||||
fn get(&self, _bh: &H256, nonce: usize) -> Address {
|
||||
fn get_with_caller(&self, _bh: &H256, nonce: usize, _: &Call) -> Address {
|
||||
let validator_n = self.validators.len();
|
||||
self.validators.get(nonce % validator_n).expect("There are validator_n authorities; taking number modulo validator_n gives number in validator_n range; qed").clone()
|
||||
}
|
||||
|
||||
fn count(&self, _bh: &H256) -> usize {
|
||||
fn count_with_caller(&self, _bh: &H256, _: &Call) -> usize {
|
||||
self.validators.len()
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user