core/state: add codehash->size cache

This commit is contained in:
Felix Lange 2016-09-27 00:34:52 +02:00
parent 65b96c40ee
commit ae9c64061f
2 changed files with 33 additions and 23 deletions

View file

@ -95,8 +95,6 @@ type Account struct {
Balance *big.Int Balance *big.Int
Root common.Hash // merkle root of the storage trie Root common.Hash // merkle root of the storage trie
CodeHash []byte CodeHash []byte
codeSize *int
} }
// NewObject creates a state object. // NewObject creates a state object.
@ -275,20 +273,9 @@ func (self *StateObject) Code(db trie.Database) []byte {
return code return code
} }
// CodeSize returns the size of the contract code associated with this object.
func (self *StateObject) CodeSize(db trie.Database) int {
if self.data.codeSize == nil {
self.data.codeSize = new(int)
*self.data.codeSize = len(self.Code(db))
}
return *self.data.codeSize
}
func (self *StateObject) SetCode(code []byte) { func (self *StateObject) SetCode(code []byte) {
self.code = code self.code = code
self.data.CodeHash = crypto.Keccak256(code) self.data.CodeHash = crypto.Keccak256(code)
self.data.codeSize = new(int)
*self.data.codeSize = len(code)
self.dirtyCode = true self.dirtyCode = true
if self.onDirty != nil { if self.onDirty != nil {
self.onDirty(self.Address()) self.onDirty(self.Address())

View file

@ -28,15 +28,21 @@ import (
"github.com/ethereum/go-ethereum/logger/glog" "github.com/ethereum/go-ethereum/logger/glog"
"github.com/ethereum/go-ethereum/rlp" "github.com/ethereum/go-ethereum/rlp"
"github.com/ethereum/go-ethereum/trie" "github.com/ethereum/go-ethereum/trie"
lru "github.com/hashicorp/golang-lru"
) )
// The starting nonce determines the default nonce when new accounts are being // The starting nonce determines the default nonce when new accounts are being
// created. // created.
var StartingNonce uint64 var StartingNonce uint64
// Number of past tries to keep. The arbitrarily chosen value here const (
// is max uncle depth + 1. // Number of past tries to keep. The arbitrarily chosen value here
const maxJournalLength = 8 // is max uncle depth + 1.
maxJournalLength = 8
// Number of codehash->size associations to keep.
codeSizeCacheSize = 100000
)
// StateDBs within the ethereum protocol are used to store anything // StateDBs within the ethereum protocol are used to store anything
// within the merkle trie. StateDBs take care of caching and storing // within the merkle trie. StateDBs take care of caching and storing
@ -44,9 +50,10 @@ const maxJournalLength = 8
// * Contracts // * Contracts
// * Accounts // * Accounts
type StateDB struct { type StateDB struct {
db ethdb.Database db ethdb.Database
trie *trie.SecureTrie trie *trie.SecureTrie
pastTries []*trie.SecureTrie pastTries []*trie.SecureTrie
codeSizeCache *lru.Cache
// This map holds 'live' objects, which will get modified while processing a state transition. // This map holds 'live' objects, which will get modified while processing a state transition.
stateObjects map[common.Address]*StateObject stateObjects map[common.Address]*StateObject
@ -67,9 +74,11 @@ 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)
return &StateDB{ return &StateDB{
db: db, db: db,
trie: tr, trie: tr,
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),
@ -88,6 +97,7 @@ func (self *StateDB) Reset(root common.Hash) error {
db: self.db, db: self.db,
trie: tr, trie: tr,
pastTries: self.pastTries, pastTries: self.pastTries,
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),
@ -193,17 +203,28 @@ func (self *StateDB) GetNonce(addr common.Address) uint64 {
func (self *StateDB) GetCode(addr common.Address) []byte { func (self *StateDB) GetCode(addr common.Address) []byte {
stateObject := self.GetStateObject(addr) stateObject := self.GetStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.Code(self.db) code := stateObject.Code(self.db)
key := common.BytesToHash(stateObject.CodeHash())
self.codeSizeCache.Add(key, len(code))
return code
} }
return nil return nil
} }
func (self *StateDB) GetCodeSize(addr common.Address) int { func (self *StateDB) GetCodeSize(addr common.Address) int {
stateObject := self.GetStateObject(addr) stateObject := self.GetStateObject(addr)
if stateObject != nil { if stateObject == nil {
return stateObject.CodeSize(self.db) return 0
} }
return 0 key := common.BytesToHash(stateObject.CodeHash())
if cached, ok := self.codeSizeCache.Get(key); ok {
return cached.(int)
}
size := len(stateObject.Code(self.db))
if stateObject.dbErr == nil {
self.codeSizeCache.Add(key, size)
}
return size
} }
func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash { func (self *StateDB) GetState(a common.Address, b common.Hash) common.Hash {
@ -373,6 +394,7 @@ func (self *StateDB) Copy() *StateDB {
db: self.db, db: self.db,
trie: self.trie, trie: self.trie,
pastTries: self.pastTries, pastTries: self.pastTries,
codeSizeCache: self.codeSizeCache,
stateObjects: make(map[common.Address]*StateObject, len(self.stateObjectsDirty)), stateObjects: make(map[common.Address]*StateObject, len(self.stateObjectsDirty)),
stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)), stateObjectsDirty: make(map[common.Address]struct{}, len(self.stateObjectsDirty)),
refund: new(big.Int).Set(self.refund), refund: new(big.Int).Set(self.refund),
@ -397,6 +419,7 @@ func (self *StateDB) Set(state *StateDB) {
self.pastTries = state.pastTries self.pastTries = state.pastTries
self.stateObjects = state.stateObjects self.stateObjects = state.stateObjects
self.stateObjectsDirty = state.stateObjectsDirty self.stateObjectsDirty = state.stateObjectsDirty
self.codeSizeCache = state.codeSizeCache
self.refund = state.refund self.refund = state.refund
self.logs = state.logs self.logs = state.logs
self.logSize = state.logSize self.logSize = state.logSize