Fatdb integration with CLI (#1464)

* fatdb integration

* --fat-db

* rerun with --pruning=archive comment
This commit is contained in:
Marek Kotewicz 2016-07-01 20:29:56 +02:00 committed by Gav Wood
parent 0a513ad06e
commit d8a4cca817
11 changed files with 91 additions and 56 deletions

View File

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

View File

@ -254,7 +254,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); 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 b = b.close_and_lock();
let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap(); let seal = engine.generate_seal(b.block(), Some(&tap)).unwrap();
assert!(b.try_seal(engine.deref(), seal).is_ok()); assert!(b.try_seal(engine.deref(), seal).is_ok());

View File

@ -222,6 +222,7 @@ impl<'x> OpenBlock<'x> {
pub fn new( pub fn new(
engine: &'x Engine, engine: &'x Engine,
vm_factory: &'x EvmFactory, vm_factory: &'x EvmFactory,
trie_factory: TrieFactory,
tracing: bool, tracing: bool,
db: Box<JournalDB>, db: Box<JournalDB>,
parent: &Header, parent: &Header,
@ -231,7 +232,7 @@ impl<'x> OpenBlock<'x> {
gas_range_target: (U256, U256), gas_range_target: (U256, U256),
extra_data: Bytes, extra_data: Bytes,
) -> Result<Self, Error> { ) -> 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 { let mut r = OpenBlock {
block: ExecutedBlock::new(state, tracing), block: ExecutedBlock::new(state, tracing),
engine: engine, engine: engine,
@ -481,16 +482,17 @@ pub fn enact(
parent: &Header, parent: &Header,
last_hashes: LastHashes, last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>, dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> { ) -> Result<LockedBlock, Error> {
{ {
if ::log::max_log_level() >= ::log::LogLevel::Trace { 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())); 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_difficulty(*header.difficulty());
b.set_gas_limit(*header.gas_limit()); b.set_gas_limit(*header.gas_limit());
b.set_timestamp(header.timestamp()); b.set_timestamp(header.timestamp());
@ -509,11 +511,12 @@ pub fn enact_bytes(
parent: &Header, parent: &Header,
last_hashes: LastHashes, last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>, dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> { ) -> Result<LockedBlock, Error> {
let block = BlockView::new(block_bytes); let block = BlockView::new(block_bytes);
let header = block.header(); 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 /// 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, parent: &Header,
last_hashes: LastHashes, last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>, dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<LockedBlock, Error> { ) -> Result<LockedBlock, Error> {
let view = BlockView::new(&block.bytes); 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 /// 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, parent: &Header,
last_hashes: LastHashes, last_hashes: LastHashes,
dao_rescue_block_gas_limit: Option<U256>, dao_rescue_block_gas_limit: Option<U256>,
vm_factory: &EvmFactory vm_factory: &EvmFactory,
trie_factory: TrieFactory,
) -> Result<SealedBlock, Error> { ) -> Result<SealedBlock, Error> {
let header = BlockView::new(block_bytes).header_view(); 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)] #[cfg(test)]
@ -565,7 +570,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); 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 = b.close_and_lock();
let _ = b.seal(engine.deref(), vec![]); let _ = b.seal(engine.deref(), vec![]);
} }
@ -581,7 +586,7 @@ mod tests {
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default(); 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(); .close_and_lock().seal(engine.deref(), vec![]).unwrap();
let orig_bytes = b.rlp_bytes(); let orig_bytes = b.rlp_bytes();
let orig_db = b.drain(); let orig_db = b.drain();
@ -589,7 +594,7 @@ mod tests {
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); 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); assert_eq!(e.rlp_bytes(), orig_bytes);
@ -609,7 +614,7 @@ mod tests {
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let vm_factory = Default::default(); 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(); let mut uncle1_header = Header::new();
uncle1_header.extra_data = b"uncle1".to_vec(); uncle1_header.extra_data = b"uncle1".to_vec();
let mut uncle2_header = Header::new(); let mut uncle2_header = Header::new();
@ -624,7 +629,7 @@ mod tests {
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); 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(); let bytes = e.rlp_bytes();
assert_eq!(bytes, orig_bytes); assert_eq!(bytes, orig_bytes);

View File

@ -94,6 +94,7 @@ pub struct Client {
panic_handler: Arc<PanicHandler>, panic_handler: Arc<PanicHandler>,
verifier: Box<Verifier>, verifier: Box<Verifier>,
vm_factory: Arc<EvmFactory>, vm_factory: Arc<EvmFactory>,
trie_factory: TrieFactory,
miner: Arc<Miner>, miner: Arc<Miner>,
io_channel: IoChannel<NetSyncMessage>, io_channel: IoChannel<NetSyncMessage>,
queue_transactions: AtomicUsize, queue_transactions: AtomicUsize,
@ -175,6 +176,7 @@ impl Client {
panic_handler: panic_handler, panic_handler: panic_handler,
verifier: verification::new(config.verifier_type), verifier: verification::new(config.verifier_type),
vm_factory: Arc::new(EvmFactory::new(config.vm_type)), vm_factory: Arc::new(EvmFactory::new(config.vm_type)),
trie_factory: TrieFactory::new(config.trie_spec),
miner: miner, miner: miner,
io_channel: message_channel, io_channel: message_channel,
queue_transactions: AtomicUsize::new(0), queue_transactions: AtomicUsize::new(0),
@ -233,7 +235,7 @@ impl Client {
let last_hashes = self.build_last_hashes(header.parent_hash.clone()); let last_hashes = self.build_last_hashes(header.parent_hash.clone());
let db = self.state_db.lock().unwrap().boxed_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 { if let Err(e) = enact_result {
warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e); warn!(target: "client", "Block import failed for #{} ({})\nError: {:?}", header.number(), header.hash(), e);
return Err(()); return Err(());
@ -418,13 +420,17 @@ impl Client {
let root = HeaderView::new(&header).state_root(); 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. /// Get a copy of the best block's state.
pub fn state(&self) -> 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.") .expect("State root of best block header always valid.")
} }
@ -809,6 +815,7 @@ impl MiningBlockChainClient for Client {
let mut open_block = OpenBlock::new( let mut open_block = OpenBlock::new(
engine, engine,
&self.vm_factory, &self.vm_factory,
self.trie_factory.clone(),
false, // TODO: this will need to be parameterised once we want to do immediate mining insertion. false, // TODO: this will need to be parameterised once we want to do immediate mining insertion.
self.state_db.lock().unwrap().boxed_clone(), 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"), &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 evm::VMType;
pub use verification::VerifierType; pub use verification::VerifierType;
use util::journaldb; use util::journaldb;
use util::trie::TrieSpec;
/// Client state db compaction profile /// Client state db compaction profile
#[derive(Debug, PartialEq)] #[derive(Debug, PartialEq)]
@ -45,6 +46,8 @@ pub struct ClientConfig {
pub tracing: TraceConfig, pub tracing: TraceConfig,
/// VM type. /// VM type.
pub vm_type: VMType, pub vm_type: VMType,
/// Trie type.
pub trie_spec: TrieSpec,
/// The JournalDB ("pruning") algorithm to use. /// The JournalDB ("pruning") algorithm to use.
pub pruning: journaldb::Algorithm, pub pruning: journaldb::Algorithm,
/// The name of the client instance. /// The name of the client instance.

View File

@ -325,7 +325,7 @@ mod tests {
spec.ensure_db_good(db.as_hashdb_mut()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); 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(); let b = b.close();
assert_eq!(b.state().balance(&Address::zero()), U256::from_str("4563918244f40000").unwrap()); 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()); spec.ensure_db_good(db.as_hashdb_mut());
let last_hashes = vec![genesis_header.hash()]; let last_hashes = vec![genesis_header.hash()];
let vm_factory = Default::default(); 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 mut uncle = Header::new();
let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106"); let uncle_author = address_from_hex("ef2d6d194084c2de36e0dabfce45d046b37d1106");
uncle.author = uncle_author.clone(); uncle.author = uncle_author.clone();

View File

@ -67,7 +67,7 @@ mod tests {
let mut db_result = get_temp_journal_db(); let mut db_result = get_temp_journal_db();
let mut db = db_result.take(); let mut db = db_result.take();
spec.ensure_db_good(db.as_hashdb_mut()); 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("0000000000000000000000000000000000000001")), U256::from(1u64));
assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000002")), 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)); assert_eq!(s.balance(&address_from_hex("0000000000000000000000000000000000000003")), U256::from(1u64));

View File

@ -42,6 +42,7 @@ pub struct State {
cache: RefCell<HashMap<Address, Option<Account>>>, cache: RefCell<HashMap<Address, Option<Account>>>,
snapshots: RefCell<Vec<HashMap<Address, Option<Option<Account>>>>>, snapshots: RefCell<Vec<HashMap<Address, Option<Option<Account>>>>>,
account_start_nonce: U256, 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. \ 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 { impl State {
/// Creates new state with empty state root /// Creates new state with empty state root
#[cfg(test)] #[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(); let mut root = H256::new();
{ {
// init trie and reset root too null // 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 { State {
@ -63,22 +64,26 @@ impl State {
cache: RefCell::new(HashMap::new()), cache: RefCell::new(HashMap::new()),
snapshots: RefCell::new(Vec::new()), snapshots: RefCell::new(Vec::new()),
account_start_nonce: account_start_nonce, account_start_nonce: account_start_nonce,
trie_factory: trie_factory,
} }
} }
/// Creates new state with existing state root /// 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) { if !db.as_hashdb().contains(&root) {
Err(TrieError::InvalidStateRoot) return 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,
})
} }
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 /// Create a recoverable snaphot of this state
@ -156,7 +161,7 @@ impl State {
/// Determine whether an account exists. /// Determine whether an account exists.
pub fn exists(&self, a: &Address) -> bool { 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) self.cache.borrow().get(&a).unwrap_or(&None).is_some() || db.contains(&a)
} }
@ -242,7 +247,10 @@ impl State {
for a in &addresses { for a in &addresses {
if self.code(a).map_or(false, |c| c.sha3() == broken_dao) { if self.code(a).map_or(false, |c| c.sha3() == broken_dao) {
// Figure out if the balance has been reduced. // 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)) { if maybe_original.map_or(false, |original| *original.balance() > self.balance(a)) {
return Err(Error::Transaction(TransactionError::DAORescue)); 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. /// 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. /// `accounts` is mutable because we may need to commit the code or storage and record that.
#[cfg_attr(feature="dev", allow(match_ref_pats))] #[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. // first, commit the sub trees.
// TODO: is this necessary or can we dispense with the `ref mut a` for just `a`? // 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() { for (address, ref mut a) in accounts.iter_mut() {
match a { match a {
&mut&mut Some(ref mut account) => { &mut&mut Some(ref mut account) => {
let mut account_db = AccountDBMut::new(db, address); 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); account.commit_code(&mut account_db);
} }
&mut&mut None => {} &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() { for (address, ref a) in accounts.iter() {
match **a { match **a {
Some(ref account) => trie.insert(address, &account.rlp()), Some(ref account) => trie.insert(address, &account.rlp()),
@ -290,7 +298,7 @@ impl State {
/// Commits our cached account changes into the trie. /// Commits our cached account changes into the trie.
pub fn commit(&mut self) { pub fn commit(&mut self) {
assert!(self.snapshots.borrow().is_empty()); 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)] #[cfg(test)]
@ -340,7 +348,7 @@ impl State {
fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option<Account> { fn get<'a>(&'a self, a: &Address, require_code: bool) -> &'a Option<Account> {
let have_key = self.cache.borrow().contains_key(a); let have_key = self.cache.borrow().contains_key(a);
if !have_key { 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)) self.insert_cache(a, db.get(&a).map(Account::from_rlp))
} }
if require_code { 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 { 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); let have_key = self.cache.borrow().contains_key(a);
if !have_key { 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)) self.insert_cache(a, db.get(&a).map(Account::from_rlp))
} else { } else {
self.note_cache(a); self.note_cache(a);
@ -396,6 +404,7 @@ impl Clone for State {
cache: RefCell::new(self.cache.borrow().clone()), cache: RefCell::new(self.cache.borrow().clone()),
snapshots: RefCell::new(self.snapshots.borrow().clone()), snapshots: RefCell::new(self.snapshots.borrow().clone()),
account_start_nonce: self.account_start_nonce.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() 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())); assert_eq!(state.code(&a), Some([1u8, 2, 3].to_vec()));
} }
@ -1194,7 +1203,7 @@ fn storage_at_from_database() {
state.drop() 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))); 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() 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.balance(&a), U256::from(69u64));
assert_eq!(state.nonce(&a), U256::from(1u64)); assert_eq!(state.nonce(&a), U256::from(1u64));
} }
@ -1244,7 +1253,7 @@ fn remove_from_database() {
}; };
let (root, db) = { 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.exists(&a), true);
assert_eq!(state.nonce(&a), U256::from(1u64)); assert_eq!(state.nonce(&a), U256::from(1u64));
state.kill_account(&a); state.kill_account(&a);
@ -1254,7 +1263,7 @@ fn remove_from_database() {
state.drop() 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.exists(&a), false);
assert_eq!(state.nonce(&a), U256::from(0u64)); 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( let mut b = OpenBlock::new(
test_engine.deref(), test_engine.deref(),
&vm_factory, &vm_factory,
Default::default(),
false, false,
db, db,
&last_header, &last_header,
@ -315,7 +316,7 @@ pub fn get_temp_state() -> GuardedTempResult<State> {
let journal_db = get_temp_journal_db_in(temp.as_path()); let journal_db = get_temp_journal_db_in(temp.as_path());
GuardedTempResult { GuardedTempResult {
_temp: temp, _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 { pub fn get_temp_state_in(path: &Path) -> State {
let journal_db = get_temp_journal_db_in(path); 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> { pub fn get_good_dummy_block_seq(count: usize) -> Vec<Bytes> {

View File

@ -203,6 +203,7 @@ Database Options:
--db-compaction TYPE Database compaction type. TYPE may be one of: --db-compaction TYPE Database compaction type. TYPE may be one of:
ssd - suitable for SSDs and fast HDDs; ssd - suitable for SSDs and fast HDDs;
hdd - suitable for slow HDDs [default: ssd]. hdd - suitable for slow HDDs [default: ssd].
--fat-db Fat database.
Import/Export Options: Import/Export Options:
--from BLOCK Export from block BLOCK, which may be an index or --from BLOCK Export from block BLOCK, which may be an index or
@ -362,6 +363,7 @@ pub struct Args {
pub flag_ipcapi: Option<String>, pub flag_ipcapi: Option<String>,
pub flag_db_cache_size: Option<usize>, pub flag_db_cache_size: Option<usize>,
pub flag_db_compaction: String, pub flag_db_compaction: String,
pub flag_fat_db: bool,
} }
pub fn print_version() { pub fn print_version() {

View File

@ -333,6 +333,14 @@ impl Configuration {
_ => { die!("Invalid pruning method given."); } _ => { die!("Invalid pruning method given."); }
}; };
if self.args.flag_fat_db {
if let journaldb::Algorithm::Archive = client_config.pruning {
client_config.trie_spec = TrieSpec::Fat;
} else {
die!("Fatdb is not supported. Please rerun with --pruning=archive")
}
}
// forced state db cache size if provided // forced state db cache size if provided
client_config.db_cache_size = self.args.flag_db_cache_size.and_then(|cs| Some(cs / 4)); client_config.db_cache_size = self.args.flag_db_cache_size.and_then(|cs| Some(cs / 4));