mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 02:12:23 +00:00
core/state: move revision-handling into journal
This commit is contained in:
parent
137fdb7fe2
commit
36e875a361
2 changed files with 49 additions and 32 deletions
|
|
@ -17,13 +17,20 @@
|
|||
package state
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"maps"
|
||||
"sort"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
type revision struct {
|
||||
id int
|
||||
journalIndex int
|
||||
}
|
||||
|
||||
// journalEntry is a modification entry in the state change journal that can be
|
||||
// reverted on demand.
|
||||
type journalEntry interface {
|
||||
|
|
@ -43,6 +50,9 @@ type journalEntry interface {
|
|||
type journal struct {
|
||||
entries []journalEntry // Current changes tracked by the journal
|
||||
dirties map[common.Address]int // Dirty accounts and the number of changes
|
||||
|
||||
validRevisions []revision
|
||||
nextRevisionId int
|
||||
}
|
||||
|
||||
// newJournal creates a new initialized journal.
|
||||
|
|
@ -52,6 +62,40 @@ func newJournal() *journal {
|
|||
}
|
||||
}
|
||||
|
||||
// Reset clears the journal, after this operation the journal can be used
|
||||
// anew. It is semantically similar to calling 'newJournal', but the underlying
|
||||
// slices can be reused
|
||||
func (j *journal) Reset() {
|
||||
j.entries = j.entries[:0]
|
||||
j.validRevisions = j.validRevisions[:0]
|
||||
j.dirties = make(map[common.Address]int)
|
||||
j.nextRevisionId = 0
|
||||
}
|
||||
|
||||
// Snapshot returns an identifier for the current revision of the state.
|
||||
func (j *journal) Snapshot() int {
|
||||
id := j.nextRevisionId
|
||||
j.nextRevisionId++
|
||||
j.validRevisions = append(j.validRevisions, revision{id, j.length()})
|
||||
return id
|
||||
}
|
||||
|
||||
// RevertToSnapshot reverts all state changes made since the given revision.
|
||||
func (j *journal) RevertToSnapshot(revid int, s *StateDB) {
|
||||
// Find the snapshot in the stack of valid snapshots.
|
||||
idx := sort.Search(len(j.validRevisions), func(i int) bool {
|
||||
return j.validRevisions[i].id >= revid
|
||||
})
|
||||
if idx == len(j.validRevisions) || j.validRevisions[idx].id != revid {
|
||||
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
|
||||
}
|
||||
snapshot := j.validRevisions[idx].journalIndex
|
||||
|
||||
// Replay the journal to undo changes and remove invalidated snapshots
|
||||
j.revert(s, snapshot)
|
||||
j.validRevisions = j.validRevisions[:idx]
|
||||
}
|
||||
|
||||
// append inserts a new modification entry to the end of the change journal.
|
||||
func (j *journal) append(entry journalEntry) {
|
||||
j.entries = append(j.entries, entry)
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import (
|
|||
"maps"
|
||||
"math/big"
|
||||
"slices"
|
||||
"sort"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"time"
|
||||
|
|
@ -48,11 +47,6 @@ import (
|
|||
// TriesInMemory represents the number of layers that are kept in RAM.
|
||||
const TriesInMemory = 128
|
||||
|
||||
type revision struct {
|
||||
id int
|
||||
journalIndex int
|
||||
}
|
||||
|
||||
type mutationType int
|
||||
|
||||
const (
|
||||
|
|
@ -144,8 +138,6 @@ type StateDB struct {
|
|||
// Journal of state modifications. This is the backbone of
|
||||
// Snapshot and RevertToSnapshot.
|
||||
journal *journal
|
||||
validRevisions []revision
|
||||
nextRevisionId int
|
||||
|
||||
// State witness if cross validation is needed
|
||||
witness *stateless.Witness
|
||||
|
|
@ -703,8 +695,6 @@ func (s *StateDB) Copy() *StateDB {
|
|||
logSize: s.logSize,
|
||||
preimages: maps.Clone(s.preimages),
|
||||
journal: s.journal.copy(),
|
||||
validRevisions: slices.Clone(s.validRevisions),
|
||||
nextRevisionId: s.nextRevisionId,
|
||||
|
||||
// In order for the block producer to be able to use and make additions
|
||||
// to the snapshot tree, we need to copy that as well. Otherwise, any
|
||||
|
|
@ -750,26 +740,12 @@ func (s *StateDB) Copy() *StateDB {
|
|||
|
||||
// Snapshot returns an identifier for the current revision of the state.
|
||||
func (s *StateDB) Snapshot() int {
|
||||
id := s.nextRevisionId
|
||||
s.nextRevisionId++
|
||||
s.validRevisions = append(s.validRevisions, revision{id, s.journal.length()})
|
||||
return id
|
||||
return s.journal.Snapshot()
|
||||
}
|
||||
|
||||
// RevertToSnapshot reverts all state changes made since the given revision.
|
||||
func (s *StateDB) RevertToSnapshot(revid int) {
|
||||
// Find the snapshot in the stack of valid snapshots.
|
||||
idx := sort.Search(len(s.validRevisions), func(i int) bool {
|
||||
return s.validRevisions[i].id >= revid
|
||||
})
|
||||
if idx == len(s.validRevisions) || s.validRevisions[idx].id != revid {
|
||||
panic(fmt.Errorf("revision id %v cannot be reverted", revid))
|
||||
}
|
||||
snapshot := s.validRevisions[idx].journalIndex
|
||||
|
||||
// Replay the journal to undo changes and remove invalidated snapshots
|
||||
s.journal.revert(s, snapshot)
|
||||
s.validRevisions = s.validRevisions[:idx]
|
||||
s.journal.RevertToSnapshot(revid, s)
|
||||
}
|
||||
|
||||
// GetRefund returns the current value of the refund counter.
|
||||
|
|
@ -983,11 +959,8 @@ func (s *StateDB) SetTxContext(thash common.Hash, ti int) {
|
|||
}
|
||||
|
||||
func (s *StateDB) clearJournalAndRefund() {
|
||||
if len(s.journal.entries) > 0 {
|
||||
s.journal = newJournal()
|
||||
s.journal.Reset()
|
||||
s.refund = 0
|
||||
}
|
||||
s.validRevisions = s.validRevisions[:0] // Snapshots can be created without journal entries
|
||||
}
|
||||
|
||||
// fastDeleteStorage is the function that efficiently deletes the storage trie
|
||||
|
|
|
|||
Loading…
Reference in a new issue