Trie query recording and AccountDB factory for no mangling (#1944)

* optionally use no mangling for accountdb

* add the recorder module

* get_recorded for tries, no virtual dispatch on readonly tries

* add recording test
This commit is contained in:
Robert Habermeier
2016-08-24 16:53:36 +02:00
committed by Gav Wood
parent 33e0a234f2
commit 190e4db266
24 changed files with 590 additions and 182 deletions

View File

@@ -35,6 +35,38 @@ fn combine_key<'a>(address_hash: &'a H256, key: &'a H256) -> H256 {
dst
}
/// A factory for different kinds of account dbs.
#[derive(Debug, Clone)]
pub enum Factory {
/// Mangle hashes based on address.
Mangled,
/// Don't mangle hashes.
Plain,
}
impl Default for Factory {
fn default() -> Self { Factory::Mangled }
}
impl Factory {
/// Create a read-only accountdb.
/// This will panic when write operations are called.
pub fn readonly<'db>(&self, db: &'db HashDB, address_hash: H256) -> Box<HashDB + 'db> {
match *self {
Factory::Mangled => Box::new(AccountDB::from_hash(db, address_hash)),
Factory::Plain => Box::new(Wrapping(db)),
}
}
/// Create a new mutable hashdb.
pub fn create<'db>(&self, db: &'db mut HashDB, address_hash: H256) -> Box<HashDB + 'db> {
match *self {
Factory::Mangled => Box::new(AccountDBMut::from_hash(db, address_hash)),
Factory::Plain => Box::new(WrappingMut(db)),
}
}
}
// TODO: introduce HashDBMut?
/// DB backend wrapper for Account trie
/// Transforms trie node keys for the database
@@ -162,4 +194,79 @@ impl<'db> HashDB for AccountDBMut<'db>{
}
}
struct Wrapping<'db>(&'db HashDB);
impl<'db> HashDB for Wrapping<'db> {
fn keys(&self) -> HashMap<H256, i32> {
unimplemented!()
}
fn get(&self, key: &H256) -> Option<&[u8]> {
if key == &SHA3_NULL_RLP {
return Some(&NULL_RLP_STATIC);
}
self.0.get(key)
}
fn contains(&self, key: &H256) -> bool {
if key == &SHA3_NULL_RLP {
return true;
}
self.0.contains(key)
}
fn insert(&mut self, _value: &[u8]) -> H256 {
unimplemented!()
}
fn emplace(&mut self, _key: H256, _value: Bytes) {
unimplemented!()
}
fn remove(&mut self, _key: &H256) {
unimplemented!()
}
}
struct WrappingMut<'db>(&'db mut HashDB);
impl<'db> HashDB for WrappingMut<'db>{
fn keys(&self) -> HashMap<H256, i32> {
unimplemented!()
}
fn get(&self, key: &H256) -> Option<&[u8]> {
if key == &SHA3_NULL_RLP {
return Some(&NULL_RLP_STATIC);
}
self.0.get(key)
}
fn contains(&self, key: &H256) -> bool {
if key == &SHA3_NULL_RLP {
return true;
}
self.0.contains(key)
}
fn insert(&mut self, value: &[u8]) -> H256 {
if value == &NULL_RLP {
return SHA3_NULL_RLP.clone();
}
self.0.insert(value)
}
fn emplace(&mut self, key: H256, value: Bytes) {
if key == SHA3_NULL_RLP {
return;
}
self.0.emplace(key, value)
}
fn remove(&mut self, key: &H256) {
if key == &SHA3_NULL_RLP {
return;
}
self.0.remove(key)
}
}

View File

