core, miner, trie: Integrate directcache with statedb

This commit is contained in:
Nick Johnson 2016-10-25 10:58:44 +01:00
parent 2fb08643cb
commit de5a818baa
8 changed files with 43 additions and 21 deletions

View file

@ -545,6 +545,11 @@ func (self *BlockChain) GetBlockByNumber(number uint64) *types.Block {
return self.GetBlock(hash, number) 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] // [deprecated by eth/62]
// GetBlocksFromHash returns the block corresponding to hash and up to n-1 ancestors. // 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) { func (self *BlockChain) GetBlocksFromHash(hash common.Hash, n int) (blocks []*types.Block) {

View file

@ -105,7 +105,7 @@ func (b *BlockGen) AddTx(tx *types.Transaction) {
if b.gasPool == nil { if b.gasPool == nil {
b.SetCoinbase(common.Address{}) 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{}) receipt, _, _, err := ApplyTransaction(MakeChainConfig(), nil, b.gasPool, b.statedb, b.header, tx, b.header.GasUsed, vm.Config{})
if err != nil { if err != nil {
panic(err) panic(err)

View file

@ -47,7 +47,7 @@ func TestNodeIteratorCoverage(t *testing.T) {
} }
} }
for _, key := range db.(*ethdb.MemDatabase).Keys() { 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 continue
} }
if _, ok := hashes[common.BytesToHash(key)]; !ok { if _, ok := hashes[common.BytesToHash(key)]; !ok {

View file

@ -41,6 +41,8 @@ var StartingNonce uint64
// Trie cache generation limit after which to evic trie nodes from memory. // Trie cache generation limit after which to evic trie nodes from memory.
var MaxTrieCacheGen = uint16(120) var MaxTrieCacheGen = uint16(120)
var CachePrefix = []byte("accounthashcache:")
const ( const (
// Number of past tries to keep. This value is chosen such that // Number of past tries to keep. This value is chosen such that
// reasonable chain reorg depths will hit an existing trie. // 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 { if err != nil {
return nil, err return nil, err
} }
csc, _ := lru.New(codeSizeCacheSize) csc, _ := lru.New(codeSizeCacheSize)
return &StateDB{ ret := &StateDB{
db: db, db: db,
trie: tr, trie: tr,
storage: trie.NewSecure(tr, db),
codeSizeCache: csc, codeSizeCache: csc,
stateObjects: make(map[common.Address]*StateObject), stateObjects: make(map[common.Address]*StateObject),
stateObjectsDirty: make(map[common.Address]struct{}), stateObjectsDirty: make(map[common.Address]struct{}),
refund: new(big.Int), refund: new(big.Int),
logs: make(map[common.Hash]vm.Logs), 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 // 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 { if err != nil {
return nil, err return nil, err
} }
return &StateDB{ ret := &StateDB{
db: self.db, db: self.db,
trie: tr, trie: tr,
storage: trie.NewSecure(tr, self.db),
codeSizeCache: self.codeSizeCache, codeSizeCache: self.codeSizeCache,
stateObjects: make(map[common.Address]*StateObject), stateObjects: make(map[common.Address]*StateObject),
stateObjectsDirty: make(map[common.Address]struct{}), stateObjectsDirty: make(map[common.Address]struct{}),
refund: new(big.Int), refund: new(big.Int),
logs: make(map[common.Hash]vm.Logs), 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 // 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 return err
} }
self.trie = tr self.trie = tr
self.storage = trie.NewSecure(tr, self.db)
self.stateObjects = make(map[common.Address]*StateObject) self.stateObjects = make(map[common.Address]*StateObject)
self.stateObjectsDirty = make(map[common.Address]struct{}) self.stateObjectsDirty = make(map[common.Address]struct{})
self.thash = common.Hash{} 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.logs = make(map[common.Hash]vm.Logs)
self.logSize = 0 self.logSize = 0
self.clearJournalAndRefund() self.clearJournalAndRefund()
self.SetTxContext(common.Hash{}, 0, common.Hash{}, 0, nil)
return nil return nil
} }
@ -177,10 +183,16 @@ func (self *StateDB) pushTrie(t *trie.Trie) {
} }
} }
func (self *StateDB) StartRecord(thash, bhash common.Hash, ti int) { func (self *StateDB) SetTxContext(blockHash common.Hash, blockNum uint64, txHash common.Hash, txIndex int, validator trie.CacheValidator) {
self.thash = thash self.bhash = blockHash
self.bhash = bhash self.thash = txHash
self.txIndex = ti 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) { func (self *StateDB) AddLog(log *vm.Log) {

View file

@ -71,7 +71,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
} }
// Iterate over and process the individual transactions // Iterate over and process the individual transactions
for i, tx := range block.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) receipt, logs, _, err := ApplyTransaction(p.config, p.bc, gp, statedb, header, tx, totalUsedGas, cfg)
if err != nil { if err != nil {
return nil, nil, totalUsedGas, err return nil, nil, totalUsedGas, err

View file

@ -583,7 +583,7 @@ func (env *Work) commitTransactions(mux *event.TypeMux, txs *types.TransactionsB
continue continue
} }
// Start executing the transaction // 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) err, logs := env.commitTransaction(tx, bc, gp)
switch { switch {

View file

@ -52,13 +52,17 @@ type DirectCache struct {
dirty map[string]bool 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{ return &DirectCache{
storage: s, storage: s,
db: db, db: db,
keyPrefix: keyPrefix, keyPrefix: keyPrefix,
blockNum: blockNum,
blockHash: blockHash,
validator: validator, validator: validator,
complete: complete, complete: complete,
dirty: make(map[string]bool), dirty: make(map[string]bool),
@ -83,6 +87,7 @@ func (dc *DirectCache) Get(key []byte) []byte {
} }
func (dc *DirectCache) TryGet(key []byte) ([]byte, error) { func (dc *DirectCache) TryGet(key []byte) ([]byte, error) {
return dc.storage.TryGet(key)
start := time.Now() start := time.Now()
// Use the underlying object for dirty keys // Use the underlying object for dirty keys

View file

@ -583,14 +583,14 @@ func tempDB() (string, Database) {
return dir, db return dir, db
} }
func getString(trie Trie, k string) []byte { func getString(trie *Trie, k string) []byte {
return trie.Get([]byte(k)) 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)) trie.Update([]byte(k), []byte(v))
} }
func deleteString(trie Trie, k string) { func deleteString(trie *Trie, k string) {
trie.Delete([]byte(k)) trie.Delete([]byte(k))
} }