diff --git a/core/blockchain.go b/core/blockchain.go index c5b304ff35..0167faf41a 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -545,6 +545,11 @@ func (self *BlockChain) GetBlockByNumber(number uint64) *types.Block { return self.GetBlock(hash, number) } +// IsCanonChainBlock checks whether the given block is in the current canonical chain. +func (self *BlockChain) IsCanonChainBlock(number uint64, hash common.Hash) bool { + return number < uint64(self.currentBlock.Number().Int64()) && GetCanonicalHash(self.chainDb, number) == hash +} + // [deprecated by eth/62] // GetBlocksFromHash returns the block corresponding to hash and up to n-1 ancestors. func (self *BlockChain) GetBlocksFromHash(hash common.Hash, n int) (blocks []*types.Block) { diff --git a/core/chain_makers.go b/core/chain_makers.go index e3ad9cda08..b361a69a31 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -105,7 +105,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) { if b.gasPool == nil { b.SetCoinbase(common.Address{}) } - b.statedb.StartRecord(tx.Hash(), common.Hash{}, len(b.txs)) + b.statedb.SetTxContext(common.Hash{}, b.header.Number.Uint64(), tx.Hash(), len(b.txs), nil) receipt, _, _, err := ApplyTransaction(MakeChainConfig(), nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{}) if err != nil { panic(err) diff --git a/core/state/iterator_test.go b/core/state/iterator_test.go index aa05c5dfe7..dc16523eff 100644 --- a/core/state/iterator_test.go +++ b/core/state/iterator_test.go @@ -47,7 +47,7 @@ func TestNodeIteratorCoverage(t *testing.T) { } } for _, key := range db.(*ethdb.MemDatabase).Keys() { - if bytes.HasPrefix(key, []byte("secure-key-")) { + if bytes.HasPrefix(key, []byte("secure-key-")) || bytes.HasPrefix(key, CachePrefix) { continue } if _, ok := hashes[common.BytesToHash(key)]; !ok { diff --git a/core/state/statedb.go b/core/state/statedb.go index eef2f38d50..dc5323f2b1 100644 --- a/core/state/statedb.go +++ b/core/state/statedb.go @@ -41,6 +41,8 @@ var StartingNonce uint64 // Trie cache generation limit after which to evic trie nodes from memory. var MaxTrieCacheGen = uint16(120) +var CachePrefix = []byte("accounthashcache:") + const ( // Number of past tries to keep. This value is chosen such that // reasonable chain reorg depths will hit an existing trie. @@ -94,17 +96,19 @@ func New(root common.Hash, db ethdb.Database) (*StateDB, error) { if err != nil { return nil, err } + csc, _ := lru.New(codeSizeCacheSize) - return &StateDB{ + ret := &StateDB{ db: db, trie: tr, - storage: trie.NewSecure(tr, db), 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 + } + ret.SetTxContext(common.Hash{}, 0, common.Hash{}, 0, nil) + return ret, nil } // New creates a new statedb by reusing any journalled tries to avoid costly @@ -117,16 +121,17 @@ func (self *StateDB) New(root common.Hash) (*StateDB, error) { if err != nil { return nil, err } - return &StateDB{ + ret := &StateDB{ db: self.db, trie: tr, - storage: trie.NewSecure(tr, self.db), codeSizeCache: self.codeSizeCache, stateObjects: make(map[common.Address]*StateObject), stateObjectsDirty: make(map[common.Address]struct{}), refund: new(big.Int), logs: make(map[common.Hash]vm.Logs), - }, nil + } + ret.SetTxContext(common.Hash{}, 0, common.Hash{}, 0, nil) + return ret, nil } // Reset clears out all emphemeral state objects from the state db, but keeps @@ -140,7 +145,6 @@ func (self *StateDB) Reset(root common.Hash) error { return err } self.trie = tr - self.storage = trie.NewSecure(tr, self.db) self.stateObjects = make(map[common.Address]*StateObject) self.stateObjectsDirty = make(map[common.Address]struct{}) self.thash = common.Hash{} @@ -149,6 +153,8 @@ func (self *StateDB) Reset(root common.Hash) error { self.logs = make(map[common.Hash]vm.Logs) self.logSize = 0 self.clearJournalAndRefund() + self.SetTxContext(common.Hash{}, 0, common.Hash{}, 0, nil) + return nil } @@ -177,10 +183,16 @@ func (self *StateDB) pushTrie(t *trie.Trie) { } } -func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) { - self.thash = thash - self.bhash = bhash - self.txIndex = ti +func (self *StateDB) SetTxContext(blockHash common.Hash, blockNum uint64, txHash common.Hash, txIndex int, validator trie.CacheValidator) { + self.bhash = blockHash + self.thash = txHash + self.txIndex = txIndex + + if validator == nil { + validator = &trie.NullCacheValidator{} + } + storage := trie.NewDirectCache(self.trie, self.db, CachePrefix, validator, true) + self.storage = trie.NewSecure(storage, self.db) } func (self *StateDB) AddLog(log *vm.Log) { diff --git a/core/state_processor.go b/core/state_processor.go index fd8e9762e9..8722e3c342 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -71,7 +71,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg } // Iterate over and process the individual transactions for i, tx := range block.Transactions() { - statedb.StartRecord(tx.Hash(), block.Hash(), i) + statedb.SetTxContext(block.Hash(), block.NumberU64(), tx.Hash(), i, p.bc) receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg) if err != nil { return nil, nil, totalUsedGas, err diff --git a/miner/worker.go b/miner/worker.go index 89064c3b95..7826605238 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -583,7 +583,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB continue } // Start executing the transaction - env.state.StartRecord(tx.Hash(), common.Hash{}, env.tcount) + env.state.SetTxContext(common.Hash{}, env.header.Number.Uint64(), tx.Hash(), env.tcount, bc) err, logs := env.commitTransaction(tx, bc, gp) switch { diff --git a/trie/directcache.go b/trie/directcache.go index 6f87ba5ef8..25d3d6e305 100644 --- a/trie/directcache.go +++ b/trie/directcache.go @@ -52,13 +52,17 @@ type DirectCache struct { dirty map[string]bool } -func NewDirectCache(s Storage, db Database, keyPrefix []byte, blockNum uint64, blockHash common.Hash, validator CacheValidator, complete bool) *DirectCache { +type NullCacheValidator struct {} + +func (cv *NullCacheValidator) IsCanonChainBlock(num uint64, hash common.Hash) bool { + return false +} + +func NewDirectCache(s Storage, db Database, keyPrefix []byte, validator CacheValidator, complete bool) *DirectCache { return &DirectCache{ storage: s, db: db, keyPrefix: keyPrefix, - blockNum: blockNum, - blockHash: blockHash, validator: validator, complete: complete, dirty: make(map[string]bool), @@ -83,6 +87,7 @@ func (dc *DirectCache) Get(key []byte) []byte { } func (dc *DirectCache) TryGet(key []byte) ([]byte, error) { + return dc.storage.TryGet(key) start := time.Now() // Use the underlying object for dirty keys diff --git a/trie/trie_test.go b/trie/trie_test.go index bb2861cf19..0e11bf931d 100644 --- a/trie/trie_test.go +++ b/trie/trie_test.go @@ -583,14 +583,14 @@ func tempDB() (string, Database) { return dir, db } -func getString(trie Trie, k string) []byte { +func getString(trie *Trie, k string) []byte { return trie.Get([]byte(k)) } -func updateString(trie Trie, k, v string) { +func updateString(trie *Trie, k, v string) { trie.Update([]byte(k), []byte(v)) } -func deleteString(trie Trie, k string) { +func deleteString(trie *Trie, k string) { trie.Delete([]byte(k)) }