Skip to content

Commit 2ccd040

Browse files
committed
core/state: move revision-handling into journal
1 parent fc340e5 commit 2ccd040

File tree

2 files changed

+50
-30
lines changed

2 files changed

+50
-30
lines changed

core/state/journal.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,19 @@
1717
package state
1818

1919
import (
20+
"fmt"
21+
"sort"
22+
2023
"github.com/ethereum/go-ethereum/common"
2124
"github.com/ethereum/go-ethereum/core/types"
2225
"github.com/holiman/uint256"
2326
)
2427

28+
type revision struct {
29+
id int
30+
journalIndex int
31+
}
32+
2533
// journalEntry is a modification entry in the state change journal that can be
2634
// reverted on demand.
2735
type journalEntry interface {
@@ -38,6 +46,9 @@ type journalEntry interface {
3846
type journal struct {
3947
entries []journalEntry // Current changes tracked by the journal
4048
dirties map[common.Address]int // Dirty accounts and the number of changes
49+
50+
validRevisions []revision
51+
nextRevisionId int
4152
}
4253

4354
// newJournal creates a new initialized journal.
@@ -47,6 +58,40 @@ func newJournal() *journal {
4758
}
4859
}
4960

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

core/state/statedb.go

Lines changed: 5 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ package state
1919

2020
import (
2121
"fmt"
22-
"sort"
2322
"time"
2423

2524
"github.com/ethereum/go-ethereum/common"
@@ -42,11 +41,6 @@ const (
4241
storageDeleteLimit = 512 * 1024 * 1024
4342
)
4443

45-
type revision struct {
46-
id int
47-
journalIndex int
48-
}
49-
5044
// StateDB structs within the ethereum protocol are used to store anything
5145
// within the merkle trie. StateDBs take care of caching and storing
5246
// nested states. It's the general query interface to retrieve:
@@ -113,9 +107,7 @@ type StateDB struct {
113107

114108
// Journal of state modifications. This is the backbone of
115109
// Snapshot and RevertToSnapshot.
116-
journal *journal
117-
validRevisions []revision
118-
nextRevisionId int
110+
journal *journal
119111

120112
// Measurements gathered during execution for debugging purposes
121113
AccountReads time.Duration
@@ -774,26 +766,12 @@ func (s *StateDB) Copy() *StateDB {
774766

775767
// Snapshot returns an identifier for the current revision of the state.
776768
func (s *StateDB) Snapshot() int {
777-
id := s.nextRevisionId
778-
s.nextRevisionId++
779-
s.validRevisions = append(s.validRevisions, revision{id, s.journal.length()})
780-
return id
769+
return s.journal.Snapshot()
781770
}
782771

783772
// RevertToSnapshot reverts all state changes made since the given revision.
784773
func (s *StateDB) RevertToSnapshot(revid int) {
785-
// Find the snapshot in the stack of valid snapshots.
786-
idx := sort.Search(len(s.validRevisions), func(i int) bool {
787-
return s.validRevisions[i].id >= revid
788-
})
789-
if idx == len(s.validRevisions) || s.validRevisions[idx].id != revid {
790-
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
791-
}
792-
snapshot := s.validRevisions[idx].journalIndex
793-
794-
// Replay the journal to undo changes and remove invalidated snapshots
795-
s.journal.revert(s, snapshot)
796-
s.validRevisions = s.validRevisions[:idx]
774+
s.journal.RevertToSnapshot(revid, s)
797775
}
798776

799777
// GetRefund returns the current value of the refund counter.
@@ -924,11 +902,8 @@ func (s *StateDB) SetTxContext(thash common.Hash, ti int) {
924902
}
925903

926904
func (s *StateDB) clearJournalAndRefund() {
927-
if len(s.journal.entries) > 0 {
928-
s.journal = newJournal()
929-
s.refund = 0
930-
}
931-
s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entries
905+
s.journal.Reset()
906+
s.refund = 0
932907
}
933908

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

0 commit comments

Comments
 (0)