Skip to content

Commit 79b00d1

Browse files
committed
core/state: simplify journal api, remove externally visible snapshot ids
1 parent 605cc25 commit 79b00d1

File tree

17 files changed

+207
-240
lines changed

17 files changed

+207
-240
lines changed

cmd/evm/internal/t8ntool/execution.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -254,9 +254,9 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
254254

255255
var (
256256
txContext = core.NewEVMTxContext(msg)
257-
snapshot = statedb.Snapshot()
258257
prevGas = gaspool.Gas()
259258
)
259+
statedb.Snapshot()
260260
if tracer != nil && tracer.OnTxStart != nil {
261261
tracer.OnTxStart(evm.GetVMContext(), tx, msg.From)
262262
}
@@ -265,7 +265,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
265265
evm.SetTxContext(txContext)
266266
msgResult, err := core.ApplyMessage(evm, msg, gaspool)
267267
if err != nil {
268-
statedb.RevertToSnapshot(snapshot)
268+
statedb.RevertSnapshot()
269269
log.Info("rejected tx", "index", i, "hash", tx.Hash(), "from", msg.From, "error", err)
270270
rejectedTxs = append(rejectedTxs, &rejectedTx{i, err.Error()})
271271
gaspool.SetGas(prevGas)
@@ -279,7 +279,7 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
279279
}
280280
continue
281281
}
282-
statedb.DiscardSnapshot(snapshot)
282+
statedb.DiscardSnapshot()
283283
includedTxs = append(includedTxs, tx)
284284
if hashError != nil {
285285
return nil, nil, nil, NewError(ErrorMissingBlockhash, hashError)

cmd/evm/runner.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -176,8 +176,8 @@ func runCmd(ctx *cli.Context) error {
176176
sdb := state.NewDatabase(triedb, nil)
177177
statedb, _ = state.New(genesis.Root(), sdb)
178178
chainConfig = genesisConfig.Config
179-
id := statedb.Snapshot()
180-
defer statedb.DiscardSnapshot(id)
179+
statedb.Snapshot()
180+
defer statedb.DiscardSnapshot()
181181
if ctx.String(SenderFlag.Name) != "" {
182182
sender = common.HexToAddress(ctx.String(SenderFlag.Name))
183183
}

core/state/journal.go

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,23 +22,23 @@ import (
2222
)
2323

2424
type journal interface {
25-
// snapshot returns an identifier for the current revision of the state.
25+
// snapshot starts a new journal scope which can be reverted or discarded.
2626
// The lifeycle of journalling is as follows:
2727
// - snapshot() starts a 'scope'.
2828
// - The method snapshot() may be called any number of times.
2929
// - For each call to snapshot, there should be a corresponding call to end
3030
// the scope via either of:
3131
// - revertToSnapshot, which undoes the changes in the scope, or
3232
// - discardSnapshot, which discards the ability to revert the changes in the scope.
33-
snapshot() int
33+
snapshot()
3434

35-
// revertToSnapshot reverts all state changes made since the given revision.
36-
revertToSnapshot(revid int, s *StateDB)
35+
// revertSnapshot reverts all state changes made since the last call to snapshot().
36+
revertSnapshot(s *StateDB)
3737

38-
// discardSnapshot removes the snapshot with the given id; after calling this
38+
// discardSnapshot removes the latest snapshot; after calling this
3939
// method, it is no longer possible to revert to that particular snapshot, the
4040
// changes are considered part of the parent scope.
41-
discardSnapshot(revid int)
41+
discardSnapshot()
4242

4343
// reset clears the journal so it can be reused.
4444
reset()

core/state/journal_linear.go

Lines changed: 26 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,21 +17,14 @@
1717
package state
1818

1919
import (
20-
"fmt"
2120
"maps"
2221
"slices"
23-
"sort"
2422

2523
"github.com/ethereum/go-ethereum/common"
2624
"github.com/ethereum/go-ethereum/core/types"
2725
"github.com/holiman/uint256"
2826
)
2927

30-
type revision struct {
31-
id int
32-
journalIndex int
33-
}
34-
3528
// journalEntry is a modification entry in the state change linear journal that can be
3629
// reverted on demand.
3730
type journalEntry interface {
@@ -52,8 +45,7 @@ type linearJournal struct {
5245
entries []journalEntry // Current changes tracked by the linearJournal
5346
dirties map[common.Address]int // Dirty accounts and the number of changes
5447

55-
validRevisions []revision
56-
nextRevisionId int
48+
revisions []int // sequence of indexes to points in time designating snapshots
5749
}
5850

5951
// compile-time interface check
@@ -71,9 +63,8 @@ func newLinearJournal() *linearJournal {
7163
// can be reused.
7264
func (j *linearJournal) reset() {
7365
j.entries = j.entries[:0]
74-
j.validRevisions = j.validRevisions[:0]
66+
j.revisions = j.revisions[:0]
7567
clear(j.dirties)
76-
j.nextRevisionId = 0
7768
}
7869

7970
func (j linearJournal) dirtyAccounts() []common.Address {
@@ -85,33 +76,33 @@ func (j linearJournal) dirtyAccounts() []common.Address {
8576
return dirty
8677
}
8778

88-
// snapshot returns an identifier for the current revision of the state.
89-
func (j *linearJournal) snapshot() int {
90-
id := j.nextRevisionId
91-
j.nextRevisionId++
92-
j.validRevisions = append(j.validRevisions, revision{id, j.length()})
93-
return id
79+
// snapshot starts a new journal scope which can be reverted or discarded.
80+
func (j *linearJournal) snapshot() {
81+
j.revisions = append(j.revisions, len(j.entries))
9482
}
9583

96-
func (j *linearJournal) revertToSnapshot(revid int, s *StateDB) {
97-
// Find the snapshot in the stack of valid snapshots.
98-
idx := sort.Search(len(j.validRevisions), func(i int) bool {
99-
return j.validRevisions[i].id >= revid
100-
})
101-
if idx == len(j.validRevisions) || j.validRevisions[idx].id != revid {
102-
panic(fmt.Errorf("revision id %v cannot be reverted (valid revisions: %d)", revid, len(j.validRevisions)))
103-
}
104-
snapshot := j.validRevisions[idx].journalIndex
105-
84+
// revertSnapshot reverts all state changes made since the last call to snapshot().
85+
func (j *linearJournal) revertSnapshot(s *StateDB) {
86+
id := len(j.revisions) - 1
87+
revision := j.revisions[id]
10688
// Replay the linearJournal to undo changes and remove invalidated snapshots
107-
j.revert(s, snapshot)
108-
j.validRevisions = j.validRevisions[:idx]
89+
j.revertTo(s, revision)
90+
j.revisions = j.revisions[:id]
10991
}
11092

111-
// discardSnapshot removes the snapshot with the given id; after calling this
93+
// discardSnapshot removes the latest snapshot; after calling this
11294
// method, it is no longer possible to revert to that particular snapshot, the
11395
// changes are considered part of the parent scope.
114-
func (j *linearJournal) discardSnapshot(id int) {
96+
func (j *linearJournal) discardSnapshot() {
97+
id := len(j.revisions) - 1
98+
if id == 0 {
99+
// If a transaction is applied successfully, the statedb.Finalize will
100+
// end by clearing and resetting the journal. Invoking a discardSnapshot
101+
// afterwards will land here: calling discard on an empty journal.
102+
// This is fine
103+
return
104+
}
105+
j.revisions = j.revisions[:id]
115106
}
116107

117108
// append inserts a new modification entry to the end of the change linearJournal.
@@ -124,7 +115,7 @@ func (j *linearJournal) append(entry journalEntry) {
124115

125116
// revert undoes a batch of journalled modifications along with any reverted
126117
// dirty handling too.
127-
func (j *linearJournal) revert(statedb *StateDB, snapshot int) {
118+
func (j *linearJournal) revertTo(statedb *StateDB, snapshot int) {
128119
for i := len(j.entries) - 1; i >= snapshot; i-- {
129120
// Undo the changes made by the operation
130121
j.entries[i].revert(statedb)
@@ -158,10 +149,9 @@ func (j *linearJournal) copy() journal {
158149
entries = append(entries, j.entries[i].copy())
159150
}
160151
return &linearJournal{
161-
entries: entries,
162-
dirties: maps.Clone(j.dirties),
163-
validRevisions: slices.Clone(j.validRevisions),
164-
nextRevisionId: j.nextRevisionId,
152+
entries: entries,
153+
dirties: maps.Clone(j.dirties),
154+
revisions: slices.Clone(j.revisions),
165155
}
166156
}
167157

core/state/journal_set.go

Lines changed: 14 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,11 @@ package state
1818

1919
import (
2020
"bytes"
21-
"fmt"
2221
"maps"
2322
"slices"
2423

2524
"github.com/ethereum/go-ethereum/common"
2625
"github.com/ethereum/go-ethereum/core/types"
27-
"github.com/ethereum/go-ethereum/log"
2826
"github.com/holiman/uint256"
2927
)
3028

@@ -349,51 +347,34 @@ func (j *sparseJournal) copy() journal {
349347
return cp
350348
}
351349

352-
// snapshot returns an identifier for the current revision of the state.
350+
// snapshot starts a new journal scope which can be reverted or discarded.
353351
// OBS: A call to Snapshot is _required_ in order to initialize the journalling,
354352
// invoking the journal-methods without having invoked Snapshot will lead to
355353
// panic.
356-
func (j *sparseJournal) snapshot() int {
357-
id := len(j.entries)
354+
func (j *sparseJournal) snapshot() {
358355
j.entries = append(j.entries, newScopedJournal())
359-
return id
360356
}
361357

362-
// revertToSnapshot reverts all state changes made since the given revision.
363-
func (j *sparseJournal) revertToSnapshot(id int, s *StateDB) {
364-
if id >= len(j.entries) {
365-
panic(fmt.Errorf("revision id %v cannot be reverted", id))
366-
}
367-
// Revert the entries sequentially
368-
for i := len(j.entries) - 1; i >= id; i-- {
369-
entry := j.entries[i]
370-
entry.revert(s)
371-
}
358+
// revertSnapshot reverts all state changes made since the last call to snapshot().
359+
func (j *sparseJournal) revertSnapshot(s *StateDB) {
360+
id := len(j.entries) - 1
361+
j.entries[id].revert(s)
372362
j.entries = j.entries[:id]
373363
}
374364

375-
// discardSnapshot removes the snapshot with the given id; after calling this
365+
// discardSnapshot removes the latest snapshot; after calling this
376366
// method, it is no longer possible to revert to that particular snapshot, the
377367
// changes are considered part of the parent scope.
378-
func (j *sparseJournal) discardSnapshot(id int) {
368+
func (j *sparseJournal) discardSnapshot() {
369+
id := len(j.entries) - 1
370+
// here we must merge the 'id' with it's parent.
379371
if id == 0 {
372+
// If a transaction is applied successfully, the statedb.Finalize will
373+
// end by clearing and resetting the journal. Invoking a discardSnapshot
374+
// afterwards will land here: calling discard on an empty journal.
375+
// This is fine
380376
return
381377
}
382-
// here we must merge the 'id' with it's parent.
383-
want := len(j.entries) - 1
384-
have := id
385-
if want != have {
386-
if want == 0 && id == 1 {
387-
// If a transcation is applied successfully, the statedb.Finalize will
388-
// end by clearing and resetting the journal. Invoking a discardSnapshot
389-
// afterwards will lead us here.
390-
// Let's not panic, but it's ok to complain a bit
391-
log.Error("Extraneous invocation to discard snapshot")
392-
return
393-
} else {
394-
panic(fmt.Sprintf("journalling error, want discard(%d), have discard(%d)", want, have))
395-
}
396-
}
397378
entry := j.entries[id]
398379
parent := j.entries[id-1]
399380
entry.merge(parent)

core/state/journal_test.go

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -75,23 +75,23 @@ func testJournalAccessList(t *testing.T, j journal) {
7575
statedb.accessList = newAccessList()
7676
statedb.journal = j
7777

78+
j.snapshot()
7879
{
7980
// If the journal performs the rollback in the wrong order, this
8081
// will cause a panic.
81-
id := j.snapshot()
8282
statedb.AddSlotToAccessList(common.Address{0x1}, common.Hash{0x4})
8383
statedb.AddSlotToAccessList(common.Address{0x3}, common.Hash{0x4})
84-
statedb.RevertToSnapshot(id)
8584
}
85+
statedb.RevertSnapshot()
86+
j.snapshot()
8687
{
87-
id := j.snapshot()
8888
statedb.AddAddressToAccessList(common.Address{0x2})
8989
statedb.AddAddressToAccessList(common.Address{0x3})
9090
statedb.AddAddressToAccessList(common.Address{0x4})
91-
statedb.RevertToSnapshot(id)
92-
if statedb.accessList.ContainsAddress(common.Address{0x2}) {
93-
t.Fatal("should be missing")
94-
}
91+
}
92+
statedb.RevertSnapshot()
93+
if statedb.accessList.ContainsAddress(common.Address{0x2}) {
94+
t.Fatal("should be missing")
9595
}
9696
}
9797

@@ -107,25 +107,27 @@ func testJournalRefunds(t *testing.T, j journal) {
107107
var statedb = &StateDB{}
108108
statedb.accessList = newAccessList()
109109
statedb.journal = j
110-
zero := j.snapshot()
111-
j.refundChange(0)
112-
j.refundChange(1)
110+
j.snapshot()
113111
{
114-
id := j.snapshot()
115-
j.refundChange(2)
116-
j.refundChange(3)
117-
j.revertToSnapshot(id, statedb)
112+
j.refundChange(0)
113+
j.refundChange(1)
114+
j.snapshot()
115+
{
116+
j.refundChange(2)
117+
j.refundChange(3)
118+
}
119+
j.revertSnapshot(statedb)
118120
if have, want := statedb.refund, uint64(2); have != want {
119121
t.Fatalf("have %d want %d", have, want)
120122
}
123+
j.snapshot()
124+
{
125+
j.refundChange(2)
126+
j.refundChange(3)
127+
}
128+
j.discardSnapshot()
121129
}
122-
{
123-
id := j.snapshot()
124-
j.refundChange(2)
125-
j.refundChange(3)
126-
j.discardSnapshot(id)
127-
}
128-
j.revertToSnapshot(zero, statedb)
130+
j.revertSnapshot(statedb)
129131
if have, want := statedb.refund, uint64(0); have != want {
130132
t.Fatalf("have %d want %d", have, want)
131133
}

0 commit comments

Comments
 (0)