@@ -21,7 +21,7 @@ use engines::Engine;
use state::*;
use verification::PreverifiedBlock;
use trace::FlatTrace;
use evm::Factory as EvmFactory;
use factory::Factories;
/// A block, encoded as it is on the block chain.
#[derive(Default, Debug, Clone, PartialEq)]
@@ -192,7 +192,6 @@ impl IsBlock for ExecutedBlock {
pub struct OpenBlock<'x> {
block: ExecutedBlock,
engine: &'x Engine,
vm_factory: &'x EvmFactory,
last_hashes: Arc<LastHashes>,
}
@@ -230,8 +229,7 @@ impl<'x> OpenBlock<'x> {
/// Create a new `OpenBlock` ready for transaction pushing.
pub fn new(
engine: &'x Engine,
vm_factory: &'x EvmFactory,
trie_factory: TrieFactory,
factories: Factories,
tracing: bool,
db: Box<JournalDB>,
parent: &Header,
@@ -240,11 +238,10 @@ 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(), trie_factory));
let state = try!(State::from_existing(db, parent.state_root().clone(), engine.account_start_nonce(), factories));
let mut r = OpenBlock {
block: ExecutedBlock::new(state, tracing),
engine: engine,
vm_factory: vm_factory,
last_hashes: last_hashes,
};
@@ -332,7 +329,7 @@ impl<'x> OpenBlock<'x> {
let env_info = self.env_info();
// info!("env_info says gas_used={}", env_info.gas_used);
match self.block.state.apply(&env_info, self.engine, self.vm_factory, &t, self.block.traces.is_some()) {
match self.block.state.apply(&env_info, self.engine, &t, self.block.traces.is_some()) {
Ok(outcome) => {
self.block.transactions_set.insert(h.unwrap_or_else(||t.hash()));
self.block.base.transactions.push(t);
@@ -421,14 +418,13 @@ impl ClosedBlock {
}
/// Given an engine reference, reopen the `ClosedBlock` into an `OpenBlock`.
pub fn reopen<'a>(self, engine: &'a Engine, vm_factory: &'a EvmFactory) -> OpenBlock<'a> {
pub fn reopen<'a>(self, engine: &'a Engine) -> OpenBlock<'a> {
// revert rewards (i.e. set state back at last transaction's state).
let mut block = self.block;
block.state = self.unclosed_state;
OpenBlock {
block: block,
engine: engine,
vm_factory: vm_factory,
last_hashes: self.last_hashes,
}
}
@@ -499,17 +495,16 @@ pub fn enact(
db: Box<JournalDB>,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
factories: Factories,
) -> 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(), trie_factory.clone()));
let s = try!(State::from_existing(db.boxed_clone(), parent.state_root().clone(), engine.account_start_nonce(), factories.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, trie_factory, tracing, db, parent, last_hashes, Address::new(), (3141562.into(), 31415620.into()), vec![]));
let mut b = try!(OpenBlock::new(engine, factories, tracing, db, parent, last_hashes, Address::new(), (3141562.into(), 31415620.into()), vec![]));
b.set_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp());
@@ -532,12 +527,11 @@ pub fn enact_bytes(
db: Box<JournalDB>,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
factories: Factories,
) -> 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, vm_factory, trie_factory)
enact(&header, &block.transactions(), &block.uncles(), engine, tracing, db, parent, last_hashes, factories)
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header
@@ -549,11 +543,10 @@ pub fn enact_verified(
db: Box<JournalDB>,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
factories: Factories,
) -> Result<LockedBlock, Error> {
let view = BlockView::new(&block.bytes);
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, vm_factory, trie_factory)
enact(&block.header, &block.transactions, &view.uncles(), engine, tracing, db, parent, last_hashes, factories)
}
/// Enact the block given by `block_bytes` using `engine` on the database `db` with given `parent` block header. Seal the block aferwards
@@ -565,11 +558,10 @@ pub fn enact_and_seal(
db: Box<JournalDB>,
parent: &Header,
last_hashes: Arc<LastHashes>,
vm_factory: &EvmFactory,
trie_factory: TrieFactory,
factories: Factories,
) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view();
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, vm_factory, trie_factory)).seal(engine, header.seal())))
Ok(try!(try!(enact_bytes(block_bytes, engine, tracing, db, parent, last_hashes, factories)).seal(engine, header.seal())))
}
#[cfg(test)]
@@ -587,8 +579,7 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(&*spec.engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(&*spec.engine, Default::default(), false, db, &genesis_header, last_hashes, Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
let _ = b.seal(&*spec.engine, vec![]);
}
@@ -603,9 +594,8 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let vm_factory = Default::default();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap()
.close_and_lock().seal(engine, vec![]).unwrap();
let orig_bytes = b.rlp_bytes();
let orig_db = b.drain();
@@ -613,7 +603,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()).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap();
assert_eq!(e.rlp_bytes(), orig_bytes);
@@ -632,9 +622,8 @@ mod tests {
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let vm_factory = Default::default();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let mut open_block = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes.clone(), Address::zero(), (3141562.into(), 31415620.into()), vec![]).unwrap();
let mut open_block = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes.clone(), 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();
@@ -649,7 +638,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()).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, &Default::default(), Default::default()).unwrap();
let e = enact_and_seal(&orig_bytes, engine, false, db, &genesis_header, last_hashes, Default::default()).unwrap();
let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes);

