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::client::Client;
|
||||||
use ethcore::sync::EthSync;
|
use ethcore::sync::EthSync;
|
||||||
use ethcore::ethereum;
|
use ethcore::ethereum;
|
||||||
|
use ethcore::ethereum::ethash::Ethash;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
::env_logger::init().ok();
|
::env_logger::init().ok();
|
||||||
let mut service = NetworkService::start().unwrap();
|
let mut service = NetworkService::start().unwrap();
|
||||||
//TODO: replace with proper genesis and chain params.
|
//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();
|
let mut dir = env::temp_dir();
|
||||||
dir.push(H32::random().hex());
|
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);
|
EthSync::register(&mut service, client);
|
||||||
loop {
|
loop {
|
||||||
let mut cmd = String::new();
|
let mut cmd = String::new();
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
//! Fast access to blockchain data.
|
//! Fast access to blockchain data.
|
||||||
|
|
||||||
use std::sync::*;
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use rocksdb::{DB, WriteBatch, Writable};
|
use rocksdb::{DB, WriteBatch, Writable};
|
||||||
use header::*;
|
use header::*;
|
||||||
|
@ -12,6 +12,11 @@ pub struct Builtin {
|
|||||||
pub execute: Box<Fn(&[u8], &mut [u8])>,
|
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 {
|
impl fmt::Debug for Builtin {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
write!(f, "<Builtin>")
|
write!(f, "<Builtin>")
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
use std::sync::Arc;
|
|
||||||
use util::*;
|
use util::*;
|
||||||
use blockchain::BlockChain;
|
use blockchain::BlockChain;
|
||||||
use views::BlockView;
|
use views::BlockView;
|
||||||
use error::ImportError;
|
use error::ImportError;
|
||||||
use header::BlockNumber;
|
use header::BlockNumber;
|
||||||
|
use engine::Engine;
|
||||||
|
|
||||||
/// General block status
|
/// General block status
|
||||||
pub enum BlockStatus {
|
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.
|
/// Blockchain database client backed by a persistent database. Owns and manages a blockchain and a block queue.
|
||||||
pub struct Client {
|
pub struct Client {
|
||||||
chain: Arc<BlockChain>,
|
chain: Arc<BlockChain>,
|
||||||
|
_engine: Arc<Engine>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Client {
|
impl Client {
|
||||||
pub fn new(genesis: &[u8], path: &Path) -> Client {
|
pub fn new(engine: Arc<Engine>, path: &Path) -> Client {
|
||||||
let chain = Arc::new(BlockChain::new(genesis, path));
|
let chain = Arc::new(BlockChain::new(&engine.spec().genesis_block(), path));
|
||||||
Client {
|
Client {
|
||||||
chain: chain.clone(),
|
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.
|
/// 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.
|
/// Provides hooks into each of the major parts of block import.
|
||||||
pub trait Engine {
|
pub trait Engine : Sync + Send {
|
||||||
/// The name of this engine.
|
/// The name of this engine.
|
||||||
fn name(&self) -> &str;
|
fn name(&self) -> &str;
|
||||||
/// The version of this engine. Should be of the form
|
/// The version of this engine. Should be of the form
|
||||||
|
@ -13,6 +13,10 @@ impl Ethash {
|
|||||||
pub fn new_boxed(spec: Spec) -> Box<Engine> {
|
pub fn new_boxed(spec: Spec) -> Box<Engine> {
|
||||||
Box::new(Ethash{spec: spec})
|
Box::new(Ethash{spec: spec})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn new_arc(spec: Spec) -> Arc<Engine> {
|
||||||
|
Arc::new(Ethash{spec: spec})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine for Ethash {
|
impl Engine for Ethash {
|
||||||
|
@ -52,7 +52,7 @@ mod tests {
|
|||||||
fn morden() {
|
fn morden() {
|
||||||
let morden = new_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();
|
let genesis = morden.genesis_block();
|
||||||
assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap());
|
assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap());
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ mod tests {
|
|||||||
fn frontier() {
|
fn frontier() {
|
||||||
let frontier = new_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();
|
let genesis = frontier.genesis_block();
|
||||||
assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap());
|
assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("d4e56740f876aef8c010b86a40d5f56745a118d0906a34e69aec8c0db1cb8fa3").unwrap());
|
||||||
|
|
||||||
|
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
|
/// 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.
|
/// chain and those to be interpreted by the active chain engine.
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
@ -62,12 +83,12 @@ pub struct Spec {
|
|||||||
pub gas_used: U256,
|
pub gas_used: U256,
|
||||||
pub timestamp: u64,
|
pub timestamp: u64,
|
||||||
pub extra_data: Bytes,
|
pub extra_data: Bytes,
|
||||||
pub genesis_state: HashMap<Address, Account>,
|
pub genesis_state: HashMap<Address, GenesisAccount>,
|
||||||
pub seal_fields: usize,
|
pub seal_fields: usize,
|
||||||
pub seal_rlp: Bytes,
|
pub seal_rlp: Bytes,
|
||||||
|
|
||||||
// May be prepopulated if we know this in advance.
|
// May be prepopulated if we know this in advance.
|
||||||
state_root_memo: RefCell<Option<H256>>,
|
state_root_memo: RwLock<Option<H256>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Spec {
|
impl Spec {
|
||||||
@ -82,11 +103,11 @@ impl Spec {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the state root for the genesis state, memoising accordingly.
|
/// Return the state root for the genesis state, memoising accordingly.
|
||||||
pub fn state_root(&self) -> Ref<H256> {
|
pub fn state_root(&self) -> H256 {
|
||||||
if self.state_root_memo.borrow().is_none() {
|
if self.state_root_memo.read().unwrap().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()));
|
*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 {
|
pub fn genesis_header(&self) -> Header {
|
||||||
@ -113,7 +134,7 @@ impl Spec {
|
|||||||
let r = Rlp::new(&seal);
|
let r = Rlp::new(&seal);
|
||||||
(0..self.seal_fields).map(|i| r.at(i).as_raw().to_vec()).collect()
|
(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)};
|
// 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.
|
// TODO: handle code & data if they exist.
|
||||||
if balance.is_some() || nonce.is_some() {
|
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,
|
genesis_state: state,
|
||||||
seal_fields: seal_fields,
|
seal_fields: seal_fields,
|
||||||
seal_rlp: seal_rlp,
|
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() {
|
fn test_chain() {
|
||||||
let test_spec = Spec::new_test();
|
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();
|
let genesis = test_spec.genesis_block();
|
||||||
assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap());
|
assert_eq!(BlockView::new(&genesis).header_view().sha3(), H256::from_str("0cd786a2425d16f152c658316c423e6ce1181e15c3295826d7c9904cba9ce303").unwrap());
|
||||||
|
|
||||||
|
@ -13,12 +13,13 @@
|
|||||||
/// use ethcore::client::Client;
|
/// use ethcore::client::Client;
|
||||||
/// use ethcore::sync::EthSync;
|
/// use ethcore::sync::EthSync;
|
||||||
/// use ethcore::ethereum;
|
/// use ethcore::ethereum;
|
||||||
|
/// use ethcore::ethereum::ethash::Ethash;
|
||||||
///
|
///
|
||||||
/// fn main() {
|
/// fn main() {
|
||||||
/// let mut service = NetworkService::start().unwrap();
|
/// 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 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);
|
/// EthSync::register(&mut service, client);
|
||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
|
Loading…
Reference in New Issue
Block a user