1717package state
1818
1919import (
20+ "fmt"
2021 "maps"
22+ "slices"
23+ "sort"
2124
2225 "github.com/ethereum/go-ethereum/common"
26+ "github.com/ethereum/go-ethereum/core/types"
2327 "github.com/holiman/uint256"
2428)
2529
30+ type revision struct {
31+ id int
32+ journalIndex int
33+ }
34+
2635// journalEntry is a modification entry in the state change journal that can be
2736// reverted on demand.
2837type journalEntry interface {
@@ -42,6 +51,9 @@ type journalEntry interface {
4251type journal struct {
4352 entries []journalEntry // Current changes tracked by the journal
4453 dirties map [common.Address ]int // Dirty accounts and the number of changes
54+
55+ validRevisions []revision
56+ nextRevisionId int
4557}
4658
4759// newJournal creates a new initialized journal.
@@ -51,6 +63,40 @@ func newJournal() *journal {
5163 }
5264}
5365
66+ // reset clears the journal, after this operation the journal can be used anew.
67+ // It is semantically similar to calling 'newJournal', but the underlying slices
68+ // can be reused.
69+ func (j * journal ) reset () {
70+ j .entries = j .entries [:0 ]
71+ j .validRevisions = j .validRevisions [:0 ]
72+ clear (j .dirties )
73+ j .nextRevisionId = 0
74+ }
75+
76+ // snapshot returns an identifier for the current revision of the state.
77+ func (j * journal ) snapshot () int {
78+ id := j .nextRevisionId
79+ j .nextRevisionId ++
80+ j .validRevisions = append (j .validRevisions , revision {id , j .length ()})
81+ return id
82+ }
83+
84+ // revertToSnapshot reverts all state changes made since the given revision.
85+ func (j * journal ) revertToSnapshot (revid int , s * StateDB ) {
86+ // Find the snapshot in the stack of valid snapshots.
87+ idx := sort .Search (len (j .validRevisions ), func (i int ) bool {
88+ return j .validRevisions [i ].id >= revid
89+ })
90+ if idx == len (j .validRevisions ) || j .validRevisions [idx ].id != revid {
91+ panic (fmt .Errorf ("revision id %v cannot be reverted" , revid ))
92+ }
93+ snapshot := j .validRevisions [idx ].journalIndex
94+
95+ // Replay the journal to undo changes and remove invalidated snapshots
96+ j .revert (s , snapshot )
97+ j .validRevisions = j .validRevisions [:idx ]
98+ }
99+
54100// append inserts a new modification entry to the end of the change journal.
55101func (j * journal ) append (entry journalEntry ) {
56102 j .entries = append (j .entries , entry )
@@ -95,11 +141,90 @@ func (j *journal) copy() *journal {
95141 entries = append (entries , j .entries [i ].copy ())
96142 }
97143 return & journal {
98- entries : entries ,
99- dirties : maps .Clone (j .dirties ),
144+ entries : entries ,
145+ dirties : maps .Clone (j .dirties ),
146+ validRevisions : slices .Clone (j .validRevisions ),
147+ nextRevisionId : j .nextRevisionId ,
148+ }
149+ }
150+
151+ func (j * journal ) logChange (txHash common.Hash ) {
152+ j .append (addLogChange {txhash : txHash })
153+ }
154+
155+ func (j * journal ) createObject (addr common.Address ) {
156+ j .append (createObjectChange {account : & addr })
157+ }
158+
159+ func (j * journal ) createContract (addr common.Address ) {
160+ j .append (createContractChange {account : addr })
161+ }
162+
163+ func (j * journal ) destruct (addr common.Address ) {
164+ j .append (selfDestructChange {account : & addr })
165+ }
166+
167+ func (j * journal ) storageChange (addr common.Address , key , prev , origin common.Hash ) {
168+ j .append (storageChange {
169+ account : & addr ,
170+ key : key ,
171+ prevvalue : prev ,
172+ origvalue : origin ,
173+ })
174+ }
175+
176+ func (j * journal ) transientStateChange (addr common.Address , key , prev common.Hash ) {
177+ j .append (transientStorageChange {
178+ account : & addr ,
179+ key : key ,
180+ prevalue : prev ,
181+ })
182+ }
183+
184+ func (j * journal ) refundChange (previous uint64 ) {
185+ j .append (refundChange {prev : previous })
186+ }
187+
188+ func (j * journal ) balanceChange (addr common.Address , previous * uint256.Int ) {
189+ j .append (balanceChange {
190+ account : & addr ,
191+ prev : previous .Clone (),
192+ })
193+ }
194+
195+ func (j * journal ) setCode (address common.Address ) {
196+ j .append (codeChange {account : & address })
197+ }
198+
199+ func (j * journal ) nonceChange (address common.Address , prev uint64 ) {
200+ j .append (nonceChange {
201+ account : & address ,
202+ prev : prev ,
203+ })
204+ }
205+
206+ func (j * journal ) touchChange (address common.Address ) {
207+ j .append (touchChange {
208+ account : & address ,
209+ })
210+ if address == ripemd {
211+ // Explicitly put it in the dirty-cache, which is otherwise generated from
212+ // flattened journals.
213+ j .dirty (address )
100214 }
101215}
102216
217+ func (j * journal ) accessListAddAccount (addr common.Address ) {
218+ j .append (accessListAddAccountChange {& addr })
219+ }
220+
221+ func (j * journal ) accessListAddSlot (addr common.Address , slot common.Hash ) {
222+ j .append (accessListAddSlotChange {
223+ address : & addr ,
224+ slot : & slot ,
225+ })
226+ }
227+
103228type (
104229 // Changes to the account trie.
105230 createObjectChange struct {
@@ -114,9 +239,7 @@ type (
114239 }
115240
116241 selfDestructChange struct {
117- account * common.Address
118- prev bool // whether account had already self-destructed
119- prevbalance * uint256.Int
242+ account * common.Address
120243 }
121244
122245 // Changes to individual accounts.
@@ -135,8 +258,7 @@ type (
135258 origvalue common.Hash
136259 }
137260 codeChange struct {
138- account * common.Address
139- prevcode , prevhash []byte
261+ account * common.Address
140262 }
141263
142264 // Changes to other state values.
@@ -146,9 +268,6 @@ type (
146268 addLogChange struct {
147269 txhash common.Hash
148270 }
149- addPreimageChange struct {
150- hash common.Hash
151- }
152271 touchChange struct {
153272 account * common.Address
154273 }
@@ -200,8 +319,7 @@ func (ch createContractChange) copy() journalEntry {
200319func (ch selfDestructChange ) revert (s * StateDB ) {
201320 obj := s .getStateObject (* ch .account )
202321 if obj != nil {
203- obj .selfDestructed = ch .prev
204- obj .setBalance (ch .prevbalance )
322+ obj .selfDestructed = false
205323 }
206324}
207325
@@ -211,9 +329,7 @@ func (ch selfDestructChange) dirtied() *common.Address {
211329
212330func (ch selfDestructChange ) copy () journalEntry {
213331 return selfDestructChange {
214- account : ch .account ,
215- prev : ch .prev ,
216- prevbalance : new (uint256.Int ).Set (ch .prevbalance ),
332+ account : ch .account ,
217333 }
218334}
219335
@@ -263,19 +379,15 @@ func (ch nonceChange) copy() journalEntry {
263379}
264380
265381func (ch codeChange ) revert (s * StateDB ) {
266- s .getStateObject (* ch .account ).setCode (common . BytesToHash ( ch . prevhash ), ch . prevcode )
382+ s .getStateObject (* ch .account ).setCode (types . EmptyCodeHash , nil )
267383}
268384
269385func (ch codeChange ) dirtied () * common.Address {
270386 return ch .account
271387}
272388
273389func (ch codeChange ) copy () journalEntry {
274- return codeChange {
275- account : ch .account ,
276- prevhash : common .CopyBytes (ch .prevhash ),
277- prevcode : common .CopyBytes (ch .prevcode ),
278- }
390+ return codeChange {account : ch .account }
279391}
280392
281393func (ch storageChange ) revert (s * StateDB ) {
@@ -344,20 +456,6 @@ func (ch addLogChange) copy() journalEntry {
344456 }
345457}
346458
347- func (ch addPreimageChange ) revert (s * StateDB ) {
348- delete (s .preimages , ch .hash )
349- }
350-
351- func (ch addPreimageChange ) dirtied () * common.Address {
352- return nil
353- }
354-
355- func (ch addPreimageChange ) copy () journalEntry {
356- return addPreimageChange {
357- hash : ch .hash ,
358- }
359- }
360-
361459func (ch accessListAddAccountChange ) revert (s * StateDB ) {
362460 /*
363461 One important invariant here, is that whenever a (addr, slot) is added, if the
0 commit comments