Engine and Spec are now thread safe
This commit is contained in:
		
							parent
							
								
									5d0e186632
								
							
						
					
					
						commit
						33d3a4d633
					
				
							
								
								
									
										0
									
								
								<std macros>
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										0
									
								
								<std macros>
									
									
									
									
									
										Normal file
									
								
							| @ -11,15 +11,16 @@ use util::network::{NetworkService}; | ||||
| use ethcore::client::Client; | ||||
| use ethcore::sync::EthSync; | ||||
| use ethcore::ethereum; | ||||
| use ethcore::ethereum::ethash::Ethash; | ||||
| 
 | ||||
| fn main() { | ||||
| 	::env_logger::init().ok(); | ||||
| 	let mut service = NetworkService::start().unwrap(); | ||||
| 	//TODO: replace with proper genesis and chain params.
 | ||||
| 	let frontier = ethereum::new_frontier(); | ||||
| 	let engine = Ethash::new_arc(ethereum::new_frontier()); | ||||
| 	let mut dir = env::temp_dir(); | ||||
| 	dir.push(H32::random().hex()); | ||||
| 	let client = Arc::new(Client::new(&frontier.genesis_block(), &dir)); | ||||
| 	let client = Arc::new(Client::new(engine, &dir)); | ||||
| 	EthSync::register(&mut service, client); | ||||
| 	loop { | ||||
| 		let mut cmd = String::new(); | ||||
|  | ||||
| @ -1,6 +1,5 @@ | ||||
| //! Fast access to blockchain data.
 | ||||
| 
 | ||||
| use std::sync::*; | ||||
| use util::*; | ||||
| use rocksdb::{DB, WriteBatch, Writable}; | ||||
| use header::*; | ||||
|  | ||||
| @ -12,6 +12,11 @@ pub struct Builtin { | ||||
| 	pub execute: Box<Fn(&[u8], &mut [u8])>, | ||||
| } | ||||
| 
 | ||||
| // Rust does not mark closurer that do not capture as Sync
 | ||||
| // We promise that all builtins are thread safe since they only operate on given input.
 | ||||
| unsafe impl Sync for Builtin {} | ||||
| unsafe impl Send for Builtin {} | ||||
| 
 | ||||
| impl fmt::Debug for Builtin { | ||||
| 	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | ||||
| 		write!(f, "<Builtin>") | ||||
|  | ||||
| @ -1,9 +1,9 @@ | ||||
| use std::sync::Arc; | ||||
| use util::*; | ||||
| use blockchain::BlockChain; | ||||
| use views::BlockView; | ||||
| use error::ImportError; | ||||
| use header::BlockNumber; | ||||
| use engine::Engine; | ||||
| 
 | ||||
| /// General block status
 | ||||
| pub enum BlockStatus { | ||||
| @ -95,13 +95,15 @@ pub trait BlockChainClient : Sync { | ||||
| /// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
 | ||||
| pub struct Client { | ||||
| 	chain: Arc<BlockChain>, | ||||
| 	_engine: Arc<Engine>, | ||||
| } | ||||
| 
 | ||||
| impl Client { | ||||
| 	pub fn new(genesis: &[u8], path: &Path) -> Client { | ||||
| 		let chain = Arc::new(BlockChain::new(genesis, path)); | ||||
| 	pub fn new(engine: Arc<Engine>, path: &Path) -> Client { | ||||
| 		let chain = Arc::new(BlockChain::new(&engine.spec().genesis_block(), path)); | ||||
| 		Client { | ||||
| 			chain: chain.clone(), | ||||
| 			_engine: engine.clone(), | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -4,7 +4,7 @@ use spec::Spec; | ||||
| 
 | ||||
| /// A consensus mechanism for the chain. Generally either proof-of-work or proof-of-stake-based.
 | ||||
| /// Provides hooks into each of the major parts of block import.
 | ||||
| pub trait Engine { | ||||
| pub trait Engine : Sync + Send { | ||||
| 	/// The name of this engine.
 | ||||
| 	fn name(&self) -> &str; | ||||
| 	/// The version of this engine. Should be of the form 
 | ||||
|  | ||||
| @ -13,6 +13,10 @@ impl Ethash { | ||||
| 	pub fn new_boxed(spec: Spec) -> Box<Engine> { | ||||
| 		Box::new(Ethash{spec: spec}) | ||||
| 	} | ||||
| 
 | ||||
| 	pub fn new_arc(spec: Spec) -> Arc<Engine> { | ||||
| 		Arc::new(Ethash{spec: spec}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| impl Engine for Ethash { | ||||
|  | ||||
| @ -52,7 +52,7 @@ mod tests { | ||||
| 	fn morden() { | ||||
| 		let morden = new_morden(); | ||||
| 
 | ||||
| 		assert_eq!(*morden.state_root(), H256::from_str("f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9").unwrap()); | ||||
| 		assert_eq!(morden.state_root(), H256::from_str("f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9").unwrap()); | ||||
| 		let genesis = morden.genesis_block(); | ||||
| 		assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap()); | ||||
| 
 | ||||
| @ -63,10 +63,10 @@ mod tests { | ||||
| 	fn frontier() { | ||||
| 		let frontier = new_frontier(); | ||||
| 
 | ||||
| 		assert_eq!(*frontier.state_root(), H256::from_str("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544").unwrap()); | ||||
| 		assert_eq!(frontier.state_root(), H256::from_str("d7f8974fb5ac78d9ac099b9ad5018bedc2ce0a72dad1827a1709da30580f0544").unwrap()); | ||||
| 		let genesis = frontier.genesis_block(); | ||||
| 		assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap()); | ||||
| 
 | ||||
| 		let _ = frontier.to_engine(); | ||||
| 	} | ||||
| } | ||||
| } | ||||
|  | ||||
							
								
								
									
										41
									
								
								src/spec.rs
									
									
									
									
									
								
							
							
						
						
									
										41
									
								
								src/spec.rs
									
									
									
									
									
								
							| @ -40,6 +40,27 @@ fn json_to_rlp_map(json: &Json) -> HashMap<String, Bytes> { | ||||
| 	}) | ||||
| } | ||||
| 
 | ||||
| //TODO: add code and data
 | ||||
| #[derive(Debug)] | ||||
| /// Genesis account data. Does no thave a DB overlay cache
 | ||||
| pub struct GenesisAccount { | ||||
| 	// Balance of the account.
 | ||||
| 	balance: U256, | ||||
| 	// Nonce of the account.
 | ||||
| 	nonce: U256, | ||||
| } | ||||
| 
 | ||||
| impl GenesisAccount { | ||||
| 	pub fn rlp(&self) -> Bytes { | ||||
| 		let mut stream = RlpStream::new_list(4); | ||||
| 		stream.append(&self.nonce); | ||||
| 		stream.append(&self.balance); | ||||
| 		stream.append(&SHA3_NULL_RLP); | ||||
| 		stream.append(&SHA3_EMPTY); | ||||
| 		stream.out() | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| /// Parameters for a block chain; includes both those intrinsic to the design of the
 | ||||
| /// chain and those to be interpreted by the active chain engine.
 | ||||
| #[derive(Debug)] | ||||
| @ -62,12 +83,12 @@ pub struct Spec { | ||||
| 	pub gas_used: U256, | ||||
| 	pub timestamp: u64, | ||||
| 	pub extra_data: Bytes, | ||||
| 	pub genesis_state: HashMap<Address, Account>, | ||||
| 	pub genesis_state: HashMap<Address, GenesisAccount>, | ||||
| 	pub seal_fields: usize, | ||||
| 	pub seal_rlp: Bytes, | ||||
| 
 | ||||
| 	// May be prepopulated if we know this in advance.
 | ||||
| 	state_root_memo: RefCell<Option<H256>>, | ||||
| 	state_root_memo: RwLock<Option<H256>>, | ||||
| } | ||||
| 
 | ||||
| impl Spec { | ||||
| @ -82,11 +103,11 @@ impl Spec { | ||||
| 	} | ||||
| 
 | ||||
| 	/// Return the state root for the genesis state, memoising accordingly.
 | ||||
| 	pub fn state_root(&self) -> Ref<H256> { | ||||
| 		if self.state_root_memo.borrow().is_none() { | ||||
| 			*self.state_root_memo.borrow_mut() = Some(sec_trie_root(self.genesis_state.iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect())); | ||||
| 	pub fn state_root(&self) -> H256 { | ||||
| 		if self.state_root_memo.read().unwrap().is_none() { | ||||
| 			*self.state_root_memo.write().unwrap() = Some(sec_trie_root(self.genesis_state.iter().map(|(k, v)| (k.to_vec(), v.rlp())).collect())); | ||||
| 		} | ||||
| 		Ref::map(self.state_root_memo.borrow(), |x|x.as_ref().unwrap()) | ||||
| 		self.state_root_memo.read().unwrap().as_ref().unwrap().clone() | ||||
| 	} | ||||
| 
 | ||||
| 	pub fn genesis_header(&self) -> Header { | ||||
| @ -113,7 +134,7 @@ impl Spec { | ||||
| 				let r = Rlp::new(&seal); | ||||
| 				(0..self.seal_fields).map(|i| r.at(i).as_raw().to_vec()).collect() | ||||
| 			}, | ||||
| 			hash: RefCell::new(None) | ||||
| 			hash: RefCell::new(None), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -149,7 +170,7 @@ impl Spec { | ||||
| //				let nonce = if let Some(&Json::String(ref n)) = acc.find("nonce") {U256::from_dec_str(n).unwrap_or(U256::from(0))} else {U256::from(0)};
 | ||||
| 				// TODO: handle code & data if they exist.
 | ||||
| 				if balance.is_some() || nonce.is_some() { | ||||
| 					state.insert(addr, Account::new_basic(balance.unwrap_or(U256::from(0)), nonce.unwrap_or(U256::from(0)))); | ||||
| 					state.insert(addr, GenesisAccount { balance: balance.unwrap_or(U256::from(0)), nonce: nonce.unwrap_or(U256::from(0)) }); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| @ -186,7 +207,7 @@ impl Spec { | ||||
| 			genesis_state: state, | ||||
| 			seal_fields: seal_fields, | ||||
| 			seal_rlp: seal_rlp, | ||||
| 			state_root_memo: RefCell::new(genesis.find("stateRoot").and_then(|_| genesis["stateRoot"].as_string()).map(|s| H256::from_str(&s[2..]).unwrap())), | ||||
| 			state_root_memo: RwLock::new(genesis.find("stateRoot").and_then(|_| genesis["stateRoot"].as_string()).map(|s| H256::from_str(&s[2..]).unwrap())), | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| @ -228,7 +249,7 @@ mod tests { | ||||
| 	fn test_chain() { | ||||
| 		let test_spec = Spec::new_test(); | ||||
| 
 | ||||
| 		assert_eq!(*test_spec.state_root(), H256::from_str("f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9").unwrap()); | ||||
| 		assert_eq!(test_spec.state_root(), H256::from_str("f3f4696bbf3b3b07775128eb7a3763279a394e382130f27c21e70233e04946a9").unwrap()); | ||||
| 		let genesis = test_spec.genesis_block(); | ||||
| 		assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap()); | ||||
| 
 | ||||
|  | ||||
| @ -13,12 +13,13 @@ | ||||
| /// use ethcore::client::Client;
 | ||||
| /// use ethcore::sync::EthSync;
 | ||||
| /// use ethcore::ethereum;
 | ||||
| /// use ethcore::ethereum::ethash::Ethash;
 | ||||
| ///
 | ||||
| /// fn main() {
 | ||||
| /// 	let mut service = NetworkService::start().unwrap();
 | ||||
| ///		let frontier = ethereum::new_frontier();
 | ||||
| /// 	let engine = Ethash::new_arc(ethereum::new_frontier());
 | ||||
| /// 	let dir = env::temp_dir();
 | ||||
| /// 	let client = Arc::new(Client::new(&frontier.genesis_block(), &dir));
 | ||||
| /// 	let client = Arc::new(Client::new(engine, &dir));
 | ||||
| /// 	EthSync::register(&mut service, client);
 | ||||
| /// }
 | ||||
| /// ```
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user