@@ -79,9 +79,10 @@ type stateObject struct {
79
79
trie Trie // storage trie, which becomes non-nil on first access
80
80
code Code // contract bytecode, which gets set when code is loaded
81
81
82
- originStorage Storage // Storage cache of original entries to dedup rewrites
83
- dirtyStorage Storage // Storage entries that need to be flushed to disk
84
- fakeStorage Storage // Fake storage which constructed by caller for debugging purpose.
82
+ originStorage Storage // Storage cache of original entries to dedup rewrites, reset for every transaction
83
+ pendingStorage Storage // Storage entries that need to be flushed to disk, at the end of an entire block
84
+ dirtyStorage Storage // Storage entries that have been modified in the current transaction execution
85
+ fakeStorage Storage // Fake storage which constructed by caller for debugging purpose.
85
86
86
87
// Cache flags.
87
88
// When an object is marked suicided it will be delete from the trie
@@ -113,13 +114,17 @@ func newObject(db *StateDB, address common.Address, data Account) *stateObject {
113
114
if data .CodeHash == nil {
114
115
data .CodeHash = emptyCodeHash
115
116
}
117
+ if data .Root == (common.Hash {}) {
118
+ data .Root = emptyRoot
119
+ }
116
120
return & stateObject {
117
- db : db ,
118
- address : address ,
119
- addrHash : crypto .Keccak256Hash (address [:]),
120
- data : data ,
121
- originStorage : make (Storage ),
122
- dirtyStorage : make (Storage ),
121
+ db : db ,
122
+ address : address ,
123
+ addrHash : crypto .Keccak256Hash (address [:]),
124
+ data : data ,
125
+ originStorage : make (Storage ),
126
+ pendingStorage : make (Storage ),
127
+ dirtyStorage : make (Storage ),
123
128
}
124
129
}
125
130
@@ -183,9 +188,11 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
183
188
if s .fakeStorage != nil {
184
189
return s .fakeStorage [key ]
185
190
}
186
- // If we have the original value cached, return that
187
- value , cached := s .originStorage [key ]
188
- if cached {
191
+ // If we have a pending write or clean cached, return that
192
+ if value , pending := s .pendingStorage [key ]; pending {
193
+ return value
194
+ }
195
+ if value , cached := s .originStorage [key ]; cached {
189
196
return value
190
197
}
191
198
// Track the amount of time wasted on reading the storage trie
@@ -198,6 +205,7 @@ func (s *stateObject) GetCommittedState(db Database, key common.Hash) common.Has
198
205
s .setError (err )
199
206
return common.Hash {}
200
207
}
208
+ var value common.Hash
201
209
if len (enc ) > 0 {
202
210
_ , content , _ , err := rlp .Split (enc )
203
211
if err != nil {
@@ -252,17 +260,29 @@ func (s *stateObject) setState(key, value common.Hash) {
252
260
s .dirtyStorage [key ] = value
253
261
}
254
262
263
+ // finalise moves all dirty storage slots into the pending area to be hashed or
264
+ // committed later. It is invoked at the end of every transaction.
265
+ func (s * stateObject ) finalise () {
266
+ for key , value := range s .dirtyStorage {
267
+ s .pendingStorage [key ] = value
268
+ }
269
+ if len (s .dirtyStorage ) > 0 {
270
+ s .dirtyStorage = make (Storage )
271
+ }
272
+ }
273
+
255
274
// updateTrie writes cached storage modifications into the object's storage trie.
256
275
func (s * stateObject ) updateTrie (db Database ) Trie {
276
+ // Make sure all dirty slots are finalized into the pending storage area
277
+ s .finalise ()
278
+
257
279
// Track the amount of time wasted on updating the storge trie
258
280
if metrics .EnabledExpensive {
259
281
defer func (start time.Time ) { s .db .StorageUpdates += time .Since (start ) }(time .Now ())
260
282
}
261
- // Update all the dirty slots in the trie
283
+ // Insert all the pending updates into the trie
262
284
tr := s .getTrie (db )
263
- for key , value := range s .dirtyStorage {
264
- delete (s .dirtyStorage , key )
265
-
285
+ for key , value := range s .pendingStorage {
266
286
// Skip noop changes, persist actual changes
267
287
if value == s .originStorage [key ] {
268
288
continue
@@ -277,6 +297,9 @@ func (s *stateObject) updateTrie(db Database) Trie {
277
297
v , _ := rlp .EncodeToBytes (common .TrimLeftZeroes (value [:]))
278
298
s .setError (tr .TryUpdate (key [:], v ))
279
299
}
300
+ if len (s .pendingStorage ) > 0 {
301
+ s .pendingStorage = make (Storage )
302
+ }
280
303
return tr
281
304
}
282
305
0 commit comments