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