mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 10:22: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
|
package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"maps"
|
"maps"
|
||||||
|
"sort"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type revision struct {
|
||||||
|
id int
|
||||||
|
journalIndex int
|
||||||
|
}
|
||||||
|
|
||||||
// journalEntry is a modification entry in the state change journal that can be
|
// journalEntry is a modification entry in the state change journal that can be
|
||||||
// reverted on demand.
|
// reverted on demand.
|
||||||
type journalEntry interface {
|
type journalEntry interface {
|
||||||
|
|
@ -43,6 +50,9 @@ type journalEntry interface {
|
||||||
type journal struct {
|
type journal struct {
|
||||||
entries []journalEntry // Current changes tracked by the journal
|
entries []journalEntry // Current changes tracked by the journal
|
||||||
dirties map[common.Address]int // Dirty accounts and the number of changes
|
dirties map[common.Address]int // Dirty accounts and the number of changes
|
||||||
|
|
||||||
|
validRevisions []revision
|
||||||
|
nextRevisionId int
|
||||||
}
|
}
|
||||||
|
|
||||||
// newJournal creates a new initialized journal.
|
// 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.
|
// append inserts a new modification entry to the end of the change journal.
|
||||||
func (j *journal) append(entry journalEntry) {
|
func (j *journal) append(entry journalEntry) {
|
||||||
j.entries = append(j.entries, entry)
|
j.entries = append(j.entries, entry)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ import (
|
||||||
"maps"
|
"maps"
|
||||||
"math/big"
|
"math/big"
|
||||||
"slices"
|
"slices"
|
||||||
"sort"
|
|
||||||
"sync"
|
"sync"
|
||||||
"sync/atomic"
|
"sync/atomic"
|
||||||
"time"
|
"time"
|
||||||
|
|
@ -48,11 +47,6 @@ import (
|
||||||
// TriesInMemory represents the number of layers that are kept in RAM.
|
// TriesInMemory represents the number of layers that are kept in RAM.
|
||||||
const TriesInMemory = 128
|
const TriesInMemory = 128
|
||||||
|
|
||||||
type revision struct {
|
|
||||||
id int
|
|
||||||
journalIndex int
|
|
||||||
}
|
|
||||||
|
|
||||||
type mutationType int
|
type mutationType int
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
|
@ -144,8 +138,6 @@ type StateDB struct {
|
||||||
// Journal of state modifications. This is the backbone of
|
// Journal of state modifications. This is the backbone of
|
||||||
// Snapshot and RevertToSnapshot.
|
// Snapshot and RevertToSnapshot.
|
||||||
journal *journal
|
journal *journal
|
||||||
validRevisions []revision
|
|
||||||
nextRevisionId int
|
|
||||||
|
|
||||||
// State witness if cross validation is needed
|
// State witness if cross validation is needed
|
||||||
witness *stateless.Witness
|
witness *stateless.Witness
|
||||||
|
|
@ -703,8 +695,6 @@ func (s *StateDB) Copy() *StateDB {
|
||||||
logSize: s.logSize,
|
logSize: s.logSize,
|
||||||
preimages: maps.Clone(s.preimages),
|
preimages: maps.Clone(s.preimages),
|
||||||
journal: s.journal.copy(),
|
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
|
// 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
|
// 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.
|
// Snapshot returns an identifier for the current revision of the state.
|
||||||
func (s *StateDB) Snapshot() int {
|
func (s *StateDB) Snapshot() int {
|
||||||
id := s.nextRevisionId
|
return s.journal.Snapshot()
|
||||||
s.nextRevisionId++
|
|
||||||
s.validRevisions = append(s.validRevisions, revision{id, s.journal.length()})
|
|
||||||
return id
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RevertToSnapshot reverts all state changes made since the given revision.
|
// RevertToSnapshot reverts all state changes made since the given revision.
|
||||||
func (s *StateDB) RevertToSnapshot(revid int) {
|
func (s *StateDB) RevertToSnapshot(revid int) {
|
||||||
// Find the snapshot in the stack of valid snapshots.
|
s.journal.RevertToSnapshot(revid, s)
|
||||||
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]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetRefund returns the current value of the refund counter.
|
// GetRefund returns the current value of the refund counter.
|
||||||
|
|
@ -983,12 +959,9 @@ func (s *StateDB) SetTxContext(thash common.Hash, ti int) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) clearJournalAndRefund() {
|
func (s *StateDB) clearJournalAndRefund() {
|
||||||
if len(s.journal.entries) > 0 {
|
s.journal.Reset()
|
||||||
s.journal = newJournal()
|
|
||||||
s.refund = 0
|
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
|
// fastDeleteStorage is the function that efficiently deletes the storage trie
|
||||||
// of a specific account. It leverages the associated state snapshot for fast
|
// of a specific account. It leverages the associated state snapshot for fast
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue