Merge branch 'master' into client-ipc-refact

This commit is contained in:
NikVolf
2016-07-05 11:29:46 +03:00
69 changed files with 929 additions and 246 deletions

View File

@@ -22,7 +22,7 @@ ethcore-util = { path = "../util" }
evmjit = { path = "../evmjit", optional = true }
ethash = { path = "../ethash" }
num_cpus = "0.2"
clippy = { version = "0.0.77", optional = true}
clippy = { version = "0.0.78", optional = true}
crossbeam = "0.2.9"
lazy_static = "0.2"
ethcore-devtools = { path = "../devtools" }

View File

@@ -214,8 +214,8 @@ impl Account {
}
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
pub fn commit_storage(&mut self, db: &mut AccountDBMut) {
let mut t = SecTrieDBMut::from_existing(db, &mut self.storage_root)
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut AccountDBMut) {
let mut t = trie_factory.from_existing(db, &mut self.storage_root)
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
SecTrieDBMut would not set it to an invalid state root. Therefore the root is valid and DB creation \
using it will not fail.");
@@ -275,7 +275,7 @@ mod tests {
let rlp = {
let mut a = Account::new_contract(69.into(), 0.into());
a.set_storage(H256::from(&U256::from(0x00u64)), H256::from(&U256::from(0x1234u64)));
a.commit_storage(&mut db);
a.commit_storage(&Default::default(), &mut db);
a.init_code(vec![]);
a.commit_code(&mut db);
a.rlp()
@@ -313,7 +313,7 @@ mod tests {
let mut db = AccountDBMut::new(&mut db, &Address::new());
a.set_storage(0.into(), 0x1234.into());
assert_eq!(a.storage_root(), None);
a.commit_storage(&mut db);
a.commit_storage(&Default::default(), &mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
}
@@ -323,11 +323,11 @@ mod tests {
let mut db = MemoryDB::new();
let mut db = AccountDBMut::new(&mut db, &Address::new());
a.set_storage(0.into(), 0x1234.into());
a.commit_storage(&mut db);
a.commit_storage(&Default::default(), &mut db);
a.set_storage(1.into(), 0x1234.into());
a.commit_storage(&mut db);
a.commit_storage(&Default::default(), &mut db);
a.set_storage(1.into(), 0.into());
a.commit_storage(&mut db);
a.commit_storage(&Default::default(), &mut db);
assert_eq!(a.storage_root().unwrap().hex(), "c57e1afb758b07f8d2c8f13a3b6e44fa5ff94ab266facc5a4fd3f062426e50b2");
}

View File

@@ -254,7 +254,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
assert!(b.try_seal(engine.deref(), seal).is_ok());

View File

@@ -222,6 +222,7 @@ impl<'x> OpenBlock<'x> {
pub fn new(
engine: &'x Engine,
vm_factory: &'x EvmFactory,
trie_factory: TrieFactory,
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
@@ -231,7 +232,7 @@ impl<'x> OpenBlock<'x> {
gas_range_target: (U256, U256),
extra_data: Bytes,
) -> Result<Self, Error> {
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce()));
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(), trie_factory));
let mut r = OpenBlock {
block: ExecutedBlock::new(state, tracing),
engine: engine,
@@ -481,16 +482,17 @@ pub fn enact(
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
{
if ::log::max_log_level() >= ::log::LogLevel::Trace {
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce()));
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(), trie_factory.clone()));
trace!("enact(): root={}, author={}, author_balance={}\n", s.root(), header.author(), s.balance(&header.author()));
}
}
let mut b = try!(OpenBlock::new(engine, vm_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), (3141562.into(), 31415620.into()), header.extra_data().clone()));
let mut b = try!(OpenBlock::new(engine, vm_factory, trie_factory, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, header.author().clone(), (3141562.into(), 31415620.into()), header.extra_data().clone()));
b.set_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp());
@@ -509,11 +511,12 @@ pub fn enact_bytes(
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
let block = BlockView::new(block_bytes);
let header = block.header();
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
@@ -526,10 +529,11 @@ pub fn enact_verified(
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> {
let view = BlockView::new(&block.bytes);
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
@@ -542,10 +546,11 @@ pub fn enact_and_seal(
parent: &Header,
last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view();
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory)).seal(engine, header.seal())))
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, dao_rescue_block_gas_limit, vm_factory, trie_factory)).seal(engine, header.seal())))
}
#[cfg(test)]
@@ -565,7 +570,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
let _ = b.seal(engine.deref(), vec![]);
}
@@ -581,7 +586,7 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
@@ -589,7 +594,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default(), Default::default()).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes);
@@ -609,7 +614,7 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default();
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut open_block = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, vec![genesis_header.hash()], None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new();
@@ -624,7 +629,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine.deref(), false, db, &genesis_header, vec![genesis_header.hash()], None, &Default::default(), Default::default()).unwrap();
let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);

