Skip to content

Commit 36e875a

Browse files
committed
core/state: move revision-handling into journal
1 parent 137fdb7 commit 36e875a

File tree

2 files changed

+49
-32
lines changed

2 files changed

+49
-32
lines changed

core/state/journal.go

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,20 @@
1717
package state
1818

1919
import (
20+
"fmt"
2021
"maps"
22+
"sort"
2123

2224
"github.com/ethereum/go-ethereum/common"
2325
"github.com/ethereum/go-ethereum/core/types"
2426
"github.com/holiman/uint256"
2527
)
2628

29+
type revision struct {
30+
id int
31+
journalIndex int
32+
}
33+
2734
// journalEntry is a modification entry in the state change journal that can be
2835
// reverted on demand.
2936
type journalEntry interface {
@@ -43,6 +50,9 @@ type journalEntry interface {
4350
type journal struct {
4451
entries []journalEntry // Current changes tracked by the journal
4552
dirties map[common.Address]int // Dirty accounts and the number of changes
53+
54+
validRevisions []revision
55+
nextRevisionId int
4656
}
4757

4858
// newJournal creates a new initialized journal.
@@ -52,6 +62,40 @@ func newJournal() *journal {
5262
}
5363
}
5464

65+
// Reset clears the journal, after this operation the journal can be used
66+
// anew. It is semantically similar to calling 'newJournal', but the underlying
67+
// slices can be reused
68+
func (j *journal) Reset() {
69+
j.entries = j.entries[:0]
70+
j.validRevisions = j.validRevisions[:0]
71+
j.dirties = make(map[common.Address]int)
72+
j.nextRevisionId = 0
73+
}
74+
75+
// Snapshot returns an identifier for the current revision of the state.
76+
func (j *journal) Snapshot() int {
77+
id := j.nextRevisionId
78+
j.nextRevisionId++
79+
j.validRevisions = append(j.validRevisions, revision{id, j.length()})
80+
return id
81+
}
82+
83+
// RevertToSnapshot reverts all state changes made since the given revision.
84+
func (j *journal) RevertToSnapshot(revid int, s *StateDB) {
85+
// Find the snapshot in the stack of valid snapshots.
86+
idx := sort.Search(len(j.validRevisions), func(i int) bool {
87+
return j.validRevisions[i].id >= revid
88+
})
89+
if idx == len(j.validRevisions) || j.validRevisions[idx].id != revid {
90+
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
91+
}
92+
snapshot := j.validRevisions[idx].journalIndex
93+
94+
// Replay the journal to undo changes and remove invalidated snapshots
95+
j.revert(s, snapshot)
96+
j.validRevisions = j.validRevisions[:idx]
97+
}
98+
5599
// append inserts a new modification entry to the end of the change journal.
56100
func (j *journal) append(entry journalEntry) {
57101
j.entries = append(j.entries, entry)

core/state/statedb.go

Lines changed: 5 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import (
2323
"maps"
2424
"math/big"
2525
"slices"
26-
"sort"
2726
"sync"
2827
"sync/atomic"
2928
"time"
@@ -48,11 +47,6 @@ import (
4847
// TriesInMemory represents the number of layers that are kept in RAM.
4948
const TriesInMemory = 128
5049

51-
type revision struct {
52-
id int
53-
journalIndex int
54-
}
55-
5650
type mutationType int
5751

5852
const (
@@ -143,9 +137,7 @@ type StateDB struct {
143137

144138
// Journal of state modifications. This is the backbone of
145139
// Snapshot and RevertToSnapshot.
146-
journal *journal
147-
validRevisions []revision
148-
nextRevisionId int
140+
journal *journal
149141

150142
// State witness if cross validation is needed
151143
witness *stateless.Witness
@@ -703,8 +695,6 @@ func (s *StateDB) Copy() *StateDB {
703695
logSize: s.logSize,
704696
preimages: maps.Clone(s.preimages),
705697
journal: s.journal.copy(),
706-
validRevisions: slices.Clone(s.validRevisions),
707-
nextRevisionId: s.nextRevisionId,
708698

709699
// In order for the block producer to be able to use and make additions
710700
// to the snapshot tree, we need to copy that as well. Otherwise, any
@@ -750,26 +740,12 @@ func (s *StateDB) Copy() *StateDB {
750740

751741
// Snapshot returns an identifier for the current revision of the state.
752742
func (s *StateDB) Snapshot() int {
753-
id := s.nextRevisionId
754-
s.nextRevisionId++
755-
s.validRevisions = append(s.validRevisions, revision{id, s.journal.length()})
756-
return id
743+
return s.journal.Snapshot()
757744
}
758745

759746
// RevertToSnapshot reverts all state changes made since the given revision.
760747
func (s *StateDB) RevertToSnapshot(revid int) {
761-
// Find the snapshot in the stack of valid snapshots.
762-
idx := sort.Search(len(s.validRevisions), func(i int) bool {
763-
return s.validRevisions[i].id >= revid
764-
})
765-
if idx == len(s.validRevisions) || s.validRevisions[idx].id != revid {
766-
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
767-
}
768-
snapshot := s.validRevisions[idx].journalIndex
769-
770-
// Replay the journal to undo changes and remove invalidated snapshots
771-
s.journal.revert(s, snapshot)
772-
s.validRevisions = s.validRevisions[:idx]
748+
s.journal.RevertToSnapshot(revid, s)
773749
}
774750

775751
// GetRefund returns the current value of the refund counter.
@@ -983,11 +959,8 @@ func (s *StateDB) SetTxContext(thash common.Hash, ti int) {
983959
}
984960

985961
func (s *StateDB) clearJournalAndRefund() {
986-
if len(s.journal.entries) > 0 {
987-
s.journal = newJournal()
988-
s.refund = 0
989-
}
990-
s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entries
962+
s.journal.Reset()
963+
s.refund = 0
991964
}
992965

993966
// fastDeleteStorage is the function that efficiently deletes the storage trie

0 commit comments

Comments
 (0)