Various state copy optimizations (#2172)
* Avoid cloning clean stuff * Don't clone state when closing/locking blocks * handle errors in commit * revert `close_and_lock` changes * defer state root update until post state commit
This commit is contained in:
parent
b7e2afd5c0
commit
2e6684dae8
@ -205,7 +205,6 @@ pub struct ClosedBlock {
|
|||||||
block: ExecutedBlock,
|
block: ExecutedBlock,
|
||||||
uncle_bytes: Bytes,
|
uncle_bytes: Bytes,
|
||||||
last_hashes: Arc<LastHashes>,
|
last_hashes: Arc<LastHashes>,
|
||||||
unclosed_state: State,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Just like `ClosedBlock` except that we can't reopen it and it's faster.
|
/// 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 {
|
pub fn close(self) -> ClosedBlock {
|
||||||
let mut s = self;
|
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.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()));
|
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,
|
block: s.block,
|
||||||
uncle_bytes: uncle_bytes,
|
uncle_bytes: uncle_bytes,
|
||||||
last_hashes: s.last_hashes,
|
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 {
|
pub fn close_and_lock(self) -> LockedBlock {
|
||||||
let mut s = self;
|
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);
|
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 {
|
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()));
|
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 {
|
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_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_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_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));
|
s.block.base.header.set_gas_used(s.block.receipts.last().map_or(U256::zero(), |r| r.gas_used));
|
||||||
|
|
||||||
LockedBlock {
|
ClosedBlock {
|
||||||
block: s.block,
|
block: s.block,
|
||||||
uncle_bytes: uncle_bytes,
|
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) }
|
pub fn hash(&self) -> H256 { self.header().rlp_sha3(Seal::Without) }
|
||||||
|
|
||||||
/// Turn this into a `LockedBlock`, unable to be reopened again.
|
/// 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 {
|
LockedBlock {
|
||||||
block: self.block,
|
block: self.block,
|
||||||
uncle_bytes: self.uncle_bytes,
|
uncle_bytes: self.uncle_bytes,
|
||||||
@ -417,12 +431,12 @@ impl ClosedBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Given an engine reference, reopen the `ClosedBlock` into an `OpenBlock`.
|
/// 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).
|
// revert rewards (i.e. set state back at last transaction's state).
|
||||||
let mut block = self.block;
|
self.block.state.revert_snapshot();
|
||||||
block.state = self.unclosed_state;
|
|
||||||
OpenBlock {
|
OpenBlock {
|
||||||
block: block,
|
block: self.block,
|
||||||
engine: engine,
|
engine: engine,
|
||||||
last_hashes: self.last_hashes,
|
last_hashes: self.last_hashes,
|
||||||
}
|
}
|
||||||
|
@ -167,9 +167,7 @@ impl Engine for Ethash {
|
|||||||
for u in fields.uncles.iter() {
|
for u in fields.uncles.iter() {
|
||||||
fields.state.add_balance(u.author(), &(reward * U256::from(8 + u.number() - current_number) / U256::from(8)));
|
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> {
|
fn verify_block_basic(&self, header: &Header, _block: Option<&[u8]>) -> result::Result<(), Error> {
|
||||||
|
@ -420,10 +420,27 @@ impl fmt::Debug for State {
|
|||||||
|
|
||||||
impl Clone for State {
|
impl Clone for State {
|
||||||
fn clone(&self) -> 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 {
|
State {
|
||||||
db: self.db.boxed_clone(),
|
db: self.db.boxed_clone(),
|
||||||
root: self.root.clone(),
|
root: self.root.clone(),
|
||||||
cache: RefCell::new(self.cache.borrow().clone()),
|
cache: RefCell::new(cache),
|
||||||
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(),
|
||||||
factories: self.factories.clone(),
|
factories: self.factories.clone(),
|
||||||
|
Loading…
Reference in New Issue
Block a user