View File

@@ -65,6 +65,7 @@ use evm::Factory as EvmFactory;
use miner::{Miner, MinerService};
use util::TrieFactory;
use snapshot::{self, io as snapshot_io};
use factory::Factories;
// re-export
pub use types::blockchain_info::BlockChainInfo;
@@ -130,8 +131,6 @@ pub struct Client {
import_lock: Mutex<()>,
panic_handler: Arc<PanicHandler>,
verifier: Box<Verifier>,
vm_factory: Arc<EvmFactory>,
trie_factory: TrieFactory,
miner: Arc<Miner>,
sleep_state: Mutex<SleepState>,
liveness: AtomicBool,
@@ -139,6 +138,7 @@ pub struct Client {
notify: RwLock<Vec<Weak<ChainNotify>>>,
queue_transactions: AtomicUsize,
last_hashes: RwLock<VecDeque<H256>>,
factories: Factories,
}
const HISTORY: u64 = 1200;
@@ -188,6 +188,13 @@ impl Client {
panic_handler.forward_from(&block_queue);
let awake = match config.mode { Mode::Dark(..) => false, _ => true };
let factories = Factories {
vm: EvmFactory::new(config.vm_type),
trie: TrieFactory::new(config.trie_spec),
accountdb: Default::default(),
};
let client = Client {
sleep_state: Mutex::new(SleepState::new(awake)),
liveness: AtomicBool::new(awake),
@@ -202,13 +209,12 @@ impl Client {
import_lock: Mutex::new(()),
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,
notify: RwLock::new(Vec::new()),
queue_transactions: AtomicUsize::new(0),
last_hashes: RwLock::new(VecDeque::new()),
factories: factories,
};
Ok(Arc::new(client))
}
@@ -289,7 +295,7 @@ impl Client {
let last_hashes = self.build_last_hashes(header.parent_hash.clone());
let db = self.state_db.lock().boxed_clone();
let enact_result = enact_verified(block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, &self.vm_factory, self.trie_factory.clone());
let enact_result = enact_verified(block, engine, self.tracedb.tracing_enabled(), db, &parent, last_hashes, self.factories.clone());
if let Err(e) = enact_result {
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(());
@@ -493,7 +499,7 @@ impl Client {
let root = HeaderView::new(&header).state_root();
State::from_existing(db, root, self.engine.account_start_nonce(), self.trie_factory.clone()).ok()
State::from_existing(db, root, self.engine.account_start_nonce(), self.factories.clone()).ok()
})
}
@@ -518,7 +524,7 @@ impl Client {
self.state_db.lock().boxed_clone(),
HeaderView::new(&self.best_block_header()).state_root(),
self.engine.account_start_nonce(),
self.trie_factory.clone())
self.factories.clone())
.expect("State root of best block header always valid.")
}
@@ -688,7 +694,7 @@ impl BlockChainClient for Client {
state.add_balance(&sender, &(needed_balance - balance));
}
let options = TransactOptions { tracing: analytics.transaction_tracing, vm_tracing: analytics.vm_tracing, check_nonce: false };
let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, &self.vm_factory).transact(t, options));
let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(t, options));
// TODO gav move this into Executive.
ret.state_diff = original_state.map(|original| state.diff_from(original));
@@ -720,7 +726,7 @@ impl BlockChainClient for Client {
gas_limit: view.gas_limit(),
};
for t in txs.iter().take(address.index) {
match Executive::new(&mut state, &env_info, &*self.engine, &self.vm_factory).transact(t, Default::default()) {
match Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(t, Default::default()) {
Ok(x) => { env_info.gas_used = env_info.gas_used + x.gas_used; }
Err(ee) => { return Err(CallError::Execution(ee)) }
}
@@ -728,7 +734,7 @@ impl BlockChainClient for Client {
let t = &txs[address.index];
let original_state = if analytics.state_diffing { Some(state.clone()) } else { None };
let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, &self.vm_factory).transact(t, options));
let mut ret = try!(Executive::new(&mut state, &env_info, &*self.engine, &self.factories.vm).transact(t, options));
ret.state_diff = original_state.map(|original| state.diff_from(original));
Ok(ret)
@@ -1029,8 +1035,7 @@ impl MiningBlockChainClient for Client {
let mut open_block = OpenBlock::new(
engine,
&self.vm_factory,
self.trie_factory.clone(),
self.factories.clone(),
false, // TODO: this will need to be parameterised once we want to do immediate mining insertion.
self.state_db.lock().boxed_clone(),
&self.chain.block_header(&h).expect("h is best block hash: so its header must exist: qed"),
@@ -1054,7 +1059,7 @@ impl MiningBlockChainClient for Client {
}
fn vm_factory(&self) -> &EvmFactory {
&self.vm_factory
&self.factories.vm
}
fn import_sealed_block(&self, block: SealedBlock) -> ImportResult {

View File

@@ -276,7 +276,6 @@ impl MiningBlockChainClient for TestBlockChainClient {
let last_hashes = vec![genesis_header.hash()];
let mut open_block = OpenBlock::new(
engine,
self.vm_factory(),
Default::default(),
false,
db,

View File

@@ -252,8 +252,7 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, 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, seal).is_ok());

View File

@@ -86,8 +86,7 @@ mod tests {
let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let last_hashes = Arc::new(vec![genesis_header.hash()]);
let vm_factory = Default::default();
let b = OpenBlock::new(engine, &vm_factory, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = OpenBlock::new(engine, Default::default(), false, db, &genesis_header, last_hashes, addr, (3141562.into(), 31415620.into()), vec![]).unwrap();
let b = b.close_and_lock();
// Seal with empty AccountProvider.
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();

View File

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

View File

@@ -80,6 +80,7 @@ impl VMType {
}
/// Evm factory. Creates appropriate Evm.
#[derive(Clone)]
pub struct Factory {
evm: VMType
}
@@ -128,7 +129,7 @@ impl Factory {
impl Default for Factory {
/// Returns jitvm factory
#[cfg(feature = "jit")]
#[cfg(all(feature = "jit", not(test)))]
fn default() -> Factory {
Factory {
evm: VMType::Jit
@@ -136,7 +137,7 @@ impl Default for Factory {
}
/// Returns native rust evm factory
#[cfg(not(feature = "jit"))]
#[cfg(any(not(feature = "jit"), test))]
fn default() -> Factory {
Factory {
evm: VMType::Interpreter

30
ethcore/src/factory.rs Normal file
View File

@@ -0,0 +1,30 @@
// Copyright 2015, 2016 Ethcore (UK) Ltd.
// This file is part of Parity.
// Parity is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
// Parity is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
// You should have received a copy of the GNU General Public License
// along with Parity. If not, see <http://www.gnu.org/licenses/>.
use util::trie::TrieFactory;
use evm::Factory as EvmFactory;
use account_db::Factory as AccountFactory;
/// Collection of factories.
#[derive(Default, Clone)]
pub struct Factories {
/// factory for evm.
pub vm: EvmFactory,
/// factory for tries.
pub trie: TrieFactory,
/// factory for account databases.
pub accountdb: AccountFactory,
}

View File

@@ -64,8 +64,7 @@ pub fn json_chain_test(json_data: &[u8], era: ChainEra) -> Vec<String> {
state.populate_from(pre);
state.commit()
.expect(&format!("State test {} failed due to internal error.", name));
let vm_factory = Default::default();
let res = state.apply(&env, &*engine, &vm_factory, &transaction, false);
let res = state.apply(&env, &*engine, &transaction, false);
if fail_unless(state.root() == &post_state_root) {
println!("!!! {}: State mismatch (got: {}, expect: {}):", name, state.root(), post_state_root);

View File

@@ -139,6 +139,7 @@ mod externalities;
mod verification;
mod blockchain;
mod types;
mod factory;
#[cfg(test)]
mod tests;

View File

@@ -270,7 +270,7 @@ impl Miner {
Some(old_block) => {
trace!(target: "miner", "Already have previous work; updating and returning");
// add transactions to old_block
old_block.reopen(&*self.engine, chain.vm_factory())
old_block.reopen(&*self.engine)
}
None => {
// block not found - create it.

View File

@@ -17,8 +17,9 @@
//! Account state encoding and decoding
use account_db::{AccountDB, AccountDBMut};
use util::{U256, FixedHash, H256, Bytes, HashDB, SHA3_EMPTY, TrieDB};
use util::{U256, FixedHash, H256, Bytes, HashDB, SHA3_EMPTY};
use util::rlp::{Rlp, RlpStream, Stream, UntrustedRlp, View};
use util::trie::{TrieDB, Trie};
use snapshot::Error;
// An alternate account structure from ::account::Account.

View File

@@ -26,13 +26,14 @@ use engines::Engine;
use ids::BlockID;
use views::BlockView;
use util::{Bytes, Hashable, HashDB, snappy, TrieDB, TrieDBMut, TrieMut};
use util::{Bytes, Hashable, HashDB, snappy};
use util::Mutex;
use util::hash::{FixedHash, H256};
use util::journaldb::{self, Algorithm, JournalDB};
use util::kvdb::Database;
use util::rlp::{DecoderError, RlpStream, Stream, UntrustedRlp, View, Compressible, RlpType};
use util::rlp::SHA3_NULL_RLP;
use util::trie::{TrieDB, TrieDBMut, Trie, TrieMut};
use self::account::Account;
use self::block::AbridgedBlock;

View File

@@ -24,7 +24,7 @@ use snapshot::account::Account;
use util::hash::{FixedHash, H256};
use util::hashdb::HashDB;
use util::trie::{Alphabet, StandardMap, SecTrieDBMut, TrieMut, ValueMode};
use util::trie::{TrieDB, TrieDBMut};
use util::trie::{TrieDB, TrieDBMut, Trie};
use util::rlp::SHA3_NULL_RLP;
// the proportion of accounts we will alter each tick.
@@ -51,10 +51,12 @@ impl StateProducer {
// modify existing accounts.
let mut accounts_to_modify: Vec<_> = {
let trie = TrieDB::new(&*db, &self.state_root).unwrap();
trie.iter()
let temp = trie.iter() // binding required due to complicated lifetime stuff
.filter(|_| rng.gen::<f32>() < ACCOUNT_CHURN)
.map(|(k, v)| (H256::from_slice(&k), v.to_owned()))
.collect()
.collect();
temp
};
// sweep once to alter storage tries.

View File

@@ -19,7 +19,6 @@
use std::collections::hash_map::Entry;
use util::*;
use pod_account::*;
use account_db::*;
use std::cell::{Ref, RefCell, Cell};
@@ -148,7 +147,7 @@ impl Account {
}
/// Get (and cache) the contents of the trie's storage at `key`.
pub fn storage_at(&self, db: &AccountDB, key: &H256) -> H256 {
pub fn storage_at(&self, db: &HashDB, key: &H256) -> H256 {
self.storage_overlay.borrow_mut().entry(key.clone()).or_insert_with(||{
let db = SecTrieDB::new(db, &self.storage_root)
.expect("Account storage_root initially set to zero (valid) and only altered by SecTrieDBMut. \
@@ -225,7 +224,7 @@ impl Account {
}
/// Provide a database to get `code_hash`. Should not be called if it is a contract without code.
pub fn cache_code(&mut self, db: &AccountDB) -> bool {
pub fn cache_code(&mut self, db: &HashDB) -> bool {
// TODO: fill out self.code_cache;
trace!("Account::cache_code: ic={}; self.code_hash={:?}, self.code_cache={}", self.is_cached(), self.code_hash, self.code_cache.pretty());
self.is_cached() ||
@@ -277,7 +276,7 @@ impl Account {
}
/// Commit the `storage_overlay` to the backing DB and update `storage_root`.
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut AccountDBMut) {
pub fn commit_storage(&mut self, trie_factory: &TrieFactory, db: &mut HashDB) {
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 \
@@ -300,7 +299,7 @@ impl Account {
}
/// Commit any unsaved code. `code_hash` will always return the hash of the `code_cache` after this.
pub fn commit_code(&mut self, db: &mut AccountDBMut) {
pub fn commit_code(&mut self, db: &mut HashDB) {
trace!("Commiting code of {:?} - {:?}, {:?}", self, self.code_hash.is_none(), self.code_cache.is_empty());
match (self.code_hash.is_none(), self.code_cache.is_empty()) {
(true, true) => self.code_hash = Some(SHA3_EMPTY),

View File

@@ -18,8 +18,7 @@ use std::cell::{RefCell, RefMut};
use common::*;
use engines::Engine;
use executive::{Executive, TransactOptions};
use evm::Factory as EvmFactory;
use account_db::*;
use factory::Factories;
use trace::FlatTrace;
use pod_account::*;
use pod_state::{self, PodState};
@@ -49,7 +48,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,
factories: Factories,
}
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. \
@@ -58,11 +57,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, trie_factory: TrieFactory) -> State {
pub fn new(mut db: Box<JournalDB>, account_start_nonce: U256, factories: Factories) -> State {
let mut root = H256::new();
{
// init trie and reset root too null
let _ = trie_factory.create(db.as_hashdb_mut(), &mut root);
let _ = factories.trie.create(db.as_hashdb_mut(), &mut root);
}
State {
@@ -71,12 +70,12 @@ impl State {
cache: RefCell::new(HashMap::new()),
snapshots: RefCell::new(Vec::new()),
account_start_nonce: account_start_nonce,
trie_factory: trie_factory,
factories: factories,
}
}
/// Creates new state with existing state root
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256, trie_factory: TrieFactory) -> Result<State, TrieError> {
pub fn from_existing(db: Box<JournalDB>, root: H256, account_start_nonce: U256, factories: Factories) -> Result<State, TrieError> {
if !db.as_hashdb().contains(&root) {
return Err(TrieError::InvalidStateRoot(root));
}
@@ -87,7 +86,7 @@ impl State {
cache: RefCell::new(HashMap::new()),
snapshots: RefCell::new(Vec::new()),
account_start_nonce: account_start_nonce,
trie_factory: trie_factory,
factories: factories
};
Ok(state)
@@ -185,8 +184,11 @@ impl State {
/// Mutate storage of account `address` so that it is `value` for `key`.
pub fn storage_at(&self, address: &Address, key: &H256) -> H256 {
self.ensure_cached(address, false,
|a| a.as_ref().map_or(H256::new(), |a|a.storage_at(&AccountDB::from_hash(self.db.as_hashdb(), a.address_hash(address)), key)))
self.ensure_cached(address, false, |a| a.as_ref().map_or(H256::new(), |a| {
let addr_hash = a.address_hash(address);
let db = self.factories.accountdb.readonly(self.db.as_hashdb(), addr_hash);
a.storage_at(db.as_hashdb(), key)
}))
}
/// Mutate storage of account `a` so that it is `value` for `key`.
@@ -236,11 +238,12 @@ impl State {
/// Execute a given transaction.
/// This will change the state accordingly.
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, vm_factory: &EvmFactory, t: &SignedTransaction, tracing: bool) -> ApplyResult {
pub fn apply(&mut self, env_info: &EnvInfo, engine: &Engine, t: &SignedTransaction, tracing: bool) -> ApplyResult {
// let old = self.to_pod();
let options = TransactOptions { tracing: tracing, vm_tracing: false, check_nonce: true };
let e = try!(Executive::new(self, env_info, engine, vm_factory).transact(t, options));
let vm_factory = self.factories.vm.clone();
let e = try!(Executive::new(self, env_info, engine, &vm_factory).transact(t, options));
// TODO uncomment once to_pod() works correctly.
// trace!("Applied transaction. Diff:\n{}\n", state_diff::diff_pod(&old, &self.to_pod()));
@@ -254,27 +257,27 @@ impl State {
/// `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(
trie_factory: &TrieFactory,
factories: &Factories,
db: &mut HashDB,
root: &mut H256,
accounts: &mut HashMap<Address,
Option<Account>>
accounts: &mut HashMap<Address, Option<Account>>
) -> Result<(), Error> {
// 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) if account.is_dirty() => {
let mut account_db = AccountDBMut::from_hash(db, account.address_hash(address));
account.commit_storage(trie_factory, &mut account_db);
account.commit_code(&mut account_db);
let addr_hash = account.address_hash(address);
let mut account_db = factories.accountdb.create(db, addr_hash);
account.commit_storage(&factories.trie, account_db.as_hashdb_mut());
account.commit_code(account_db.as_hashdb_mut());
}
_ => {}
}
}
{
let mut trie = trie_factory.from_existing(db, root).unwrap();
let mut trie = factories.trie.from_existing(db, root).unwrap();
for (address, ref mut a) in accounts.iter_mut() {
match **a {
Some(ref mut account) if account.is_dirty() => {
@@ -293,7 +296,7 @@ impl State {
/// Commits our cached account changes into the trie.
pub fn commit(&mut self) -> Result<(), Error> {
assert!(self.snapshots.borrow().is_empty());
Self::commit_into(&self.trie_factory, self.db.as_hashdb_mut(), &mut self.root, &mut *self.cache.borrow_mut())
Self::commit_into(&self.factories, self.db.as_hashdb_mut(), &mut self.root, &mut *self.cache.borrow_mut())
}
/// Clear state cache
@@ -351,7 +354,7 @@ impl State {
where F: FnOnce(&Option<Account>) -> U {
let have_key = self.cache.borrow().contains_key(a);
if !have_key {
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let maybe_acc = match db.get(a) {
Ok(acc) => acc.map(Account::from_rlp),
Err(e) => panic!("Potential DB corruption encountered: {}", e),
@@ -361,7 +364,8 @@ impl State {
if require_code {
if let Some(ref mut account) = self.cache.borrow_mut().get_mut(a).unwrap().as_mut() {
let addr_hash = account.address_hash(a);
account.cache_code(&AccountDB::from_hash(self.db.as_hashdb(), addr_hash));
let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), addr_hash);
account.cache_code(accountdb.as_hashdb());
}
}
@@ -380,7 +384,7 @@ impl State {
{
let contains_key = self.cache.borrow().contains_key(a);
if !contains_key {
let db = self.trie_factory.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let db = self.factories.trie.readonly(self.db.as_hashdb(), &self.root).expect(SEC_TRIE_DB_UNWRAP_STR);
let maybe_acc = match db.get(a) {
Ok(acc) => acc.map(Account::from_rlp),
Err(e) => panic!("Potential DB corruption encountered: {}", e),
@@ -400,7 +404,8 @@ impl State {
let account = c.get_mut(a).unwrap().as_mut().unwrap();
if require_code {
let addr_hash = account.address_hash(a);
account.cache_code(&AccountDB::from_hash(self.db.as_hashdb(), addr_hash));
let accountdb = self.factories.accountdb.readonly(self.db.as_hashdb(), addr_hash);
account.cache_code(accountdb.as_hashdb());
}
account
})
@@ -421,7 +426,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(),
factories: self.factories.clone(),
}
}
}
@@ -464,8 +469,7 @@ fn should_apply_create_transaction() {
}.sign(&"".sha3());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 0,
@@ -525,8 +529,7 @@ fn should_trace_failed_create_transaction() {
}.sign(&"".sha3());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
action: trace::Action::Create(trace::Create {
@@ -564,8 +567,7 @@ fn should_trace_call_transaction() {
state.init_code(&0xa.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
action: trace::Action::Call(trace::Call {
@@ -607,8 +609,7 @@ fn should_trace_basic_call_transaction() {
}.sign(&"".sha3());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
action: trace::Action::Call(trace::Call {
@@ -649,8 +650,7 @@ fn should_trace_call_transaction_to_builtin() {
data: vec![],
}.sign(&"".sha3());
let vm_factory = Default::default();
let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
@@ -693,8 +693,7 @@ fn should_not_trace_subcall_transaction_to_builtin() {
}.sign(&"".sha3());
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060006001610be0f1").unwrap());
let vm_factory = Default::default();
let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
@@ -738,8 +737,7 @@ fn should_not_trace_callcode() {
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b611000f2").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
let vm_factory = Default::default();
let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
@@ -801,8 +799,7 @@ fn should_not_trace_delegatecall() {
state.init_code(&0xa.into(), FromHex::from_hex("6000600060006000600b618000f4").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
let vm_factory = Default::default();
let result = state.apply(&info, engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
@@ -861,8 +858,7 @@ fn should_trace_failed_call_transaction() {
state.init_code(&0xa.into(), FromHex::from_hex("5b600056").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
action: trace::Action::Call(trace::Call {
@@ -903,8 +899,7 @@ fn should_trace_call_with_subcall_transaction() {
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
@@ -963,8 +958,7 @@ fn should_trace_call_with_basic_subcall_transaction() {
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006045600b6000f1").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
@@ -1019,8 +1013,7 @@ fn should_not_trace_call_with_invalid_basic_subcall_transaction() {
state.init_code(&0xa.into(), FromHex::from_hex("600060006000600060ff600b6000f1").unwrap()); // not enough funds.
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 0,
@@ -1064,8 +1057,7 @@ fn should_trace_failed_subcall_transaction() {
state.init_code(&0xa.into(), FromHex::from_hex("60006000600060006000600b602b5a03f1").unwrap());
state.init_code(&0xb.into(), FromHex::from_hex("5b600056").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
@@ -1122,8 +1114,7 @@ fn should_trace_call_with_subcall_with_subcall_transaction() {
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1").unwrap());
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,
@@ -1198,8 +1189,7 @@ fn should_trace_failed_subcall_with_subcall_transaction() {
state.init_code(&0xb.into(), FromHex::from_hex("60006000600060006000600c602b5a03f1505b601256").unwrap());
state.init_code(&0xc.into(), FromHex::from_hex("6000").unwrap());
state.add_balance(t.sender().as_ref().unwrap(), &(100.into()));
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
@@ -1271,8 +1261,7 @@ fn should_trace_suicide() {
state.init_code(&0xa.into(), FromHex::from_hex("73000000000000000000000000000000000000000bff").unwrap());
state.add_balance(&0xa.into(), &50.into());
state.add_balance(t.sender().as_ref().unwrap(), &100.into());
let vm_factory = Default::default();
let result = state.apply(&info, &engine, &vm_factory, &t, true).unwrap();
let result = state.apply(&info, &engine, &t, true).unwrap();
let expected_trace = vec![FlatTrace {
trace_address: Default::default(),
subtraces: 1,

View File

@@ -139,7 +139,6 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
let mut db_result = get_temp_journal_db();
let mut db = db_result.take();
test_spec.ensure_db_good(db.as_hashdb_mut()).unwrap();
let vm_factory = Default::default();
let genesis_header = test_spec.genesis_header();
let mut rolling_timestamp = 40;
@@ -156,7 +155,6 @@ pub fn generate_dummy_client_with_spec_and_data<F>(get_test_spec: F, block_numbe
// forge block.
let mut b = OpenBlock::new(
test_engine,
&vm_factory,
Default::default(),
false,
db,