core/state: storage journal entry should revert dirtyness too

This commit is contained in:
Péter Szilágyi 2024-04-24 15:29:49 +03:00
parent ac21f9bfb5
commit 23f4f7e708
2 changed files with 37 additions and 16 deletions

View file

@ -129,8 +129,9 @@ type (
prev uint64 prev uint64
} }
storageChange struct { storageChange struct {
account *common.Address account *common.Address
key, prevalue common.Hash key common.Hash
prevvalue *common.Hash
} }
codeChange struct { codeChange struct {
account *common.Address account *common.Address
@ -277,7 +278,7 @@ func (ch codeChange) copy() journalEntry {
} }
func (ch storageChange) revert(s *StateDB) { func (ch storageChange) revert(s *StateDB) {
s.getStateObject(*ch.account).setState(ch.key, ch.prevalue) s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue)
} }
func (ch storageChange) dirtied() *common.Address { func (ch storageChange) dirtied() *common.Address {
@ -286,9 +287,9 @@ func (ch storageChange) dirtied() *common.Address {
func (ch storageChange) copy() journalEntry { func (ch storageChange) copy() journalEntry {
return storageChange{ return storageChange{
account: ch.account, account: ch.account,
key: ch.key, key: ch.key,
prevalue: ch.prevalue, prevvalue: ch.prevvalue,
} }
} }

View file

@ -140,13 +140,20 @@ func (s *stateObject) getTrie() (Trie, error) {
// GetState retrieves a value from the account storage trie. // GetState retrieves a value from the account storage trie.
func (s *stateObject) GetState(key common.Hash) common.Hash { func (s *stateObject) GetState(key common.Hash) common.Hash {
value, _ := s.getState(key)
return value
}
// getState retrieves a value from the account storage trie and also returns if
// the slot is already dirty or not.
func (s *stateObject) getState(key common.Hash) (common.Hash, bool) {
// 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, true
} }
// Otherwise return the entry's original value // Otherwise return the entry's original value
return s.GetCommittedState(key) return s.GetCommittedState(key), false
} }
// GetCommittedState retrieves a value from the committed account storage trie. // GetCommittedState retrieves a value from the committed account storage trie.
@ -209,25 +216,38 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
// SetState updates a value in account storage. // SetState updates a value in account storage.
func (s *stateObject) SetState(key, value common.Hash) { func (s *stateObject) SetState(key, value common.Hash) {
// If the new value is the same as old, don't set // If the new value is the same as old, don't set. Otherwise, track only the
prev := s.GetState(key) // dirty changes, supporting reverting all of it back to no change.
prev, dirty := s.getState(key)
if prev == value { if prev == value {
return return
} }
var prevvalue *common.Hash
if dirty {
prevvalue = &prev
}
// New value is different, update and journal the change // New value is different, update and journal the change
s.db.journal.append(storageChange{ s.db.journal.append(storageChange{
account: &s.address, account: &s.address,
key: key, key: key,
prevalue: prev, prevvalue: prevvalue,
}) })
if s.db.logger != nil && s.db.logger.OnStorageChange != nil { if s.db.logger != nil && s.db.logger.OnStorageChange != nil {
s.db.logger.OnStorageChange(s.address, key, prev, value) s.db.logger.OnStorageChange(s.address, key, prev, value)
} }
s.setState(key, value) s.setState(key, &value)
} }
func (s *stateObject) setState(key, value common.Hash) { // setState updates a value in account dirty storage. If the value being set is
s.dirtyStorage[key] = value // nil (assuming journal revert), the dirtyness is removed.
func (s *stateObject) setState(key common.Hash, value *common.Hash) {
// If the first set is being reverted, undo the dirty marker
if value == nil {
delete(s.dirtyStorage, key)
return
}
// Otherwise restore the previous value
s.dirtyStorage[key] = *value
} }
// finalise moves all dirty storage slots into the pending area to be hashed or // finalise moves all dirty storage slots into the pending area to be hashed or