use native contracts in ValidatorSet
				
					
				
			This commit is contained in:
		
							parent
							
								
									2f5a774325
								
							
						
					
					
						commit
						0f80c57dca
					
				| @ -46,7 +46,7 @@ pub fn generate_module(struct_name: &str, abi: &str) -> Result<String, Error> { | ||||
| 
 | ||||
| 	Ok(format!(r##" | ||||
| use byteorder::{{BigEndian, ByteOrder}}; | ||||
| use futures::{{future, Future, BoxFuture}}; | ||||
| use futures::{{future, Future, IntoFuture, BoxFuture}}; | ||||
| use ethabi::{{Contract, Interface, Token}}; | ||||
| use util::{{self, Uint}}; | ||||
| 
 | ||||
| @ -99,7 +99,10 @@ fn generate_functions(contract: &Contract) -> Result<String, Error> { | ||||
| /// Inputs: {abi_inputs:?}
 | ||||
| /// Outputs: {abi_outputs:?}
 | ||||
| pub fn {snake_name}<F, U>(&self, call: F, {params}) -> BoxFuture<{output_type}, String> | ||||
| 	where F: Fn(util::Address, Vec<u8>) -> U, U: Future<Item=Vec<u8>, Error=String> + Send + 'static | ||||
| 	where | ||||
| 	    F: Fn(util::Address, Vec<u8>) -> U, | ||||
| 	    U: IntoFuture<Item=Vec<u8>, Error=String>, | ||||
| 		U::Future: Send + 'static | ||||
| {{ | ||||
| 	let function = self.contract.function(r#"{abi_name}"#.to_string()) | ||||
| 		.expect("function existence checked at compile-time; qed"); | ||||
| @ -111,6 +114,7 @@ pub fn {snake_name}<F, U>(&self, call: F, {params}) -> BoxFuture<{output_type}, | ||||
| 	}}; | ||||
| 
 | ||||
| 	call_future | ||||
| 		.into_future() | ||||
| 		.and_then(move |out| function.decode_output(out).map_err(|e| format!("{{:?}}", e))) | ||||
| 		.map(::std::collections::VecDeque::from) | ||||
| 		.and_then(|mut outputs| {decode_outputs}) | ||||
|  | ||||
							
								
								
									
										22
									
								
								ethcore/native_contracts/src/validator_report.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								ethcore/native_contracts/src/validator_report.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| // Copyright 2015-2017 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| 
 | ||||
| // Parity is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||
| // GNU General Public License for more details.
 | ||||
| 
 | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| #![allow(unused_mut, unused_variables, unused_imports)] | ||||
| 
 | ||||
| //! Validator reporting.
 | ||||
| // TODO: testing.
 | ||||
| 
 | ||||
| include!(concat!(env!("OUT_DIR"), "/validator_report.rs")); | ||||
							
								
								
									
										22
									
								
								ethcore/native_contracts/src/validator_set.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								ethcore/native_contracts/src/validator_set.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,22 @@ | ||||
| // Copyright 2015-2017 Parity Technologies (UK) Ltd.
 | ||||
| // This file is part of Parity.
 | ||||
| 
 | ||||
| // Parity is free software: you can redistribute it and/or modify
 | ||||
| // it under the terms of the GNU General Public License as published by
 | ||||
| // the Free Software Foundation, either version 3 of the License, or
 | ||||
| // (at your option) any later version.
 | ||||
| 
 | ||||
| // Parity is distributed in the hope that it will be useful,
 | ||||
| // but WITHOUT ANY WARRANTY; without even the implied warranty of
 | ||||
| // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | ||||
| // GNU General Public License for more details.
 | ||||
| 
 | ||||
| // You should have received a copy of the GNU General Public License
 | ||||
| // along with Parity.  If not, see <http://www.gnu.org/licenses/>.
 | ||||
| 
 | ||||
| #![allow(unused_mut, unused_variables, unused_imports)] | ||||
| 
 | ||||
| //! Validator set contract.
 | ||||
| // TODO: testing.
 | ||||
| 
 | ||||
| include!(concat!(env!("OUT_DIR"), "/validator_set.rs")); | ||||
| @ -18,27 +18,46 @@ | ||||
| /// 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 native_contracts::ValidatorReport as Provider; | ||||
| 
 | ||||
| use super::ValidatorSet; | ||||
| use super::safe_contract::ValidatorSafeContract; | ||||
| 
 | ||||
| /// The validator contract should have the following interface:
 | ||||
| /// [{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}]
 | ||||
| /// A validator contract with reporting.
 | ||||
| pub struct ValidatorContract { | ||||
| 	validators: ValidatorSafeContract, | ||||
| 	provider: RwLock<Option<provider::Contract>>, | ||||
| 	provider: Provider, | ||||
| 	client: RwLock<Option<Weak<Client>>>, // TODO [keorn]: remove
 | ||||
| } | ||||
| 
 | ||||
| impl ValidatorContract { | ||||
| 	pub fn new(contract_address: Address) -> Self { | ||||
| 		ValidatorContract { | ||||
| 			validators: ValidatorSafeContract::new(contract_address), | ||||
| 			provider: RwLock::new(None), | ||||
| 			provider: Provider::new(contract_address), | ||||
| 			client: RwLock::new(None), | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| 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>> { | ||||
| 		let client = self.client.read().clone(); | ||||
| 		Box::new(move |a, d| client.as_ref() | ||||
| 			.and_then(Weak::upgrade) | ||||
| 			.ok_or("No client!".into()) | ||||
| 			.and_then(|c| c.transact_contract(a, d).map_err(|e| format!("Transaction import error: {}", e))) | ||||
| 			.map(|_| Default::default())) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl ValidatorSet for ValidatorContract { | ||||
| 	fn contains(&self, bh: &H256, address: &Address) -> bool { | ||||
| 		self.validators.contains(bh, address) | ||||
| @ -53,85 +72,22 @@ impl ValidatorSet for ValidatorContract { | ||||
| 	} | ||||
| 
 | ||||
| 	fn report_malicious(&self, address: &Address) { | ||||
| 		if let Some(ref provider) = *self.provider.read() { | ||||
| 			match provider.report_malicious(address) { | ||||
| 				Ok(_) => warn!(target: "engine", "Reported malicious validator {}", address), | ||||
| 				Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s), | ||||
| 			} | ||||
| 		} else { | ||||
| 			warn!(target: "engine", "Malicious behaviour could not be reported: no provider contract.") | ||||
| 		match self.provider.report_malicious(&*self.transact(), *address).wait() { | ||||
| 			Ok(_) => warn!(target: "engine", "Reported malicious validator {}", address), | ||||
| 			Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn report_benign(&self, address: &Address) { | ||||
| 		if let Some(ref provider) = *self.provider.read() { | ||||
| 			match provider.report_benign(address) { | ||||
| 				Ok(_) => warn!(target: "engine", "Reported benign validator misbehaviour {}", address), | ||||
| 				Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s), | ||||
| 			} | ||||
| 		} else { | ||||
| 			warn!(target: "engine", "Benign misbehaviour could not be reported: no provider contract.") | ||||
| 		match self.provider.report_benign(&*self.transact(), *address).wait() { | ||||
| 			Ok(_) => warn!(target: "engine", "Reported benign validator misbehaviour {}", address), | ||||
| 			Err(s) => warn!(target: "engine", "Validator {} could not be reported {}", address, s), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	fn register_contract(&self, client: Weak<Client>) { | ||||
| 		self.validators.register_contract(client.clone()); | ||||
| 		let transact = move |a, d| client | ||||
| 			.upgrade() | ||||
| 			.ok_or("No client!".into()) | ||||
| 			.and_then(|c| c.transact_contract(a, d).map_err(|e| format!("Transaction import error: {}", e))) | ||||
| 			.map(|_| Default::default()); | ||||
| 		*self.provider.write() = Some(provider::Contract::new(self.validators.address, transact)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| mod provider { | ||||
| 	// Autogenerated from JSON contract definition using Rust contract convertor.
 | ||||
| 	#![allow(unused_imports)] | ||||
| 	use std::string::String; | ||||
| 	use std::result::Result; | ||||
| 	use std::fmt; | ||||
| 	use {util, ethabi}; | ||||
| 	use util::{Uint}; | ||||
| 
 | ||||
| 	pub struct Contract { | ||||
| 		contract: ethabi::Contract, | ||||
| 		address: util::Address, | ||||
| 		do_call: Box<Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send + Sync + 'static>, | ||||
| 	} | ||||
| 	impl Contract { | ||||
| 		pub fn new<F>(address: util::Address, do_call: F) -> Self where F: Fn(util::Address, Vec<u8>) -> Result<Vec<u8>, String> + Send + Sync + 'static { | ||||
| 			Contract { | ||||
| 				contract: ethabi::Contract::new(ethabi::Interface::load(b"[{\"constant\":false,\"inputs\":[{\"name\":\"validator\",\"type\":\"address\"}],\"name\":\"reportMalicious\",\"outputs\":[],\"payable\":false,\"type\":\"function\"},{\"constant\":false,\"inputs\":[{\"name\":\"validator\",\"type\":\"address\"}],\"name\":\"reportBenign\",\"outputs\":[],\"payable\":false,\"type\":\"function\"}]").expect("JSON is autogenerated; qed")), | ||||
| 				address: address, | ||||
| 				do_call: Box::new(do_call), | ||||
| 			} | ||||
| 		} | ||||
| 		fn as_string<T: fmt::Debug>(e: T) -> String { format!("{:?}", e) } | ||||
| 
 | ||||
| 		/// Auto-generated from: `{"constant":false,"inputs":[{"name":"validator","type":"address"}],"name":"reportMalicious","outputs":[],"payable":false,"type":"function"}`
 | ||||
| 		#[allow(dead_code)] | ||||
| 		pub fn report_malicious(&self, validator: &util::Address) -> Result<(), String> { | ||||
| 			let call = self.contract.function("reportMalicious".into()).map_err(Self::as_string)?; | ||||
| 			let data = call.encode_call( | ||||
| 				vec![ethabi::Token::Address(validator.clone().0)] | ||||
| 			).map_err(Self::as_string)?; | ||||
| 			call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; | ||||
| 
 | ||||
| 			Ok(()) | ||||
| 		} | ||||
| 
 | ||||
| 		/// Auto-generated from: `{"constant":false,"inputs":[{"name":"validator","type":"address"}],"name":"reportBenign","outputs":[],"payable":false,"type":"function"}`
 | ||||
| 		#[allow(dead_code)] | ||||
| 		pub fn report_benign(&self, validator: &util::Address) -> Result<(), String> { | ||||
| 			let call = self.contract.function("reportBenign".into()).map_err(Self::as_string)?; | ||||
| 			let data = call.encode_call( | ||||
| 				vec![ethabi::Token::Address(validator.clone().0)] | ||||
| 			).map_err(Self::as_string)?; | ||||
| 			call.decode_output((self.do_call)(self.address.clone(), data)?).map_err(Self::as_string)?; | ||||
| 
 | ||||
| 			Ok(()) | ||||
| 		} | ||||
| 		*self.client.write() = Some(client); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -17,24 +17,26 @@ | ||||
| /// Validator set maintained in a contract, updated using `getValidators` method.
 | ||||
| 
 | ||||
| use std::sync::Weak; | ||||
| use ethabi; | ||||
| use futures::Future; | ||||
| use native_contracts::ValidatorSet as Provider; | ||||
| 
 | ||||
| use util::*; | ||||
| use util::cache::MemoryLruCache; | ||||
| 
 | ||||
| use types::ids::BlockId; | ||||
| use client::{Client, BlockChainClient}; | ||||
| 
 | ||||
| use super::ValidatorSet; | ||||
| use super::simple_list::SimpleList; | ||||
| 
 | ||||
| const MEMOIZE_CAPACITY: usize = 500; | ||||
| const CONTRACT_INTERFACE: &'static [u8] = b"[{\"constant\":true,\"inputs\":[],\"name\":\"getValidators\",\"outputs\":[{\"name\":\"\",\"type\":\"address[]\"}],\"payable\":false,\"type\":\"function\"}]"; | ||||
| const GET_VALIDATORS: &'static str = "getValidators"; | ||||
| 
 | ||||
| /// The validator contract should have the following interface:
 | ||||
| /// [{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}]
 | ||||
| pub struct ValidatorSafeContract { | ||||
| 	pub address: Address, | ||||
| 	validators: RwLock<MemoryLruCache<H256, SimpleList>>, | ||||
| 	provider: RwLock<Option<provider::Contract>>, | ||||
| 	provider: Provider, | ||||
| 	client: RwLock<Option<Weak<Client>>>, // TODO [keorn]: remove
 | ||||
| } | ||||
| 
 | ||||
| impl ValidatorSafeContract { | ||||
| @ -42,26 +44,30 @@ impl ValidatorSafeContract { | ||||
| 		ValidatorSafeContract { | ||||
| 			address: contract_address, | ||||
| 			validators: RwLock::new(MemoryLruCache::new(MEMOIZE_CAPACITY)), | ||||
| 			provider: RwLock::new(None), | ||||
| 			provider: Provider::new(contract_address), | ||||
| 			client: RwLock::new(None), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	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> { | ||||
| 		if let Some(ref provider) = *self.provider.read() { | ||||
| 			match provider.get_validators(BlockId::Hash(block_hash)) { | ||||
| 				Ok(new) => { | ||||
| 					debug!(target: "engine", "Set of validators obtained: {:?}", new); | ||||
| 					Some(SimpleList::new(new)) | ||||
| 				}, | ||||
| 				Err(s) => { | ||||
| 					debug!(target: "engine", "Set of validators could not be updated: {}", s); | ||||
| 					None | ||||
| 				}, | ||||
| 			} | ||||
| 		} else { | ||||
| 			warn!(target: "engine", "Set of validators could not be updated: no provider contract."); | ||||
| 			None | ||||
| 		match self.provider.get_validators(&*self.do_call(BlockId::Hash(block_hash))).wait() { | ||||
| 			Ok(new) => { | ||||
| 				debug!(target: "engine", "Set of validators obtained: {:?}", new); | ||||
| 				Some(SimpleList::new(new)) | ||||
| 			}, | ||||
| 			Err(s) => { | ||||
| 				debug!(target: "engine", "Set of validators could not be updated: {}", s); | ||||
| 				None | ||||
| 			}, | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| @ -114,55 +120,7 @@ impl ValidatorSet for ValidatorSafeContract { | ||||
| 
 | ||||
| 	fn register_contract(&self, client: Weak<Client>) { | ||||
| 		trace!(target: "engine", "Setting up contract caller."); | ||||
| 		let contract = ethabi::Contract::new(ethabi::Interface::load(CONTRACT_INTERFACE).expect("JSON interface is valid; qed")); | ||||
| 		let call = contract.function(GET_VALIDATORS.into()).expect("Method name is valid; qed"); | ||||
| 		let data = call.encode_call(vec![]).expect("get_validators does not take any arguments; qed"); | ||||
| 		let contract_address = self.address.clone(); | ||||
| 		let do_call = move |id| client | ||||
| 			.upgrade() | ||||
| 			.ok_or("No client!".into()) | ||||
| 			.and_then(|c| c.call_contract(id, contract_address.clone(), data.clone())) | ||||
| 			.map(|raw_output| call.decode_output(raw_output).expect("ethabi is correct; qed")); | ||||
| 		*self.provider.write() = Some(provider::Contract::new(do_call)); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| mod provider { | ||||
| 	use std::string::String; | ||||
| 	use std::result::Result; | ||||
| 	use {util, ethabi}; | ||||
| 	use types::ids::BlockId; | ||||
| 
 | ||||
| 	pub struct Contract { | ||||
| 		do_call: Box<Fn(BlockId) -> Result<Vec<ethabi::Token>, String> + Send + Sync + 'static>, | ||||
| 	} | ||||
| 
 | ||||
| 	impl Contract { | ||||
| 		pub fn new<F>(do_call: F) -> Self where F: Fn(BlockId) -> Result<Vec<ethabi::Token>, String> + Send + Sync + 'static { | ||||
| 			Contract { | ||||
| 				do_call: Box::new(do_call), | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		/// Gets validators from contract with interface: `{"constant":true,"inputs":[],"name":"getValidators","outputs":[{"name":"","type":"address[]"}],"payable":false,"type":"function"}`
 | ||||
| 		pub fn get_validators(&self, id: BlockId) -> Result<Vec<util::Address>, String> { | ||||
| 			Ok((self.do_call)(id)? | ||||
| 				 .into_iter() | ||||
| 				 .rev() | ||||
| 				 .collect::<Vec<_>>() | ||||
| 				 .pop() | ||||
| 				 .expect("get_validators returns one argument; qed") | ||||
| 				 .to_array() | ||||
| 				 .and_then(|v| v | ||||
| 					 .into_iter() | ||||
| 					 .map(|a| a.to_address()) | ||||
| 					 .collect::<Option<Vec<[u8; 20]>>>()) | ||||
| 				 .expect("get_validators returns a list of addresses; qed") | ||||
| 				 .into_iter() | ||||
| 				 .map(util::Address::from) | ||||
| 				 .collect::<Vec<_>>() | ||||
| 			) | ||||
| 		} | ||||
| 		*self.client.write() = Some(client); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user