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