Revert "core/state: be smarter as to where we read state from"

This reverts commit aef093b73f.
This commit is contained in:
Péter Szilágyi 2019-08-12 10:15:54 +03:00
parent 9e96671bd1
commit 9265a267cd
No known key found for this signature in database
GPG key ID: E9AE538CEDF8293D
4 changed files with 33 additions and 63 deletions

View file

@ -151,7 +151,7 @@ func (ch resetObjectChange) dirtied() *common.Address {
} }
func (ch suicideChange) revert(s *StateDB) { func (ch suicideChange) revert(s *StateDB) {
obj := s.getStateObject(*ch.account, true) obj := s.getStateObject(*ch.account)
if obj != nil { if obj != nil {
obj.suicided = ch.prev obj.suicided = ch.prev
obj.setBalance(ch.prevbalance) obj.setBalance(ch.prevbalance)
@ -172,7 +172,7 @@ func (ch touchChange) dirtied() *common.Address {
} }
func (ch balanceChange) revert(s *StateDB) { func (ch balanceChange) revert(s *StateDB) {
s.getStateObject(*ch.account, true).setBalance(ch.prev) s.getStateObject(*ch.account).setBalance(ch.prev)
} }
func (ch balanceChange) dirtied() *common.Address { func (ch balanceChange) dirtied() *common.Address {
@ -180,7 +180,7 @@ func (ch balanceChange) dirtied() *common.Address {
} }
func (ch nonceChange) revert(s *StateDB) { func (ch nonceChange) revert(s *StateDB) {
s.getStateObject(*ch.account, true).setNonce(ch.prev) s.getStateObject(*ch.account).setNonce(ch.prev)
} }
func (ch nonceChange) dirtied() *common.Address { func (ch nonceChange) dirtied() *common.Address {
@ -188,7 +188,7 @@ func (ch nonceChange) dirtied() *common.Address {
} }
func (ch codeChange) revert(s *StateDB) { func (ch codeChange) revert(s *StateDB) {
s.getStateObject(*ch.account, true).setCode(common.BytesToHash(ch.prevhash), ch.prevcode) s.getStateObject(*ch.account).setCode(common.BytesToHash(ch.prevhash), ch.prevcode)
} }
func (ch codeChange) dirtied() *common.Address { func (ch codeChange) dirtied() *common.Address {
@ -196,7 +196,7 @@ func (ch codeChange) dirtied() *common.Address {
} }
func (ch storageChange) revert(s *StateDB) { func (ch storageChange) revert(s *StateDB) {
s.getStateObject(*ch.account, true).setState(ch.key, ch.prevalue) s.getStateObject(*ch.account).setState(ch.key, ch.prevalue)
} }
func (ch storageChange) dirtied() *common.Address { func (ch storageChange) dirtied() *common.Address {

View file

@ -162,56 +162,27 @@ func (s *stateObject) getTrie(db Database) Trie {
return s.trie return s.trie
} }
// GetState retrieves a value from the account storage. This method will use the // GetState retrieves a value from the account storage trie.
// state snapshot so retrieve the value (opposed to the trie directly) since the
// read doesn't need to pull in log(n) trie nodes in addition from disk.
func (s *stateObject) GetState(db Database, key common.Hash) common.Hash { func (s *stateObject) GetState(db Database, key common.Hash) common.Hash {
// If the fake storage is set, only lookup the state here (debugging mode) // If the fake storage is set, only lookup the state here(in the debugging mode)
if s.fakeStorage != nil { if s.fakeStorage != nil {
return s.fakeStorage[key] return s.fakeStorage[key]
} }
// No fake storage, retrieve a real object from the storage trie. We're cheating
// a bit here since we know that this method is only using during simple reads.
// As such, we possibly will not write this key, so might as well avoid touching
// trie nodes and pull it directly from the state snapshot.
return s.getState(db, key, true)
}
// getState retrieves a value from the account's storage, but the caller gets to
// control whether to use the state snapshot or the state trie as the source. For
// simple reads, the snapshot should be used as it's faster. For writes however,
// using the trie will be a bit slower, but will pre-cache nodes needed during
// commit anyway.
func (s *stateObject) getState(db Database, key common.Hash, snapshot bool) common.Hash {
// If we have a dirty value for this state entry, return it // If we have a dirty value for this state entry, return it
value, dirty := s.dirtyStorage[key] value, dirty := s.dirtyStorage[key]
if dirty { if dirty {
return value return value
} }
// Otherwise return the entry's original value // Otherwise return the entry's original value
return s.getCommittedState(db, key, snapshot) return s.GetCommittedState(db, key)
} }
// GetCommittedState retrieves a value from the committed account storage. This // GetCommittedState retrieves a value from the committed account storage trie.
// method will use the slow trie (opposed to state snapshots) since the committed
// value is only ever used to avoid writes, so we can pre-load trie nodes.
func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash { func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Hash {
// If the fake storage is set, only lookup the state here (debugging mode) // If the fake storage is set, only lookup the state here(in the debugging mode)
if s.fakeStorage != nil { if s.fakeStorage != nil {
return s.fakeStorage[key] return s.fakeStorage[key]
} }
// No fake storage, retrieve a real object from the storage trie. We're cheating
// a bit here since we know that this method is only using during net sstore gas
// metering. As such, we probably not only read, but also write this key in the
// same transaction, so might as well pre-cache trie nodes on the write path.
return s.getCommittedState(db, key, false)
}
// getCommittedState retrieves a value from the account's storage, but the caller
// gets to control whether to use the state snapshot or the state trie. For simple
// reads, the snapshot should be used as it's faster. For pre-writes however, using
// the trie will be a bit slower, but will pre-cache nodes needed during commit.
func (s *stateObject) getCommittedState(db Database, key common.Hash, snapshot bool) common.Hash {
// If we have the original value cached, return that // If we have the original value cached, return that
value, cached := s.originStorage[key] value, cached := s.originStorage[key]
if cached { if cached {
@ -222,7 +193,7 @@ func (s *stateObject) getCommittedState(db Database, key common.Hash, snapshot b
enc []byte enc []byte
err error err error
) )
if snapshot && s.db.snap != nil { if s.db.snap != nil {
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
defer func(start time.Time) { s.db.SnapshotStorageReads += time.Since(start) }(time.Now()) defer func(start time.Time) { s.db.SnapshotStorageReads += time.Since(start) }(time.Now())
} }
@ -256,9 +227,8 @@ func (s *stateObject) SetState(db Database, key, value common.Hash) {
s.fakeStorage[key] = value s.fakeStorage[key] = value
return return
} }
// If the new value is the same as old, don't set (use the trie to cache any // If the new value is the same as old, don't set
// nodes if we decide to write) prev := s.GetState(db, key)
prev := s.getState(db, key, false)
if prev == value { if prev == value {
return return
} }

View file

@ -234,19 +234,19 @@ func (self *StateDB) SubRefund(gas uint64) {
// Exist reports whether the given account address exists in the state. // Exist reports whether the given account address exists in the state.
// Notably this also returns true for suicided accounts. // Notably this also returns true for suicided accounts.
func (self *StateDB) Exist(addr common.Address) bool { func (self *StateDB) Exist(addr common.Address) bool {
return self.getStateObject(addr, true) != nil return self.getStateObject(addr) != nil
} }
// Empty returns whether the state object is either non-existent // Empty returns whether the state object is either non-existent
// or empty according to the EIP161 specification (balance = nonce = code = 0) // or empty according to the EIP161 specification (balance = nonce = code = 0)
func (self *StateDB) Empty(addr common.Address) bool { func (self *StateDB) Empty(addr common.Address) bool {
so := self.getStateObject(addr, true) so := self.getStateObject(addr)
return so == nil || so.empty() return so == nil || so.empty()
} }
// Retrieve the balance from the given address or 0 if object not found // Retrieve the balance from the given address or 0 if object not found
func (self *StateDB) GetBalance(addr common.Address) *big.Int { func (self *StateDB) GetBalance(addr common.Address) *big.Int {
stateObject := self.getStateObject(addr, true) stateObject := self.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.Balance() return stateObject.Balance()
} }
@ -254,7 +254,7 @@ func (self *StateDB) GetBalance(addr common.Address) *big.Int {
} }
func (self *StateDB) GetNonce(addr common.Address) uint64 { func (self *StateDB) GetNonce(addr common.Address) uint64 {
stateObject := self.getStateObject(addr, true) stateObject := self.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.Nonce() return stateObject.Nonce()
} }
@ -273,7 +273,7 @@ func (self *StateDB) BlockHash() common.Hash {
} }
func (self *StateDB) GetCode(addr common.Address) []byte { func (self *StateDB) GetCode(addr common.Address) []byte {
stateObject := self.getStateObject(addr, true) stateObject := self.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.Code(self.db) return stateObject.Code(self.db)
} }
@ -281,7 +281,7 @@ func (self *StateDB) GetCode(addr common.Address) []byte {
} }
func (self *StateDB) GetCodeSize(addr common.Address) int { func (self *StateDB) GetCodeSize(addr common.Address) int {
stateObject := self.getStateObject(addr, true) stateObject := self.getStateObject(addr)
if stateObject == nil { if stateObject == nil {
return 0 return 0
} }
@ -296,7 +296,7 @@ func (self *StateDB) GetCodeSize(addr common.Address) int {
} }
func (self *StateDB) GetCodeHash(addr common.Address) common.Hash { func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
stateObject := self.getStateObject(addr, true) stateObject := self.getStateObject(addr)
if stateObject == nil { if stateObject == nil {
return common.Hash{} return common.Hash{}
} }
@ -305,7 +305,7 @@ func (self *StateDB) GetCodeHash(addr common.Address) common.Hash {
// GetState retrieves a value from the given account's storage trie. // GetState retrieves a value from the given account's storage trie.
func (self *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash { func (self *StateDB) GetState(addr common.Address, hash common.Hash) common.Hash {
stateObject := self.getStateObject(addr, true) stateObject := self.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.GetState(self.db, hash) return stateObject.GetState(self.db, hash)
} }
@ -330,11 +330,9 @@ func (self *StateDB) GetStorageProof(a common.Address, key common.Hash) ([][]byt
return [][]byte(proof), err return [][]byte(proof), err
} }
// GetCommittedState retrieves a value from the given account's committed storage. // GetCommittedState retrieves a value from the given account's committed storage trie.
// This method will use the slow trie (opposed to state snapshots) since the value
// committed is only ever used to avoid writes, so we can pre-load trie nodes.
func (self *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash { func (self *StateDB) GetCommittedState(addr common.Address, hash common.Hash) common.Hash {
stateObject := self.getStateObject(addr, false) stateObject := self.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.GetCommittedState(self.db, hash) return stateObject.GetCommittedState(self.db, hash)
} }
@ -349,7 +347,7 @@ func (self *StateDB) Database() Database {
// StorageTrie returns the storage trie of an account. // StorageTrie returns the storage trie of an account.
// The return value is a copy and is nil for non-existent accounts. // The return value is a copy and is nil for non-existent accounts.
func (self *StateDB) StorageTrie(addr common.Address) Trie { func (self *StateDB) StorageTrie(addr common.Address) Trie {
stateObject := self.getStateObject(addr, true) stateObject := self.getStateObject(addr)
if stateObject == nil { if stateObject == nil {
return nil return nil
} }
@ -358,7 +356,7 @@ func (self *StateDB) StorageTrie(addr common.Address) Trie {
} }
func (self *StateDB) HasSuicided(addr common.Address) bool { func (self *StateDB) HasSuicided(addr common.Address) bool {
stateObject := self.getStateObject(addr, true) stateObject := self.getStateObject(addr)
if stateObject != nil { if stateObject != nil {
return stateObject.suicided return stateObject.suicided
} }
@ -428,7 +426,7 @@ func (self *StateDB) SetStorage(addr common.Address, storage map[common.Hash]com
// The account's state object is still available until the state is committed, // The account's state object is still available until the state is committed,
// getStateObject will return a non-nil account after Suicide. // getStateObject will return a non-nil account after Suicide.
func (self *StateDB) Suicide(addr common.Address) bool { func (self *StateDB) Suicide(addr common.Address) bool {
stateObject := self.getStateObject(addr, false) stateObject := self.getStateObject(addr)
if stateObject == nil { if stateObject == nil {
return false return false
} }
@ -487,7 +485,7 @@ func (s *StateDB) deleteStateObject(stateObject *stateObject) {
} }
// Retrieve a state object given by the address. Returns nil if not found. // Retrieve a state object given by the address. Returns nil if not found.
func (s *StateDB) getStateObject(addr common.Address, snapshot bool) (stateObject *stateObject) { func (s *StateDB) getStateObject(addr common.Address) (stateObject *stateObject) {
// Prefer live objects // Prefer live objects
if obj := s.stateObjects[addr]; obj != nil { if obj := s.stateObjects[addr]; obj != nil {
if obj.deleted { if obj.deleted {
@ -497,7 +495,7 @@ func (s *StateDB) getStateObject(addr common.Address, snapshot bool) (stateObjec
} }
// If no live objects are available, attempt to use snapshots // If no live objects are available, attempt to use snapshots
var data Account var data Account
if snapshot && s.snap != nil { if s.snap != nil {
if metrics.EnabledExpensive { if metrics.EnabledExpensive {
defer func(start time.Time) { s.SnapshotAccountReads += time.Since(start) }(time.Now()) defer func(start time.Time) { s.SnapshotAccountReads += time.Since(start) }(time.Now())
} }
@ -540,7 +538,7 @@ func (self *StateDB) setStateObject(object *stateObject) {
// Retrieve a state object or create a new state object if nil. // Retrieve a state object or create a new state object if nil.
func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject { func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
stateObject := self.getStateObject(addr, true) stateObject := self.getStateObject(addr)
if stateObject == nil || stateObject.deleted { if stateObject == nil || stateObject.deleted {
stateObject, _ = self.createObject(addr) stateObject, _ = self.createObject(addr)
} }
@ -550,7 +548,7 @@ func (self *StateDB) GetOrNewStateObject(addr common.Address) *stateObject {
// createObject creates a new state object. If there is an existing account with // createObject creates a new state object. If there is an existing account with
// the given address, it is overwritten and returned as the second return value. // the given address, it is overwritten and returned as the second return value.
func (self *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) { func (self *StateDB) createObject(addr common.Address) (newobj, prev *stateObject) {
prev = self.getStateObject(addr, false) prev = self.getStateObject(addr)
newobj = newObject(self, addr, Account{}) newobj = newObject(self, addr, Account{})
newobj.setNonce(0) // sets the object to dirty newobj.setNonce(0) // sets the object to dirty
if prev == nil { if prev == nil {
@ -580,7 +578,7 @@ func (self *StateDB) CreateAccount(addr common.Address) {
} }
func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error { func (db *StateDB) ForEachStorage(addr common.Address, cb func(key, value common.Hash) bool) error {
so := db.getStateObject(addr, true) so := db.getStateObject(addr)
if so == nil { if so == nil {
return nil return nil
} }

View file

@ -65,6 +65,8 @@ func (p *statePrefetcher) Prefetch(block *types.Block, statedb *state.StateDB, c
return // Ugh, something went horribly wrong, bail out return // Ugh, something went horribly wrong, bail out
} }
} }
// All transactions processed, finalize the block to force loading written-only trie paths
statedb.Finalise(true) // TODO(karalabe): should we run this on interrupt too?
} }
// precacheTransaction attempts to apply a transaction to the given state database // precacheTransaction attempts to apply a transaction to the given state database