diff --git a/core/blockchain.go b/core/blockchain.go index a5f146a2d3..1fbcdfc6f7 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -357,7 +357,12 @@ func (self *BlockChain) AuxValidator() pow.PoW { return self.pow } // State returns a new mutable state based on the current HEAD block. func (self *BlockChain) State() (*state.StateDB, error) { - return state.New(self.CurrentBlock().Root(), self.chainDb) + return self.StateAt(self.CurrentBlock().Root()) +} + +// StateAt returns a new mutable state based on a particular point in time. +func (self *BlockChain) StateAt(root common.Hash) (*state.StateDB, error) { + return self.stateCache.New(root) } // Reset purges the entire blockchain, restoring it to its genesis state. diff --git a/core/state/statedb.go b/core/state/statedb.go index 802f37ba09..2942b69e96 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -86,6 +86,25 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) { }, nil } +// New creates a new statedb by reusing any journalled tries to avoid costly +// disk io. +func (self *StateDB) New(root common.Hash) (*StateDB, error) { + tr, err := self.openTrie(root) + if err != nil { + return nil, err + } + csc, _ := lru.New(codeSizeCacheSize) + return &StateDB{ + db: self.db, + trie: tr, + codeSizeCache: csc, + stateObjects: make(map[common.Address]*StateObject), + stateObjectsDirty: make(map[common.Address]struct{}), + refund: new(big.Int), + logs: make(map[common.Hash]vm.Logs), + }, nil +} + // Reset clears out all emphemeral state objects from the state db, but keeps // the underlying state trie to avoid reloading data for the next operations. func (self *StateDB) Reset(root common.Hash) error { @@ -110,7 +129,8 @@ func (self *StateDB) Reset(root common.Hash) error { // from the journal if available. func (self *StateDB) openTrie(root common.Hash) (*trie.SecureTrie, error) { if self.trie != nil && self.trie.Hash() == root { - return self.trie, nil + cpy := *self.trie + return &cpy, nil } for i := len(self.pastTries) - 1; i >= 0; i-- { if self.pastTries[i].Hash() == root { diff --git a/miner/worker.go b/miner/worker.go index 1676036d87..ac1ef5ba3d 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -361,7 +361,7 @@ func (self *worker) push(work *Work) { // makeCurrent creates a new environment for the current cycle. func (self *worker) makeCurrent(parent *types.Block, header *types.Header) error { - state, err := state.New(parent.Root(), self.eth.ChainDb()) + state, err := self.chain.StateAt(parent.Root()) if err != nil { return err }