State copy optimization
This commit is contained in:
parent
d467ac76b0
commit
b9af3f9260
@ -62,7 +62,7 @@ impl Decodable for Block {
|
|||||||
/// Internal type for a block's common elements.
|
/// Internal type for a block's common elements.
|
||||||
// TODO: rename to ExecutedBlock
|
// TODO: rename to ExecutedBlock
|
||||||
// TODO: use BareBlock
|
// TODO: use BareBlock
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug)]
|
||||||
pub struct ExecutedBlock {
|
pub struct ExecutedBlock {
|
||||||
base: Block,
|
base: Block,
|
||||||
|
|
||||||
@ -318,8 +318,8 @@ impl IsBlock for SealedBlock {
|
|||||||
/// Enact the block given by block header, transactions and uncles
|
/// Enact the block given by block header, transactions and uncles
|
||||||
pub fn enact<'x, 'y>(header: &Header, transactions: &[Transaction], uncles: &[Header], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes) -> Result<ClosedBlock<'x, 'y>, Error> {
|
pub fn enact<'x, 'y>(header: &Header, transactions: &[Transaction], uncles: &[Header], engine: &'x Engine, db: JournalDB, parent: &Header, last_hashes: &'y LastHashes) -> Result<ClosedBlock<'x, 'y>, Error> {
|
||||||
{
|
{
|
||||||
let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce());
|
//let s = State::from_existing(db.clone(), parent.state_root().clone(), engine.account_start_nonce());
|
||||||
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 = OpenBlock::new(engine, db, parent, last_hashes, header.author().clone(), header.extra_data().clone());
|
let mut b = OpenBlock::new(engine, db, parent, last_hashes, header.author().clone(), header.extra_data().clone());
|
||||||
@ -363,10 +363,10 @@ mod tests {
|
|||||||
let engine = Spec::new_test().to_engine().unwrap();
|
let engine = Spec::new_test().to_engine().unwrap();
|
||||||
let genesis_header = engine.spec().genesis_header();
|
let genesis_header = engine.spec().genesis_header();
|
||||||
let mut db_result = get_temp_journal_db();
|
let mut db_result = get_temp_journal_db();
|
||||||
let db = db_result.reference_mut();
|
let mut db = db_result.take();
|
||||||
engine.spec().ensure_db_good(db);
|
engine.spec().ensure_db_good(&mut db);
|
||||||
let last_hashes = vec![genesis_header.hash()];
|
let last_hashes = vec![genesis_header.hash()];
|
||||||
let b = OpenBlock::new(engine.deref(), db.clone(), &genesis_header, &last_hashes, Address::zero(), vec![]);
|
let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]);
|
||||||
let b = b.close();
|
let b = b.close();
|
||||||
let _ = b.seal(vec![]);
|
let _ = b.seal(vec![]);
|
||||||
}
|
}
|
||||||
@ -378,16 +378,16 @@ mod tests {
|
|||||||
let genesis_header = engine.spec().genesis_header();
|
let genesis_header = engine.spec().genesis_header();
|
||||||
|
|
||||||
let mut db_result = get_temp_journal_db();
|
let mut db_result = get_temp_journal_db();
|
||||||
let db = db_result.reference_mut();
|
let mut db = db_result.take();
|
||||||
engine.spec().ensure_db_good(db);
|
engine.spec().ensure_db_good(&mut db);
|
||||||
let b = OpenBlock::new(engine.deref(), db.clone(), &genesis_header, &vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(vec![]).unwrap();
|
let b = OpenBlock::new(engine.deref(), db, &genesis_header, &vec![genesis_header.hash()], Address::zero(), vec![]).close().seal(vec![]).unwrap();
|
||||||
let orig_bytes = b.rlp_bytes();
|
let orig_bytes = b.rlp_bytes();
|
||||||
let orig_db = b.drain();
|
let orig_db = b.drain();
|
||||||
|
|
||||||
let mut db_result = get_temp_journal_db();
|
let mut db_result = get_temp_journal_db();
|
||||||
let db = db_result.reference_mut();
|
let mut db = db_result.take();
|
||||||
engine.spec().ensure_db_good(db);
|
engine.spec().ensure_db_good(&mut db);
|
||||||
let e = enact_and_seal(&orig_bytes, engine.deref(), db.clone(), &genesis_header, &vec![genesis_header.hash()]).unwrap();
|
let e = enact_and_seal(&orig_bytes, engine.deref(), db, &genesis_header, &vec![genesis_header.hash()]).unwrap();
|
||||||
|
|
||||||
assert_eq!(e.rlp_bytes(), orig_bytes);
|
assert_eq!(e.rlp_bytes(), orig_bytes);
|
||||||
|
|
||||||
|
@ -139,7 +139,7 @@ impl ClientReport {
|
|||||||
pub struct Client {
|
pub struct Client {
|
||||||
chain: Arc<RwLock<BlockChain>>,
|
chain: Arc<RwLock<BlockChain>>,
|
||||||
engine: Arc<Box<Engine>>,
|
engine: Arc<Box<Engine>>,
|
||||||
state_db: JournalDB,
|
state_db: Arc<DB>,
|
||||||
block_queue: RwLock<BlockQueue>,
|
block_queue: RwLock<BlockQueue>,
|
||||||
report: RwLock<ClientReport>,
|
report: RwLock<ClientReport>,
|
||||||
uncommited_states: RwLock<HashMap<H256, JournalDB>>,
|
uncommited_states: RwLock<HashMap<H256, JournalDB>>,
|
||||||
@ -186,7 +186,7 @@ impl Client {
|
|||||||
Ok(Arc::new(Client {
|
Ok(Arc::new(Client {
|
||||||
chain: chain,
|
chain: chain,
|
||||||
engine: engine.clone(),
|
engine: engine.clone(),
|
||||||
state_db: state_db,
|
state_db: db,
|
||||||
block_queue: RwLock::new(BlockQueue::new(engine, message_channel)),
|
block_queue: RwLock::new(BlockQueue::new(engine, message_channel)),
|
||||||
report: RwLock::new(Default::default()),
|
report: RwLock::new(Default::default()),
|
||||||
uncommited_states: RwLock::new(HashMap::new()),
|
uncommited_states: RwLock::new(HashMap::new()),
|
||||||
@ -242,7 +242,7 @@ impl Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let db = self.state_db.clone();
|
let db = JournalDB::new_with_arc(self.state_db.clone());
|
||||||
let result = match enact_verified(&block, self.engine.deref().deref(), db, &parent, &last_hashes) {
|
let result = match enact_verified(&block, self.engine.deref().deref(), db, &parent, &last_hashes) {
|
||||||
Ok(b) => b,
|
Ok(b) => b,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
@ -284,7 +284,7 @@ impl Client {
|
|||||||
|
|
||||||
/// 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.clone(), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce())
|
State::from_existing(JournalDB::new_with_arc(self.state_db.clone()), HeaderView::new(&self.best_block_header()).state_root(), self.engine.account_start_nonce())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get info on the cache.
|
/// Get info on the cache.
|
||||||
|
@ -232,10 +232,10 @@ fn on_close_block() {
|
|||||||
let engine = new_morden().to_engine().unwrap();
|
let engine = new_morden().to_engine().unwrap();
|
||||||
let genesis_header = engine.spec().genesis_header();
|
let genesis_header = engine.spec().genesis_header();
|
||||||
let mut db_result = get_temp_journal_db();
|
let mut db_result = get_temp_journal_db();
|
||||||
let mut db = db_result.reference_mut();
|
let mut db = db_result.take();
|
||||||
engine.spec().ensure_db_good(db);
|
engine.spec().ensure_db_good(&mut db);
|
||||||
let last_hashes = vec![genesis_header.hash()];
|
let last_hashes = vec![genesis_header.hash()];
|
||||||
let b = OpenBlock::new(engine.deref(), db.clone(), &genesis_header, &last_hashes, Address::zero(), vec![]);
|
let b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]);
|
||||||
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());
|
||||||
}
|
}
|
||||||
@ -246,10 +246,10 @@ fn on_close_block_with_uncle() {
|
|||||||
let engine = new_morden().to_engine().unwrap();
|
let engine = new_morden().to_engine().unwrap();
|
||||||
let genesis_header = engine.spec().genesis_header();
|
let genesis_header = engine.spec().genesis_header();
|
||||||
let mut db_result = get_temp_journal_db();
|
let mut db_result = get_temp_journal_db();
|
||||||
let mut db = db_result.reference_mut();
|
let mut db = db_result.take();
|
||||||
engine.spec().ensure_db_good(db);
|
engine.spec().ensure_db_good(&mut db);
|
||||||
let last_hashes = vec![genesis_header.hash()];
|
let last_hashes = vec![genesis_header.hash()];
|
||||||
let mut b = OpenBlock::new(engine.deref(), db.clone(), &genesis_header, &last_hashes, Address::zero(), vec![]);
|
let mut b = OpenBlock::new(engine.deref(), db, &genesis_header, &last_hashes, Address::zero(), vec![]);
|
||||||
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();
|
||||||
|
@ -44,9 +44,9 @@ mod tests {
|
|||||||
let engine = new_morden().to_engine().unwrap();
|
let engine = new_morden().to_engine().unwrap();
|
||||||
let genesis_header = engine.spec().genesis_header();
|
let genesis_header = engine.spec().genesis_header();
|
||||||
let mut db_result = get_temp_journal_db();
|
let mut db_result = get_temp_journal_db();
|
||||||
let mut db = db_result.reference_mut();
|
let mut db = db_result.take();
|
||||||
engine.spec().ensure_db_good(db);
|
engine.spec().ensure_db_good(&mut db);
|
||||||
let s = State::from_existing(db.clone(), genesis_header.state_root.clone(), engine.account_start_nonce());
|
let s = State::from_existing(db, genesis_header.state_root.clone(), engine.account_start_nonce());
|
||||||
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));
|
||||||
|
@ -194,7 +194,7 @@ impl<'a> Executive<'a> {
|
|||||||
/// Returns either gas_left or `evm::Error`.
|
/// Returns either gas_left or `evm::Error`.
|
||||||
pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result {
|
pub fn call(&mut self, params: ActionParams, substate: &mut Substate, mut output: BytesRef) -> evm::Result {
|
||||||
// backup used in case of running out of gas
|
// backup used in case of running out of gas
|
||||||
let backup = self.state.clone();
|
self.state.snapshot();
|
||||||
|
|
||||||
// at first, transfer value to destination
|
// at first, transfer value to destination
|
||||||
if let ActionValue::Transfer(val) = params.value {
|
if let ActionValue::Transfer(val) = params.value {
|
||||||
@ -212,11 +212,12 @@ impl<'a> Executive<'a> {
|
|||||||
match cost <= params.gas {
|
match cost <= params.gas {
|
||||||
true => {
|
true => {
|
||||||
self.engine.execute_builtin(¶ms.code_address, data, &mut output);
|
self.engine.execute_builtin(¶ms.code_address, data, &mut output);
|
||||||
|
self.state.clear_snapshot();
|
||||||
Ok(params.gas - cost)
|
Ok(params.gas - cost)
|
||||||
},
|
},
|
||||||
// just drain the whole gas
|
// just drain the whole gas
|
||||||
false => {
|
false => {
|
||||||
self.state.revert(backup);
|
self.state.revert_snapshot();
|
||||||
Err(evm::Error::OutOfGas)
|
Err(evm::Error::OutOfGas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -232,11 +233,12 @@ impl<'a> Executive<'a> {
|
|||||||
|
|
||||||
trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count);
|
trace!("exec: sstore-clears={}\n", unconfirmed_substate.sstore_clears_count);
|
||||||
trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
trace!("exec: substate={:?}; unconfirmed_substate={:?}\n", substate, unconfirmed_substate);
|
||||||
self.enact_result(&res, substate, unconfirmed_substate, backup);
|
self.enact_result(&res, substate, unconfirmed_substate);
|
||||||
trace!("exec: new substate={:?}\n", substate);
|
trace!("exec: new substate={:?}\n", substate);
|
||||||
res
|
res
|
||||||
} else {
|
} else {
|
||||||
// otherwise, nothing
|
// otherwise, nothing
|
||||||
|
self.state.clear_snapshot();
|
||||||
Ok(params.gas)
|
Ok(params.gas)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -246,7 +248,7 @@ impl<'a> Executive<'a> {
|
|||||||
/// Modifies the substate.
|
/// Modifies the substate.
|
||||||
pub fn create(&mut self, params: ActionParams, substate: &mut Substate) -> evm::Result {
|
pub fn create(&mut self, params: ActionParams, substate: &mut Substate) -> evm::Result {
|
||||||
// backup used in case of running out of gas
|
// backup used in case of running out of gas
|
||||||
let backup = self.state.clone();
|
self.state.snapshot();
|
||||||
|
|
||||||
// part of substate that may be reverted
|
// part of substate that may be reverted
|
||||||
let mut unconfirmed_substate = Substate::new();
|
let mut unconfirmed_substate = Substate::new();
|
||||||
@ -263,7 +265,7 @@ impl<'a> Executive<'a> {
|
|||||||
let res = {
|
let res = {
|
||||||
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract)
|
self.exec_vm(params, &mut unconfirmed_substate, OutputPolicy::InitContract)
|
||||||
};
|
};
|
||||||
self.enact_result(&res, substate, unconfirmed_substate, backup);
|
self.enact_result(&res, substate, unconfirmed_substate);
|
||||||
res
|
res
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -324,16 +326,19 @@ impl<'a> Executive<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate, backup: State) {
|
fn enact_result(&mut self, result: &evm::Result, substate: &mut Substate, un_substate: Substate) {
|
||||||
match *result {
|
match *result {
|
||||||
Err(evm::Error::OutOfGas)
|
Err(evm::Error::OutOfGas)
|
||||||
| Err(evm::Error::BadJumpDestination {..})
|
| Err(evm::Error::BadJumpDestination {..})
|
||||||
| Err(evm::Error::BadInstruction {.. })
|
| Err(evm::Error::BadInstruction {.. })
|
||||||
| Err(evm::Error::StackUnderflow {..})
|
| Err(evm::Error::StackUnderflow {..})
|
||||||
| Err(evm::Error::OutOfStack {..}) => {
|
| Err(evm::Error::OutOfStack {..}) => {
|
||||||
self.state.revert(backup);
|
self.state.revert_snapshot();
|
||||||
},
|
},
|
||||||
Ok(_) | Err(evm::Error::Internal) => substate.accrue(un_substate)
|
Ok(_) | Err(evm::Error::Internal) => {
|
||||||
|
self.state.clear_snapshot();
|
||||||
|
substate.accrue(un_substate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,12 +13,11 @@ use pod_state::PodState;
|
|||||||
pub type ApplyResult = Result<Receipt, Error>;
|
pub type ApplyResult = Result<Receipt, Error>;
|
||||||
|
|
||||||
/// Representation of the entire state of all accounts in the system.
|
/// Representation of the entire state of all accounts in the system.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct State {
|
pub struct State {
|
||||||
db: JournalDB,
|
db: JournalDB,
|
||||||
root: H256,
|
root: H256,
|
||||||
cache: RefCell<HashMap<Address, Option<Account>>>,
|
cache: RefCell<HashMap<Address, Option<Account>>>,
|
||||||
|
snapshots: RefCell<Vec<HashMap<Address, Option<Option<Account>>>>>,
|
||||||
account_start_nonce: U256,
|
account_start_nonce: U256,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -36,6 +35,7 @@ impl State {
|
|||||||
db: db,
|
db: db,
|
||||||
root: root,
|
root: root,
|
||||||
cache: RefCell::new(HashMap::new()),
|
cache: RefCell::new(HashMap::new()),
|
||||||
|
snapshots: RefCell::new(Vec::new()),
|
||||||
account_start_nonce: account_start_nonce,
|
account_start_nonce: account_start_nonce,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -51,10 +51,62 @@ impl State {
|
|||||||
db: db,
|
db: db,
|
||||||
root: root,
|
root: root,
|
||||||
cache: RefCell::new(HashMap::new()),
|
cache: RefCell::new(HashMap::new()),
|
||||||
|
snapshots: RefCell::new(Vec::new()),
|
||||||
account_start_nonce: account_start_nonce,
|
account_start_nonce: account_start_nonce,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a recoverable snaphot of this state
|
||||||
|
pub fn snapshot(&mut self) {
|
||||||
|
self.snapshots.borrow_mut().push(HashMap::new());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn clear_snapshot(&mut self) {
|
||||||
|
// merge with previous snapshot
|
||||||
|
let last = self.snapshots.borrow_mut().pop();
|
||||||
|
if let Some(mut snapshot) = last {
|
||||||
|
if let Some(ref mut prev) = self.snapshots.borrow_mut().last_mut() {
|
||||||
|
for (k, v) in snapshot.drain() {
|
||||||
|
prev.entry(k).or_insert(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn revert_snapshot(&mut self) {
|
||||||
|
if let Some(mut snapshot) = self.snapshots.borrow_mut().pop() {
|
||||||
|
for (k, v) in snapshot.drain() {
|
||||||
|
match v {
|
||||||
|
Some(v) => {
|
||||||
|
self.cache.borrow_mut().insert(k, v);
|
||||||
|
},
|
||||||
|
None => {
|
||||||
|
self.cache.borrow_mut().remove(&k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
fn insert_cache(&self, address: &Address, account: Option<Account>) {
|
||||||
|
if let Some(ref mut snapshot) = self.snapshots.borrow_mut().last_mut() {
|
||||||
|
if !snapshot.contains_key(&address) {
|
||||||
|
snapshot.insert(address.clone(), self.cache.borrow_mut().insert(address.clone(), account));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.cache.borrow_mut().insert(address.clone(), account);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn note_cache(&self, address: &Address) {
|
||||||
|
if let Some(ref mut snapshot) = self.snapshots.borrow_mut().last_mut() {
|
||||||
|
if !snapshot.contains_key(&address) {
|
||||||
|
snapshot.insert(address.clone(), self.cache.borrow().get(address).cloned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Destroy the current object and return root and database.
|
/// Destroy the current object and return root and database.
|
||||||
pub fn drop(self) -> (H256, JournalDB) {
|
pub fn drop(self) -> (H256, JournalDB) {
|
||||||
(self.root, self.db)
|
(self.root, self.db)
|
||||||
@ -68,12 +120,12 @@ impl State {
|
|||||||
/// Create a new contract at address `contract`. If there is already an account at the address
|
/// Create a new contract at address `contract`. If there is already an account at the address
|
||||||
/// it will have its code reset, ready for `init_code()`.
|
/// it will have its code reset, ready for `init_code()`.
|
||||||
pub fn new_contract(&mut self, contract: &Address, balance: U256) {
|
pub fn new_contract(&mut self, contract: &Address, balance: U256) {
|
||||||
self.cache.borrow_mut().insert(contract.clone(), Some(Account::new_contract(balance)));
|
self.insert_cache(&contract, Some(Account::new_contract(balance)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove an existing account.
|
/// Remove an existing account.
|
||||||
pub fn kill_account(&mut self, account: &Address) {
|
pub fn kill_account(&mut self, account: &Address) {
|
||||||
self.cache.borrow_mut().insert(account.clone(), None);
|
self.insert_cache(account, None);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determine whether an account exists.
|
/// Determine whether an account exists.
|
||||||
@ -152,11 +204,6 @@ impl State {
|
|||||||
Ok(receipt)
|
Ok(receipt)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reverts uncommited changed.
|
|
||||||
pub fn revert(&mut self, backup: State) {
|
|
||||||
self.cache = backup.cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
||||||
#[allow(match_ref_pats)]
|
#[allow(match_ref_pats)]
|
||||||
@ -186,6 +233,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());
|
||||||
Self::commit_into(&mut self.db, &mut self.root, self.cache.borrow_mut().deref_mut());
|
Self::commit_into(&mut self.db, &mut self.root, self.cache.borrow_mut().deref_mut());
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -193,6 +241,7 @@ impl State {
|
|||||||
#[cfg(feature = "json-tests")]
|
#[cfg(feature = "json-tests")]
|
||||||
/// Populate the state from `accounts`.
|
/// Populate the state from `accounts`.
|
||||||
pub fn populate_from(&mut self, accounts: PodState) {
|
pub fn populate_from(&mut self, accounts: PodState) {
|
||||||
|
assert!(self.snapshots.borrow().is_empty());
|
||||||
for (add, acc) in accounts.drain().into_iter() {
|
for (add, acc) in accounts.drain().into_iter() {
|
||||||
self.cache.borrow_mut().insert(add, Some(Account::from_pod(acc)));
|
self.cache.borrow_mut().insert(add, Some(Account::from_pod(acc)));
|
||||||
}
|
}
|
||||||
@ -202,6 +251,7 @@ impl State {
|
|||||||
#[cfg(feature = "json-tests")]
|
#[cfg(feature = "json-tests")]
|
||||||
/// Populate a PodAccount map from this state.
|
/// Populate a PodAccount map from this state.
|
||||||
pub fn to_pod(&self) -> PodState {
|
pub fn to_pod(&self) -> PodState {
|
||||||
|
assert!(self.snapshots.borrow().is_empty());
|
||||||
// TODO: handle database rather than just the cache.
|
// TODO: handle database rather than just the cache.
|
||||||
PodState::from(self.cache.borrow().iter().fold(BTreeMap::new(), |mut m, (add, opt)| {
|
PodState::from(self.cache.borrow().iter().fold(BTreeMap::new(), |mut m, (add, opt)| {
|
||||||
if let Some(ref acc) = *opt {
|
if let Some(ref acc) = *opt {
|
||||||
@ -214,9 +264,10 @@ impl State {
|
|||||||
/// Pull account `a` in our cache from the trie DB and return it.
|
/// Pull account `a` in our cache from the trie DB and return it.
|
||||||
/// `require_code` requires that the code be cached, too.
|
/// `require_code` requires that the code be cached, too.
|
||||||
fn get(&self, a: &Address, require_code: bool) -> Ref<Option<Account>> {
|
fn get(&self, a: &Address, require_code: bool) -> Ref<Option<Account>> {
|
||||||
self.cache.borrow_mut().entry(a.clone()).or_insert_with(|| {
|
let have_key = self.cache.borrow().contains_key(a);
|
||||||
SecTrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp))
|
if !have_key {
|
||||||
});
|
self.insert_cache(a, SecTrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp)))
|
||||||
|
}
|
||||||
if require_code {
|
if require_code {
|
||||||
if let Some(ref mut account) = self.cache.borrow_mut().get_mut(a).unwrap().as_mut() {
|
if let Some(ref mut account) = self.cache.borrow_mut().get_mut(a).unwrap().as_mut() {
|
||||||
account.cache_code(&self.db);
|
account.cache_code(&self.db);
|
||||||
@ -233,8 +284,12 @@ impl State {
|
|||||||
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
|
/// Pull account `a` in our cache from the trie DB. `require_code` requires that the code be cached, too.
|
||||||
/// If it doesn't exist, make account equal the evaluation of `default`.
|
/// If it doesn't exist, make account equal the evaluation of `default`.
|
||||||
fn require_or_from<F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> RefMut<Account> {
|
fn require_or_from<F: FnOnce() -> Account, G: FnOnce(&mut Account)>(&self, a: &Address, require_code: bool, default: F, not_default: G) -> RefMut<Account> {
|
||||||
self.cache.borrow_mut().entry(a.clone()).or_insert_with(||
|
let have_key = self.cache.borrow().contains_key(a);
|
||||||
SecTrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp)));
|
if !have_key {
|
||||||
|
self.insert_cache(a, SecTrieDB::new(&self.db, &self.root).get(&a).map(|rlp| Account::from_rlp(rlp)))
|
||||||
|
} else {
|
||||||
|
self.note_cache(a);
|
||||||
|
}
|
||||||
let preexists = self.cache.borrow().get(a).unwrap().is_none();
|
let preexists = self.cache.borrow().get(a).unwrap().is_none();
|
||||||
if preexists {
|
if preexists {
|
||||||
self.cache.borrow_mut().insert(a.clone(), Some(default()));
|
self.cache.borrow_mut().insert(a.clone(), Some(default()));
|
||||||
|
@ -48,17 +48,21 @@ impl Drop for RandomTempPath {
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
pub struct GuardedTempResult<T> {
|
pub struct GuardedTempResult<T> {
|
||||||
result: T,
|
result: Option<T>,
|
||||||
_temp: RandomTempPath
|
_temp: RandomTempPath
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> GuardedTempResult<T> {
|
impl<T> GuardedTempResult<T> {
|
||||||
pub fn reference(&self) -> &T {
|
pub fn reference(&self) -> &T {
|
||||||
&self.result
|
self.result.as_ref().unwrap()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reference_mut(&mut self) -> &mut T {
|
pub fn reference_mut(&mut self) -> &mut T {
|
||||||
&mut self.result
|
self.result.as_mut().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn take(&mut self) -> T {
|
||||||
|
self.result.take().unwrap()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -150,7 +154,7 @@ pub fn generate_dummy_client(block_number: u32) -> GuardedTempResult<Arc<Client>
|
|||||||
|
|
||||||
GuardedTempResult::<Arc<Client>> {
|
GuardedTempResult::<Arc<Client>> {
|
||||||
_temp: dir,
|
_temp: dir,
|
||||||
result: client
|
result: Some(client)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -168,7 +172,7 @@ pub fn get_test_client_with_blocks(blocks: Vec<Bytes>) -> GuardedTempResult<Arc<
|
|||||||
|
|
||||||
GuardedTempResult::<Arc<Client>> {
|
GuardedTempResult::<Arc<Client>> {
|
||||||
_temp: dir,
|
_temp: dir,
|
||||||
result: client
|
result: Some(client)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,7 +185,7 @@ pub fn generate_dummy_blockchain(block_number: u32) -> GuardedTempResult<BlockCh
|
|||||||
|
|
||||||
GuardedTempResult::<BlockChain> {
|
GuardedTempResult::<BlockChain> {
|
||||||
_temp: temp,
|
_temp: temp,
|
||||||
result: bc
|
result: Some(bc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -194,7 +198,7 @@ pub fn generate_dummy_blockchain_with_extra(block_number: u32) -> GuardedTempRes
|
|||||||
|
|
||||||
GuardedTempResult::<BlockChain> {
|
GuardedTempResult::<BlockChain> {
|
||||||
_temp: temp,
|
_temp: temp,
|
||||||
result: bc
|
result: Some(bc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,7 +208,7 @@ pub fn generate_dummy_empty_blockchain() -> GuardedTempResult<BlockChain> {
|
|||||||
|
|
||||||
GuardedTempResult::<BlockChain> {
|
GuardedTempResult::<BlockChain> {
|
||||||
_temp: temp,
|
_temp: temp,
|
||||||
result: bc
|
result: Some(bc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,7 +218,7 @@ pub fn get_temp_journal_db() -> GuardedTempResult<JournalDB> {
|
|||||||
let journal_db = JournalDB::new(db);
|
let journal_db = JournalDB::new(db);
|
||||||
GuardedTempResult {
|
GuardedTempResult {
|
||||||
_temp: temp,
|
_temp: temp,
|
||||||
result: journal_db
|
result: Some(journal_db)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -223,7 +227,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: State::new(journal_db, U256::from(0u8))
|
result: Some(State::new(journal_db, U256::from(0u8)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,7 +8,6 @@ use rocksdb::{DB, Writable};
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
/// Implementation of the HashDB trait for a disk-backed database with a memory overlay
|
/// Implementation of the HashDB trait for a disk-backed database with a memory overlay
|
||||||
/// and latent-removal semantics.
|
/// and latent-removal semantics.
|
||||||
///
|
///
|
||||||
@ -53,8 +52,6 @@ impl JournalDB {
|
|||||||
Self::new(DB::open_default(dir.to_str().unwrap()).unwrap())
|
Self::new(DB::open_default(dir.to_str().unwrap()).unwrap())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a clone of the overlay db portion of this.
|
|
||||||
pub fn to_overlaydb(&self) -> OverlayDB { self.forward.clone() }
|
|
||||||
|
|
||||||
/// Commit all recent insert operations and historical removals from the old era
|
/// Commit all recent insert operations and historical removals from the old era
|
||||||
/// to the backing database.
|
/// to the backing database.
|
||||||
@ -119,10 +116,6 @@ impl JournalDB {
|
|||||||
|
|
||||||
self.forward.commit()
|
self.forward.commit()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Revert all operations on this object (i.e. `insert()`s and `removes()`s) since the
|
|
||||||
/// last `commit()`.
|
|
||||||
pub fn revert(&mut self) { self.forward.revert(); self.removes.clear(); }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HashDB for JournalDB {
|
impl HashDB for JournalDB {
|
||||||
|
@ -12,7 +12,6 @@ use std::env;
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use rocksdb::{DB, Writable, IteratorMode};
|
use rocksdb::{DB, Writable, IteratorMode};
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
/// Implementation of the HashDB trait for a disk-backed database with a memory overlay.
|
/// Implementation of the HashDB trait for a disk-backed database with a memory overlay.
|
||||||
///
|
///
|
||||||
/// The operations `insert()` and `remove()` take place on the memory overlay; batches of
|
/// The operations `insert()` and `remove()` take place on the memory overlay; batches of
|
||||||
|
Loading…
Reference in New Issue
Block a user