Engine and Spec are now thread safe

This commit is contained in:
arkpar 2016-01-11 11:51:31 +01:00
parent 5d0e186632
commit 33d3a4d633
10 changed files with 55 additions and 22 deletions

0
<std macros> Normal file
View File

View 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();

View File

@ -1,6 +1,5 @@
//! Fast access to blockchain data.
use std::sync::*;
use util::*;
use rocksdb::{DB, WriteBatch, Writable};
use header::*;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
/// }
/// ```