Skip to content

Commit 945bcb8

Browse files
committed
[release/1.4.15] core/state: track dirty state entries for each object
(cherry picked from commit b715981)
1 parent f1949f4 commit 945bcb8

File tree

2 files changed

+24
-18
lines changed

2 files changed

+24
-18
lines changed

core/state/state_object.go

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -75,9 +75,11 @@ type StateObject struct {
7575
dbErr error
7676

7777
// Write caches.
78-
trie *trie.SecureTrie // storage trie, which becomes non-nil on first access
79-
code Code // contract bytecode, which gets set when code is loaded
80-
storage Storage // Cached storage (flushed when updated)
78+
trie *trie.SecureTrie // storage trie, which becomes non-nil on first access
79+
code Code // contract bytecode, which gets set when code is loaded
80+
81+
cachedStorage Storage // Storage entry cache to avoid duplicate reads
82+
dirtyStorage Storage // Storage entries that need to be flushed to disk
8183

8284
// Cache flags.
8385
// When an object is marked for deletion it will be delete from the trie
@@ -105,7 +107,7 @@ func NewObject(address common.Address, data Account, onDirty func(addr common.Ad
105107
if data.CodeHash == nil {
106108
data.CodeHash = emptyCodeHash
107109
}
108-
return &StateObject{address: address, data: data, storage: make(Storage), onDirty: onDirty}
110+
return &StateObject{address: address, data: data, cachedStorage: make(Storage), dirtyStorage: make(Storage), onDirty: onDirty}
109111
}
110112

111113
// EncodeRLP implements rlp.Encoder.
@@ -145,7 +147,7 @@ func (c *StateObject) getTrie(db trie.Database) *trie.SecureTrie {
145147

146148
// GetState returns a value in account storage.
147149
func (self *StateObject) GetState(db trie.Database, key common.Hash) common.Hash {
148-
value, exists := self.storage[key]
150+
value, exists := self.cachedStorage[key]
149151
if exists {
150152
return value
151153
}
@@ -155,14 +157,16 @@ func (self *StateObject) GetState(db trie.Database, key common.Hash) common.Hash
155157
rlp.DecodeBytes(tr.Get(key[:]), &ret)
156158
value = common.BytesToHash(ret)
157159
if (value != common.Hash{}) {
158-
self.storage[key] = value
160+
self.cachedStorage[key] = value
159161
}
160162
return value
161163
}
162164

163165
// SetState updates a value in account storage.
164166
func (self *StateObject) SetState(key, value common.Hash) {
165-
self.storage[key] = value
167+
self.cachedStorage[key] = value
168+
self.dirtyStorage[key] = value
169+
166170
if self.onDirty != nil {
167171
self.onDirty(self.Address())
168172
self.onDirty = nil
@@ -172,7 +176,8 @@ func (self *StateObject) SetState(key, value common.Hash) {
172176
// updateTrie writes cached storage modifications into the object's storage trie.
173177
func (self *StateObject) updateTrie(db trie.Database) {
174178
tr := self.getTrie(db)
175-
for key, value := range self.storage {
179+
for key, value := range self.dirtyStorage {
180+
delete(self.dirtyStorage, key)
176181
if (value == common.Hash{}) {
177182
tr.Delete(key[:])
178183
continue
@@ -241,7 +246,8 @@ func (self *StateObject) Copy(db trie.Database, onDirty func(addr common.Address
241246
stateObject := NewObject(self.address, self.data, onDirty)
242247
stateObject.trie = self.trie
243248
stateObject.code = self.code
244-
stateObject.storage = self.storage.Copy()
249+
stateObject.dirtyStorage = self.dirtyStorage.Copy()
250+
stateObject.cachedStorage = self.dirtyStorage.Copy()
245251
stateObject.remove = self.remove
246252
stateObject.dirtyCode = self.dirtyCode
247253
stateObject.deleted = self.deleted
@@ -312,15 +318,15 @@ func (self *StateObject) Value() *big.Int {
312318

313319
func (self *StateObject) ForEachStorage(cb func(key, value common.Hash) bool) {
314320
// When iterating over the storage check the cache first
315-
for h, value := range self.storage {
321+
for h, value := range self.cachedStorage {
316322
cb(h, value)
317323
}
318324

319325
it := self.trie.Iterator()
320326
for it.Next() {
321327
// ignore cached values
322328
key := common.BytesToHash(self.trie.GetKey(it.Key))
323-
if _, ok := self.storage[key]; !ok {
329+
if _, ok := self.cachedStorage[key]; !ok {
324330
cb(key, common.BytesToHash(it.Value))
325331
}
326332
}

core/state/state_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -208,16 +208,16 @@ func compareStateObjects(so0, so1 *StateObject, t *testing.T) {
208208
t.Fatalf("Code mismatch: have %v, want %v", so0.code, so1.code)
209209
}
210210

211-
if len(so1.storage) != len(so0.storage) {
212-
t.Errorf("Storage size mismatch: have %d, want %d", len(so1.storage), len(so0.storage))
211+
if len(so1.cachedStorage) != len(so0.cachedStorage) {
212+
t.Errorf("Storage size mismatch: have %d, want %d", len(so1.cachedStorage), len(so0.cachedStorage))
213213
}
214-
for k, v := range so1.storage {
215-
if so0.storage[k] != v {
216-
t.Errorf("Storage key %x mismatch: have %v, want %v", k, so0.storage[k], v)
214+
for k, v := range so1.cachedStorage {
215+
if so0.cachedStorage[k] != v {
216+
t.Errorf("Storage key %x mismatch: have %v, want %v", k, so0.cachedStorage[k], v)
217217
}
218218
}
219-
for k, v := range so0.storage {
220-
if so1.storage[k] != v {
219+
for k, v := range so0.cachedStorage {
220+
if so1.cachedStorage[k] != v {
221221
t.Errorf("Storage key %x mismatch: have %v, want none.", k, v)
222222
}
223223
}

0 commit comments

Comments
 (0)