diff --git a/ethcore/src/block.rs b/ethcore/src/block.rs index 88894618c..87f4749a1 100644 --- a/ethcore/src/block.rs +++ b/ethcore/src/block.rs @@ -205,7 +205,6 @@ pub struct ClosedBlock { block: ExecutedBlock, uncle_bytes: Bytes, last_hashes: Arc, - unclosed_state: State, } /// Just like `ClosedBlock` except that we can't reopen it and it's faster. @@ -343,11 +342,12 @@ impl<'x> OpenBlock<'x> { } } - /// Turn this into a `ClosedBlock`. A `BlockChain` must be provided in order to figure out the uncles. + /// Turn this into a `ClosedBlock`. pub fn close(self) -> ClosedBlock { let mut s = self; - let unclosed_state = s.block.state.clone(); + // take a snapshot so the engine's changes can be rolled back. + s.block.state.snapshot(); s.engine.on_close_block(&mut s.block); s.block.base.header.set_transactions_root(ordered_trie_root(s.block.base.transactions.iter().map(|e| e.rlp_bytes().to_vec()).collect())); @@ -362,14 +362,16 @@ impl<'x> OpenBlock<'x> { block: s.block, uncle_bytes: uncle_bytes, last_hashes: s.last_hashes, - unclosed_state: unclosed_state, } } - /// Turn this into a `LockedBlock`. A BlockChain must be provided in order to figure out the uncles. + /// Turn this into a `LockedBlock`. pub fn close_and_lock(self) -> LockedBlock { let mut s = self; + // take a snapshot so the engine's changes can be rolled back. + s.block.state.snapshot(); + s.engine.on_close_block(&mut s.block); if s.block.base.header.transactions_root().is_zero() || s.block.base.header.transactions_root() == &SHA3_NULL_RLP { s.block.base.header.set_transactions_root(ordered_trie_root(s.block.base.transactions.iter().map(|e| e.rlp_bytes().to_vec()).collect())); @@ -381,14 +383,16 @@ impl<'x> OpenBlock<'x> { if s.block.base.header.receipts_root().is_zero() || s.block.base.header.receipts_root() == &SHA3_NULL_RLP { s.block.base.header.set_receipts_root(ordered_trie_root(s.block.receipts.iter().map(|r| r.rlp_bytes().to_vec()).collect())); } + s.block.base.header.set_state_root(s.block.state.root().clone()); s.block.base.header.set_log_bloom(s.block.receipts.iter().fold(LogBloom::zero(), |mut b, r| {b = &b | &r.log_bloom; b})); //TODO: use |= operator s.block.base.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used)); - LockedBlock { + ClosedBlock { block: s.block, uncle_bytes: uncle_bytes, - } + last_hashes: s.last_hashes, + }.lock() } } @@ -409,7 +413,17 @@ impl ClosedBlock { pub fn hash(&self) -> H256 { self.header().rlp_sha3(Seal::Without) } /// Turn this into a `LockedBlock`, unable to be reopened again. - pub fn lock(self) -> LockedBlock { + pub fn lock(mut self) -> LockedBlock { + // finalize the changes made by the engine. + self.block.state.clear_snapshot(); + if let Err(e) = self.block.state.commit() { + warn!("Error committing closed block's state: {:?}", e); + } + + // set the state root here, after commit recalculates with the block + // rewards. + self.block.base.header.set_state_root(self.block.state.root().clone()); + LockedBlock { block: self.block, uncle_bytes: self.uncle_bytes, @@ -417,12 +431,12 @@ impl ClosedBlock { } /// Given an engine reference, reopen the `ClosedBlock` into an `OpenBlock`. - pub fn reopen(self, engine: &Engine) -> OpenBlock { + pub fn reopen(mut self, engine: &Engine) -> OpenBlock { // revert rewards (i.e. set state back at last transaction's state). - let mut block = self.block; - block.state = self.unclosed_state; + self.block.state.revert_snapshot(); + OpenBlock { - block: block, + block: self.block, engine: engine, last_hashes: self.last_hashes, } diff --git a/ethcore/src/ethereum/ethash.rs b/ethcore/src/ethereum/ethash.rs index 216ebed17..734acb758 100644 --- a/ethcore/src/ethereum/ethash.rs +++ b/ethcore/src/ethereum/ethash.rs @@ -167,9 +167,7 @@ impl Engine for Ethash { for u in fields.uncles.iter() { fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8))); } - if let Err(e) = fields.state.commit() { - warn!("Encountered error on state commit: {}", e); - } + } fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> { diff --git a/ethcore/src/state/mod.rs b/ethcore/src/state/mod.rs index 8c7e49ba3..78eb01c7c 100644 --- a/ethcore/src/state/mod.rs +++ b/ethcore/src/state/mod.rs @@ -420,10 +420,27 @@ impl fmt::Debug for State { impl Clone for State { fn clone(&self) -> State { + let cache = { + let mut cache = HashMap::new(); + for (key, val) in self.cache.borrow().iter() { + let key = key.clone(); + match *val { + Some(ref acc) if acc.is_dirty() => { + cache.insert(key, Some(acc.clone())); + }, + None => { + cache.insert(key, None); + }, + _ => {}, + } + } + cache + }; + State { db: self.db.boxed_clone(), root: self.root.clone(), - cache: RefCell::new(self.cache.borrow().clone()), + cache: RefCell::new(cache), snapshots: RefCell::new(self.snapshots.borrow().clone()), account_start_nonce: self.account_start_nonce.clone(), factories: self.factories.clone(),