View File

@@ -30,7 +30,7 @@ use blockchain::best_block::BestBlock;
use types::tree_route::TreeRoute;
use blockchain::update::ExtrasUpdate;
use blockchain::{CacheSize, ImportRoute, Config};
use db::{Writable, Readable, CacheUpdatePolicy};
use db::{Writable, Readable, CacheUpdatePolicy, Key};
const LOG_BLOOMS_LEVELS: usize = 3;
const LOG_BLOOMS_ELEMENTS_PER_INDEX: usize = 16;
@@ -295,7 +295,22 @@ impl BlockChain {
// load best block
let best_block_hash = match bc.extras_db.get(b"best").unwrap() {
Some(best) => H256::from_slice(&best),
Some(best) => {
let best = H256::from_slice(&best);
let mut b = best.clone();
while !bc.blocks_db.get(&b).unwrap().is_some() {
// track back to the best block we have in the blocks database
let extras: BlockDetails = bc.extras_db.read(&b).unwrap();
type DetailsKey = Key<BlockDetails, Target=H264>;
bc.extras_db.delete(&(DetailsKey::key(&b))).unwrap();
b = extras.parent;
}
if b != best {
info!("Restored mismatched best block. Was: {}, new: {}", best.hex(), b.hex());
bc.extras_db.put(b"best", &b).unwrap();
}
b
}
None => {
// best block does not exist
// we need to insert genesis into the cache

View File

@@ -18,3 +18,4 @@
#![allow(dead_code, unused_assignments, unused_variables, missing_docs)] // codegen issues
include!(concat!(env!("OUT_DIR"), "/client.ipc.rs"));

View File

@@ -122,6 +122,7 @@ pub struct Client {
panic_handler: Arc<PanicHandler>,
verifier: Box<Verifier>,
vm_factory: Arc<EvmFactory>,
trie_factory: TrieFactory,
miner: Arc<Miner>,
io_channel: IoChannel<NetSyncMessage>,
queue_transactions: AtomicUsize,
@@ -203,6 +204,7 @@ impl Client {
panic_handler: panic_handler,
verifier: verification::new(config.verifier_type),
vm_factory: Arc::new(EvmFactory::new(config.vm_type)),
trie_factory: TrieFactory::new(config.trie_spec),
miner: miner,
io_channel: message_channel,
queue_transactions: AtomicUsize::new(0),
@@ -261,7 +263,7 @@ impl Client {
let last_hashes = self.build_last_hashes(header.parent_hash.clone());
let db = self.state_db.lock().unwrap().boxed_clone();
let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(header.parent_hash.clone()), &self.vm_factory);
let enact_result = enact_verified(&block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.dao_rescue_block_gas_limit(header.parent_hash.clone()), &self.vm_factory, self.trie_factory.clone());
if let Err(e) = enact_result {
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(());
@@ -376,7 +378,7 @@ impl Client {
imported
}
fn commit_block<B>(&self, block: B, hash: &H256, block_data: &Bytes) -> ImportRoute where B: IsBlock + Drain {
fn commit_block<B>(&self, block: B, hash: &H256, block_data: &[u8]) -> ImportRoute where B: IsBlock + Drain {
let number = block.header().number();
// Are we committing an era?
let ancient = if number >= HISTORY {
@@ -446,13 +448,17 @@ impl Client {
let root = HeaderView::new(&header).state_root();
State::from_existing(db, root, self.engine.account_start_nonce()).ok()
State::from_existing(db, root, self.engine.account_start_nonce(), self.trie_factory.clone()).ok()
})
}
/// Get a copy of the best block's state.
pub fn state(&self) -> State {
State::from_existing(self.state_db.lock().unwrap().boxed_clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce())
State::from_existing(
self.state_db.lock().unwrap().boxed_clone(),
HeaderView::new(&self.best_block_header()).state_root(),
self.engine.account_start_nonce(),
self.trie_factory.clone())
.expect("State root of best block header always valid.")
}
@@ -509,7 +515,6 @@ impl Client {
}
}
#[derive(Ipc)]
impl BlockChainClient for Client {
fn call(&self, t: &SignedTransaction, analytics: CallAnalytics) -> Result<Executed, ExecutionError> {
let header = self.block_header(BlockID::Latest).unwrap();
@@ -610,7 +615,7 @@ impl BlockChainClient for Client {
fn uncle(&self, id: UncleID) -> Option<Bytes> {
let index = id.position;
self.block(id.block).and_then(|block| BlockView::new(&block).uncle_at(index).and_then(|u| Some(u.rlp(Seal::With))))
self.block(id.block).and_then(|block| BlockView::new(&block).uncle_rlp_at(index))
}
fn transaction_receipt(&self, id: TransactionID) -> Option<LocalizedReceipt> {
@@ -684,7 +689,7 @@ impl BlockChainClient for Client {
return Err(BlockImportError::Import(ImportError::AlreadyInChain));
}
if self.block_status(BlockID::Hash(header.parent_hash())) == BlockStatus::Unknown {
return Err(BlockImportError::Block(BlockError::UnknownParent(header.parent_hash()));
return Err(BlockImportError::Block(BlockError::UnknownParent(header.parent_hash())));
}
}
Ok(try!(self.block_queue.import_block(bytes)))
@@ -694,9 +699,8 @@ impl BlockChainClient for Client {
self.block_queue.queue_info()
}
fn clear_queue(&self) -> bool {
fn clear_queue(&self) {
self.block_queue.clear();
true
}
fn chain_info(&self) -> BlockChainInfo {
@@ -742,8 +746,8 @@ impl BlockChainClient for Client {
receipt.logs.into_iter()
.enumerate()
.filter(|tuple| filter.matches(&tuple.1))
.map(|(i, log)| LocalizedLogEntry {
entry: log,
.map(|(i, log)| LocalizedLogEntry {
entry: log,
block_hash: hash.clone(),
block_number: number,
transaction_hash: hashes.get(index).cloned().unwrap_or_else(H256::new),
@@ -802,31 +806,29 @@ impl BlockChainClient for Client {
self.build_last_hashes(self.chain.best_block_hash())
}
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, String>> {
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, TransactionImportError>> {
let fetch_account = |a: &Address| AccountDetails {
nonce: self.latest_nonce(a),
balance: self.latest_balance(a),
};
self.miner.import_transactions(self, transactions, fetch_account)
.iter()
.map(|res| match res { &Ok(ref t) => Ok(t.clone()), &Err(ref e) => Err(format!("{:?}", e)) })
.collect::<Vec<Result<TransactionImportResult, String>>>()
self.miner.import_transactions(self, transactions, &fetch_account)
.into_iter()
.map(|res| res.map_err(|e| e.into()))
.collect()
}
fn queue_transactions(&self, transactions: Vec<Bytes>) -> bool {
fn queue_transactions(&self, transactions: Vec<Bytes>) {
if self.queue_transactions.load(AtomicOrdering::Relaxed) > MAX_TX_QUEUE_SIZE {
debug!("Ignoring {} transactions: queue is full", transactions.len());
false
} else {
let len = transactions.len();
match self.io_channel.send(NetworkIoMessage::User(SyncMessage::NewTransactions(transactions))) {
Ok(_) => {
self.queue_transactions.fetch_add(len, AtomicOrdering::SeqCst);
true
}
Err(e) => {
debug!("Ignoring {} transactions: error queueing: {}", len, e);
false
}
}
}
@@ -845,6 +847,7 @@ impl MiningBlockChainClient for Client {
let mut open_block = OpenBlock::new(
engine,
&self.vm_factory,
self.trie_factory.clone(),
false, // TODO: this will need to be parameterised once we want to do immediate mining insertion.
self.state_db.lock().unwrap().boxed_clone(),
&self.chain.block_header(&h).expect("h is best block hash: so it's header must exist: qed"),

View File

@@ -20,6 +20,7 @@ pub use trace::{Config as TraceConfig, Switch};
pub use evm::VMType;
pub use verification::VerifierType;
use util::journaldb;
use util::trie::TrieSpec;
/// Client state db compaction profile
#[derive(Debug, PartialEq)]
@@ -45,6 +46,8 @@ pub struct ClientConfig {
pub tracing: TraceConfig,
/// VM type.
pub vm_type: VMType,
/// Trie type.
pub trie_spec: TrieSpec,
/// The JournalDB ("pruning") algorithm to use.
pub pruning: journaldb::Algorithm,
/// The name of the client instance.

View File

@@ -47,9 +47,25 @@ use error::{ImportResult, ExecutionError};
use receipt::LocalizedReceipt;
use trace::LocalizedTrace;
use evm::Factory as EvmFactory;
<<<<<<< HEAD
use miner::{TransactionImportResult};
pub use types::call_analytics::CallAnalytics;
pub use types::block_import_error::BlockImportError;
=======
pub use block_import_error::BlockImportError;
pub use transaction_import::{TransactionImportResult, TransactionImportError};
/// Options concerning what analytics we run on the call.
#[derive(Eq, PartialEq, Default, Clone, Copy, Debug)]
pub struct CallAnalytics {
/// Make a transaction trace.
pub transaction_tracing: bool,
/// Make a VM trace.
pub vm_tracing: bool,
/// Make a diff.
pub state_diffing: bool,
}
>>>>>>> master
/// Blockchain database client. Owns and manages a blockchain and a block queue.
pub trait BlockChainClient : Sync + Send {
@@ -178,7 +194,11 @@ pub trait BlockChainClient : Sync + Send {
fn last_hashes(&self) -> LastHashes;
/// import transactions from network/other 3rd party
<<<<<<< HEAD
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, String>>;
=======
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, TransactionImportError>>;
>>>>>>> master
/// Queue transactions for importing.
fn queue_transactions(&self, transactions: Vec<Bytes>) -> bool;

View File

@@ -21,7 +21,8 @@ use util::*;
use transaction::{Transaction, LocalizedTransaction, SignedTransaction, Action};
use blockchain::TreeRoute;
use client::{BlockChainClient, MiningBlockChainClient, BlockChainInfo, BlockStatus, BlockID,
TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics, BlockImportError};
TransactionID, UncleID, TraceId, TraceFilter, LastHashes, CallAnalytics,
TransactionImportError, BlockImportError};
use header::{Header as BlockHeader, BlockNumber};
use filter::Filter;
use log_entry::LocalizedLogEntry;
@@ -488,7 +489,7 @@ impl BlockChainClient for TestBlockChainClient {
unimplemented!();
}
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, String>> {
fn import_transactions(&self, transactions: Vec<SignedTransaction>) -> Vec<Result<TransactionImportResult, TransactionImportError>> {
let nonces = self.nonces.read().unwrap();
let balances = self.balances.read().unwrap();
let fetch_account = |a: &Address| AccountDetails {
@@ -496,10 +497,10 @@ impl BlockChainClient for TestBlockChainClient {
balance: balances[a],
};
self.miner.import_transactions(self, transactions, fetch_account)
.iter()
.map(|res| match res { &Ok(ref t) => Ok(t.clone()), &Err(ref e) => Err(format!("{:?}", e)) })
.collect::<Vec<Result<TransactionImportResult, String>>>()
self.miner.import_transactions(self, transactions, &fetch_account)
.into_iter()
.map(|res| res.map_err(|e| e.into()))
.collect()
}
fn queue_transactions(&self, transactions: Vec<Bytes>) -> bool {

View File

@@ -20,12 +20,11 @@ use util::*;
use header::BlockNumber;
use basic_types::LogBloom;
use client::Error as ClientError;
use client::BlockImportError;
use ipc::binary::{BinaryConvertable, BinaryConvertError};
use ipc::binary::{BinaryConvertError, BinaryConvertable};
use types::block_import_error::BlockImportError;
pub use types::executed::ExecutionError;
#[derive(Debug, PartialEq)]
#[derive(Debug, PartialEq, Clone)]
/// Errors concerning transaction processing.
pub enum TransactionError {
/// Transaction is already imported to the queue
@@ -196,9 +195,6 @@ pub enum ImportError {
KnownBad,
}
binary_fixed_size!(BlockError);
binary_fixed_size!(ImportError);
impl fmt::Display for ImportError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let msg = match *self {
@@ -327,6 +323,10 @@ impl From<BlockImportError> for Error {
}
}
binary_fixed_size!(BlockError);
binary_fixed_size!(ImportError);
binary_fixed_size!(TransactionError);
// TODO: uncomment below once https://github.com/rust-lang/rust/issues/27336 sorted.
/*#![feature(concat_idents)]
macro_rules! assimilate {

View File

@@ -325,7 +325,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close();
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap());
}
@@ -340,7 +340,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default();
let mut b = OpenBlock::new(engine.deref(), &vm_factory, false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut b = OpenBlock::new(engine.deref(), &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, None, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut uncle = Header::new();
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
uncle.author = uncle_author.clone();

View File

@@ -67,7 +67,7 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut());
let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce()).unwrap();
let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce(), Default::default()).unwrap();
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000001")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000002")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000003")), U256::from(1u64));

View File

@@ -29,8 +29,10 @@ use transaction::SignedTransaction;
use receipt::{Receipt};
use spec::Spec;
use engine::Engine;
use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
use miner::{MinerService, MinerStatus, TransactionQueue, AccountDetails, TransactionOrigin};
use miner::work_notify::WorkPoster;
use client::TransactionImportResult;
/// Different possible definitions for pending transaction set.
#[derive(Debug)]
@@ -158,7 +160,7 @@ impl Miner {
fn prepare_sealing(&self, chain: &MiningBlockChainClient) {
trace!(target: "miner", "prepare_sealing: entering");
let (transactions, mut open_block, last_work_hash) = {
let (transactions, mut open_block, original_work_hash) = {
let transactions = {self.transaction_queue.lock().unwrap().top_transactions()};
let mut sealing_work = self.sealing_work.lock().unwrap();
let last_work_hash = sealing_work.peek_last_ref().map(|pb| pb.block().fields().header.hash());
@@ -254,23 +256,31 @@ impl Miner {
}
}
let work = {
let (work, is_new) = {
let mut sealing_work = self.sealing_work.lock().unwrap();
trace!(target: "miner", "Checking whether we need to reseal: last={:?}, this={:?}", last_work_hash, block.block().fields().header.hash());
let work = if last_work_hash.map_or(true, |h| h != block.block().fields().header.hash()) {
let last_work_hash = sealing_work.peek_last_ref().map(|pb| pb.block().fields().header.hash());
trace!(target: "miner", "Checking whether we need to reseal: orig={:?} last={:?}, this={:?}", original_work_hash, last_work_hash, block.block().fields().header.hash());
let (work, is_new) = if last_work_hash.map_or(true, |h| h != block.block().fields().header.hash()) {
trace!(target: "miner", "Pushing a new, refreshed or borrowed pending {}...", block.block().fields().header.hash());
let pow_hash = block.block().fields().header.hash();
let number = block.block().fields().header.number();
let difficulty = *block.block().fields().header.difficulty();
let is_new = original_work_hash.map_or(true, |h| block.block().fields().header.hash() != h);
sealing_work.push(block);
Some((pow_hash, difficulty, number))
// If push notifications are enabled we assume all work items are used.
if self.work_poster.is_some() && is_new {
sealing_work.use_last_ref();
}
(Some((pow_hash, difficulty, number)), is_new)
} else {
None
(None, false)
};
trace!(target: "miner", "prepare_sealing: leaving (last={:?})", sealing_work.peek_last_ref().map(|b| b.block().fields().header.hash()));
work
(work, is_new)
};
work.map(|(pow_hash, difficulty, number)| self.work_poster.as_ref().map(|ref p| p.notify(pow_hash, difficulty, number)));
if is_new {
work.map(|(pow_hash, difficulty, number)| self.work_poster.as_ref().map(|ref p| p.notify(pow_hash, difficulty, number)));
}
}
fn update_gas_limit(&self, chain: &MiningBlockChainClient) {

View File

@@ -47,9 +47,10 @@ mod external;
mod transaction_queue;
mod work_notify;
pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionImportResult, TransactionOrigin};
pub use self::transaction_queue::{TransactionQueue, AccountDetails, TransactionOrigin};
pub use self::miner::{Miner, MinerOptions, PendingSet};
pub use self::external::{ExternalMiner, ExternalMinerService};
pub use client::TransactionImportResult;
use std::collections::BTreeMap;
use util::{H256, U256, Address, Bytes};

View File

@@ -90,7 +90,11 @@ use util::hash::{Address, H256};
use util::table::*;
use transaction::*;
use error::{Error, TransactionError};
<<<<<<< HEAD
pub use types::transaction_import_result::TransactionImportResult;
=======
use client::TransactionImportResult;
>>>>>>> master
/// Transaction origin
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -805,6 +809,7 @@ mod test {
use error::{Error, TransactionError};
use super::*;
use super::{TransactionSet, TransactionOrder, VerifiedTransaction};
use client::TransactionImportResult;
fn unwrap_tx_err(err: Result<TransactionImportResult, Error>) -> TransactionError {
match err.unwrap_err() {

View File

@@ -52,10 +52,10 @@ impl WorkPoster {
}
fn create_client() -> Client<PostHandler> {
let client = Client::<PostHandler>::configure()
Client::<PostHandler>::configure()
.keep_alive(true)
.build().expect("Error creating HTTP client") as Client<PostHandler>;
client
.build()
.expect("Error creating HTTP client")
}
pub fn notify(&self, pow_hash: H256, difficulty: U256, number: u64) {
@@ -63,8 +63,10 @@ impl WorkPoster {
let target = Ethash::difficulty_to_boundary(&difficulty);
let seed_hash = &self.seed_compute.lock().unwrap().get_seedhash(number);
let seed_hash = H256::from_slice(&seed_hash[..]);
let body = format!(r#"{{ "result": ["0x{}","0x{}","0x{}","0x{:x}"] }}"#,
pow_hash.hex(), seed_hash.hex(), target.hex(), number);
let body = format!(
r#"{{ "result": ["0x{}","0x{}","0x{}","0x{:x}"] }}"#,
pow_hash.hex(), seed_hash.hex(), target.hex(), number
);
let mut client = self.client.lock().unwrap();
for u in &self.urls {
if let Err(e) = client.request(u.clone(), PostHandler { body: body.clone() }) {
@@ -104,12 +106,12 @@ impl hyper::client::Handler<HttpStream> for PostHandler {
}
fn on_response_readable(&mut self, _decoder: &mut hyper::Decoder<HttpStream>) -> Next {
Next::end()
Next::end()
}
fn on_error(&mut self, err: hyper::Error) -> Next {
fn on_error(&mut self, err: hyper::Error) -> Next {
trace!("Error posting work data: {}", err);
Next::end()
}
}
}

View File

@@ -42,6 +42,7 @@ pub struct State {
cache: RefCell<HashMap<Address, Option<Account>>>,
snapshots: RefCell<Vec<HashMap<Address, Option<Option<Account>>>>>,
account_start_nonce: U256,
trie_factory: TrieFactory,
}
const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with valid root. Creating a SecTrieDB with a valid root will not fail. \
@@ -50,11 +51,11 @@ const SEC_TRIE_DB_UNWRAP_STR: &'static str = "A state can only be created with v
impl State {
/// Creates new state with empty state root
#[cfg(test)]
pub fn new(mut db: Box<JournalDB>, account_start_nonce: U256) -> State {
pub fn new(mut db: Box<JournalDB>, account_start_nonce: U256, trie_factory: TrieFactory) -> State {
let mut root = H256::new();
{
// init trie and reset root too null
let _ = SecTrieDBMut::new(db.as_hashdb_mut(), &mut root);
let _ = trie_factory.create(db.as_hashdb_mut(), &mut root);
}
State {
@@ -63,22 +64,26 @@ impl State {
cache: RefCell::new(HashMap::new()),
snapshots: RefCell::new(Vec::new()),
account_start_nonce: account_start_nonce,
trie_factory: trie_factory,
}
}
/// Creates new state with existing state root
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256) -> Result<State, TrieError> {
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256, trie_factory: TrieFactory) -> Result<State, TrieError> {
if !db.as_hashdb().contains(&root) {
Err(TrieError::InvalidStateRoot)
} else {
Ok(State {
db: db,
root: root,
cache: RefCell::new(HashMap::new()),
snapshots: RefCell::new(Vec::new()),
account_start_nonce: account_start_nonce,
})
return Err(TrieError::InvalidStateRoot);
}
let state = State {
db: db,
root: root,
cache: RefCell::new(HashMap::new()),
snapshots: RefCell::new(Vec::new()),
account_start_nonce: account_start_nonce,
trie_factory: trie_factory,
};
Ok(state)
}
/// Create a recoverable snaphot of this state
@@ -156,7 +161,7 @@ impl State {
/// Determine whether an account exists.
pub fn exists(&self, a: &Address) -> bool {
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
self.cache.borrow().get(&a).unwrap_or(&None).is_some() || db.contains(&a)
}
@@ -242,7 +247,10 @@ impl State {
for a in &addresses {
if self.code(a).map_or(false, |c| c.sha3() == broken_dao) {
// Figure out if the balance has been reduced.
let maybe_original = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR).get(&a).map(Account::from_rlp);
let maybe_original = self.trie_factory
.readonly(self.db.as_hashdb(), &self.root)
.expect(SEC_TRIE_DB_UNWRAP_STR)
.get(&a).map(Account::from_rlp);
if maybe_original.map_or(false, |original| *original.balance() > self.balance(a)) {
return Err(Error::Transaction(TransactionError::DAORescue));
}
@@ -262,14 +270,14 @@ impl State {
/// Commit accounts to SecTrieDBMut. This is similar to cpp-ethereum's dev::eth::commit.
/// `accounts` is mutable because we may need to commit the code or storage and record that.
#[cfg_attr(feature="dev", allow(match_ref_pats))]
pub fn commit_into(db: &mut HashDB, root: &mut H256, accounts: &mut HashMap<Address, Option<Account>>) {
pub fn commit_into(trie_factory: &TrieFactory, db: &mut HashDB, root: &mut H256, accounts: &mut HashMap<Address, Option<Account>>) {
// first, commit the sub trees.
// TODO: is this necessary or can we dispense with the `ref mut a` for just `a`?
for (address, ref mut a) in accounts.iter_mut() {
match a {
&mut&mut Some(ref mut account) => {
let mut account_db = AccountDBMut::new(db, address);
account.commit_storage(&mut account_db);
account.commit_storage(trie_factory, &mut account_db);
account.commit_code(&mut account_db);
}
&mut&mut None => {}
@@ -277,7 +285,7 @@ impl State {
}
{
let mut trie = SecTrieDBMut::from_existing(db, root).unwrap();
let mut trie = trie_factory.from_existing(db, root).unwrap();
for (address, ref a) in accounts.iter() {
match **a {
Some(ref account) => trie.insert(address, &account.rlp()),
@@ -290,7 +298,7 @@ impl State {
/// Commits our cached account changes into the trie.
pub fn commit(&mut self) {
assert!(self.snapshots.borrow().is_empty());
Self::commit_into(self.db.as_hashdb_mut(), &mut self.root, self.cache.borrow_mut().deref_mut());
Self::commit_into(&self.trie_factory, self.db.as_hashdb_mut(), &mut self.root, self.cache.borrow_mut().deref_mut());
}
#[cfg(test)]
@@ -340,7 +348,7 @@ impl State {
fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option<Account> {
let have_key = self.cache.borrow().contains_key(a);
if !have_key {
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
self.insert_cache(a, db.get(&a).map(Account::from_rlp))
}
if require_code {
@@ -361,7 +369,7 @@ impl State {
fn require_or_from<'a, F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> &'a mut Account {
let have_key = self.cache.borrow().contains_key(a);
if !have_key {
let db = SecTrieDB::new(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
self.insert_cache(a, db.get(&a).map(Account::from_rlp))
} else {
self.note_cache(a);
@@ -396,6 +404,7 @@ impl Clone for State {
cache: RefCell::new(self.cache.borrow().clone()),
snapshots: RefCell::new(self.snapshots.borrow().clone()),
account_start_nonce: self.account_start_nonce.clone(),
trie_factory: self.trie_factory.clone(),
}
}
}
@@ -1179,7 +1188,7 @@ fn code_from_database() {
state.drop()
};
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
}
@@ -1194,7 +1203,7 @@ fn storage_at_from_database() {
state.drop()
};
let s = State::from_existing(db, root, U256::from(0u8)).unwrap();
let s = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert_eq!(s.storage_at(&a, &H256::from(&U256::from(01u64))), H256::from(&U256::from(69u64)));
}
@@ -1211,7 +1220,7 @@ fn get_from_database() {
state.drop()
};
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert_eq!(state.balance(&a), U256::from(69u64));
assert_eq!(state.nonce(&a), U256::from(1u64));
}
@@ -1244,7 +1253,7 @@ fn remove_from_database() {
};
let (root, db) = {
let mut state = State::from_existing(db, root, U256::from(0u8)).unwrap();
let mut state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert_eq!(state.exists(&a), true);
assert_eq!(state.nonce(&a), U256::from(1u64));
state.kill_account(&a);
@@ -1254,7 +1263,7 @@ fn remove_from_database() {
state.drop()
};
let state = State::from_existing(db, root, U256::from(0u8)).unwrap();
let state = State::from_existing(db, root, U256::from(0u8), Default::default()).unwrap();
assert_eq!(state.exists(&a), false);
assert_eq!(state.nonce(&a), U256::from(0u64));
}

View File

@@ -175,6 +175,7 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
let mut b = OpenBlock::new(
test_engine.deref(),
&vm_factory,
Default::default(),
false,
db,
&last_header,
@@ -315,7 +316,7 @@ pub fn get_temp_state() -> GuardedTempResult<State> {
let journal_db = get_temp_journal_db_in(temp.as_path());
GuardedTempResult {
_temp: temp,
result: Some(State::new(journal_db, U256::from(0u8)))
result: Some(State::new(journal_db, U256::from(0), Default::default())),
}
}
@@ -325,7 +326,7 @@ pub fn get_temp_journal_db_in(path: &Path) -> Box<JournalDB> {
pub fn get_temp_state_in(path: &Path) -> State {
let journal_db = get_temp_journal_db_in(path);
State::new(journal_db, U256::from(0u8))
State::new(journal_db, U256::from(0), Default::default())
}
pub fn get_good_dummy_block_seq(count: usize) -> Vec<Bytes> {

View File

@@ -26,8 +26,8 @@ pub mod block_status;
pub mod account_diff;
pub mod state_diff;
pub mod block_queue_info;
pub mod transaction_import_result;
pub mod filter;
pub mod trace_filter;
pub mod call_analytics;
pub mod transaction_import;
pub mod block_import_error;

View File

@@ -16,10 +16,13 @@
//! Transaction import result related types
use ipc::binary::BinaryConvertError;
use ipc::binary::{BinaryConvertError, BinaryConvertable};
use std::collections::VecDeque;
use error::{TransactionError, Error};
use std::mem;
use util::Populatable;
#[derive(Debug, Clone, PartialEq, Binary)]
#[derive(Debug, Clone, PartialEq)]
/// Represents the result of importing transaction.
pub enum TransactionImportResult {
/// Transaction was imported to current queue.
@@ -27,3 +30,23 @@ pub enum TransactionImportResult {
/// Transaction was imported to future queue.
Future
}
binary_fixed_size!(TransactionImportResult);
/// Api-level error for transaction import
#[derive(Debug, Clone, Binary)]
pub enum TransactionImportError {
/// Transaction error
Transaction(TransactionError),
/// Other error
Other(String),
}
impl From<Error> for TransactionImportError {
fn from(e: Error) -> Self {
match e {
Error::Transaction(transaction_error) => TransactionImportError::Transaction(transaction_error),
_ => TransactionImportError::Other(format!("other block import error: {:?}", e)),
}
}
}

View File

@@ -139,6 +139,11 @@ impl<'a> BlockView<'a> {
pub fn uncle_at(&self, index: usize) -> Option<Header> {
self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_val())
}
/// Return nth uncle rlp.
pub fn uncle_rlp_at(&self, index: usize) -> Option<Bytes> {
self.rlp.at(2).iter().nth(index).map(|rlp| rlp.as_raw().to_vec())
}
}
impl<'a> Hashable for BlockView<'a> {