Skip to content

Commit 5005f21

Browse files
committed
core/state: remove slot dirtiness if it's set back to origin value
1 parent 3e896c8 commit 5005f21

File tree

3 files changed

+65
-25
lines changed

3 files changed

+65
-25
lines changed

core/state/journal.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,8 @@ type (
131131
storageChange struct {
132132
account *common.Address
133133
key common.Hash
134-
prevvalue *common.Hash
134+
prevvalue common.Hash
135+
origvalue common.Hash
135136
}
136137
codeChange struct {
137138
account *common.Address
@@ -278,7 +279,7 @@ func (ch codeChange) copy() journalEntry {
278279
}
279280

280281
func (ch storageChange) revert(s *StateDB) {
281-
s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue)
282+
s.getStateObject(*ch.account).setState(ch.key, ch.prevvalue, ch.origvalue)
282283
}
283284

284285
func (ch storageChange) dirtied() *common.Address {

core/state/state_object.go

Lines changed: 18 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -145,16 +145,15 @@ func (s *stateObject) GetState(key common.Hash) common.Hash {
145145
return value
146146
}
147147

148-
// getState retrieves a value from the account storage trie and also returns if
149-
// the slot is already dirty or not.
150-
func (s *stateObject) getState(key common.Hash) (common.Hash, bool) {
151-
// If we have a dirty value for this state entry, return it
148+
// getState retrieves a value associated with the given storage key, along with
149+
// it's original value.
150+
func (s *stateObject) getState(key common.Hash) (common.Hash, common.Hash) {
151+
origin := s.GetCommittedState(key)
152152
value, dirty := s.dirtyStorage[key]
153-
if dirty {
154-
return value, true
153+
if !dirty {
154+
value = origin
155155
}
156-
// Otherwise return the entry's original value
157-
return s.GetCommittedState(key), false
156+
return value, origin
158157
}
159158

160159
// GetCommittedState retrieves a value from the committed account storage trie.
@@ -219,36 +218,32 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
219218
func (s *stateObject) SetState(key, value common.Hash) {
220219
// If the new value is the same as old, don't set. Otherwise, track only the
221220
// dirty changes, supporting reverting all of it back to no change.
222-
prev, dirty := s.getState(key)
221+
prev, origin := s.getState(key)
223222
if prev == value {
224223
return
225224
}
226-
var prevvalue *common.Hash
227-
if dirty {
228-
prevvalue = &prev
229-
}
230225
// New value is different, update and journal the change
231226
s.db.journal.append(storageChange{
232227
account: &s.address,
233228
key: key,
234-
prevvalue: prevvalue,
229+
prevvalue: prev,
230+
origvalue: origin,
235231
})
236232
if s.db.logger != nil && s.db.logger.OnStorageChange != nil {
237233
s.db.logger.OnStorageChange(s.address, key, prev, value)
238234
}
239-
s.setState(key, &value)
235+
s.setState(key, value, origin)
240236
}
241237

242-
// setState updates a value in account dirty storage. If the value being set is
243-
// nil (assuming journal revert), the dirtyness is removed.
244-
func (s *stateObject) setState(key common.Hash, value *common.Hash) {
245-
// If the first set is being reverted, undo the dirty marker
246-
if value == nil {
238+
// setState updates a value in account dirty storage. The dirtiness will be
239+
// removed if the value being set equals to the original value.
240+
func (s *stateObject) setState(key common.Hash, value common.Hash, origin common.Hash) {
241+
// Storage slot is set back to its original value, undo the dirty marker
242+
if value == origin {
247243
delete(s.dirtyStorage, key)
248244
return
249245
}
250-
// Otherwise restore the previous value
251-
s.dirtyStorage[key] = *value
246+
s.dirtyStorage[key] = value
252247
}
253248

254249
// finalise moves all dirty storage slots into the pending area to be hashed or
@@ -264,7 +259,7 @@ func (s *stateObject) finalise(prefetch bool) {
264259
slotsToPrefetch = append(slotsToPrefetch, common.CopyBytes(key[:])) // Copy needed for closure
265260
} else {
266261
// Otherwise, the slot was reverted to its original value, remove it
267-
// from the pending area to avoid thrashing the data strutures.
262+
// from the pending area to avoid thrashing the data structure.
268263
delete(s.pendingStorage, key)
269264
}
270265
}

core/state/statedb_test.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1329,3 +1329,47 @@ func TestDeleteStorage(t *testing.T) {
13291329
t.Fatalf("difference found:\nfast: %v\nslow: %v\n", fastRes, slowRes)
13301330
}
13311331
}
1332+
1333+
func TestStorageDirtiness(t *testing.T) {
1334+
var (
1335+
disk = rawdb.NewMemoryDatabase()
1336+
tdb = triedb.NewDatabase(disk, nil)
1337+
db = NewDatabaseWithNodeDB(disk, tdb)
1338+
state, _ = New(types.EmptyRootHash, db, nil)
1339+
addr = common.HexToAddress("0x1")
1340+
checkDirty = func(key common.Hash, value common.Hash, dirty bool) {
1341+
obj := state.getStateObject(addr)
1342+
v, exist := obj.dirtyStorage[key]
1343+
if exist != dirty {
1344+
t.Fatalf("Unexpected dirty marker, want: %t, got: %t", dirty, exist)
1345+
}
1346+
if v != value {
1347+
t.Fatalf("Unexpected storage slot, want: %t, got: %t", value, v)
1348+
}
1349+
}
1350+
)
1351+
state.CreateAccount(addr)
1352+
1353+
// the storage change is noop, no dirty marker
1354+
state.SetState(addr, common.Hash{0x1}, common.Hash{})
1355+
checkDirty(common.Hash{0x1}, common.Hash{}, false)
1356+
1357+
// the storage change is valid, dirty marker is expected
1358+
snap := state.Snapshot()
1359+
state.SetState(addr, common.Hash{0x1}, common.Hash{0x1})
1360+
checkDirty(common.Hash{0x1}, common.Hash{0x1}, true)
1361+
1362+
// the storage change is reverted, dirtiness should be revoked
1363+
state.RevertToSnapshot(snap)
1364+
checkDirty(common.Hash{0x1}, common.Hash{}, false)
1365+
1366+
// the storage is reset back to its original value, dirtiness should be revoked
1367+
state.SetState(addr, common.Hash{0x1}, common.Hash{0x1})
1368+
snap = state.Snapshot()
1369+
state.SetState(addr, common.Hash{0x1}, common.Hash{})
1370+
checkDirty(common.Hash{0x1}, common.Hash{}, false)
1371+
1372+
// the storage change is reverted, dirty value should be set back
1373+
state.RevertToSnapshot(snap)
1374+
checkDirty(common.Hash{0x1}, common.Hash{0x1}, true)
1375+
}

0 commit comments

Comments
 (0)