mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-12 01:41:36 +00:00
core/state: remove trie prefetcher and witness from stateDB
This commit is contained in:
parent
e2c00d6c96
commit
9daaef1923
3 changed files with 18 additions and 208 deletions
|
|
@ -119,11 +119,6 @@ func (s *stateObject) addrHash() common.Hash {
|
||||||
return *s.addressHash
|
return *s.addressHash
|
||||||
}
|
}
|
||||||
|
|
||||||
// storageTrieID returns the unique identifier for this account's storage trie.
|
|
||||||
func (s *stateObject) storageTrieID() trie.ID {
|
|
||||||
return *trie.StorageTrieID(s.db.originalRoot, s.addrHash(), s.data.Root)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *stateObject) markSelfdestructed() {
|
func (s *stateObject) markSelfdestructed() {
|
||||||
s.selfDestructed = true
|
s.selfDestructed = true
|
||||||
}
|
}
|
||||||
|
|
@ -149,23 +144,6 @@ func (s *stateObject) getTrie() (Trie, error) {
|
||||||
return s.trie, nil
|
return s.trie, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// getPrefetchedTrie returns the associated trie, as populated by the prefetcher
|
|
||||||
// if it's available.
|
|
||||||
//
|
|
||||||
// Note, opposed to getTrie, this method will *NOT* blindly cache the resulting
|
|
||||||
// trie in the state object. The caller might want to do that, but it's cleaner
|
|
||||||
// to break the hidden interdependency between retrieving tries from the db or
|
|
||||||
// from the prefetcher.
|
|
||||||
func (s *stateObject) getPrefetchedTrie() Trie {
|
|
||||||
// If there's nothing to meaningfully return, let the user figure it out by
|
|
||||||
// pulling the trie from disk.
|
|
||||||
if (s.data.Root == types.EmptyRootHash && !s.db.db.TrieDB().IsVerkle()) || s.db.prefetcher == nil {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
// Attempt to retrieve the trie from the prefetcher
|
|
||||||
return s.db.prefetcher.trie(s.storageTrieID())
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetState retrieves a value associated with the given storage key.
|
// GetState retrieves a value associated with the given storage key.
|
||||||
func (s *stateObject) GetState(key common.Hash) common.Hash {
|
func (s *stateObject) GetState(key common.Hash) common.Hash {
|
||||||
value, _ := s.getState(key)
|
value, _ := s.getState(key)
|
||||||
|
|
@ -226,12 +204,6 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
|
||||||
}
|
}
|
||||||
s.db.StorageReads += time.Since(start)
|
s.db.StorageReads += time.Since(start)
|
||||||
|
|
||||||
// Schedule the resolved storage slots for prefetching if it's enabled.
|
|
||||||
if s.db.prefetcher != nil && s.data.Root != types.EmptyRootHash {
|
|
||||||
if err = s.db.prefetcher.prefetchStorage(s.storageTrieID(), s.address, []common.Hash{key}, true); err != nil {
|
|
||||||
log.Error("Failed to prefetch storage slot", "addr", s.address, "key", key, "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s.originStorage[key] = value
|
s.originStorage[key] = value
|
||||||
return value
|
return value
|
||||||
}
|
}
|
||||||
|
|
@ -265,7 +237,6 @@ func (s *stateObject) setState(key common.Hash, value common.Hash, origin common
|
||||||
// finalise moves all dirty storage slots into the pending area to be hashed or
|
// finalise moves all dirty storage slots into the pending area to be hashed or
|
||||||
// committed later. It is invoked at the end of every transaction.
|
// committed later. It is invoked at the end of every transaction.
|
||||||
func (s *stateObject) finalise() {
|
func (s *stateObject) finalise() {
|
||||||
slotsToPrefetch := make([]common.Hash, 0, len(s.dirtyStorage))
|
|
||||||
for key, value := range s.dirtyStorage {
|
for key, value := range s.dirtyStorage {
|
||||||
if origin, exist := s.uncommittedStorage[key]; exist && origin == value {
|
if origin, exist := s.uncommittedStorage[key]; exist && origin == value {
|
||||||
// The slot is reverted to its original value, delete the entry
|
// The slot is reverted to its original value, delete the entry
|
||||||
|
|
@ -278,7 +249,6 @@ func (s *stateObject) finalise() {
|
||||||
// The slot is different from its original value and hasn't been
|
// The slot is different from its original value and hasn't been
|
||||||
// tracked for commit yet.
|
// tracked for commit yet.
|
||||||
s.uncommittedStorage[key] = s.GetCommittedState(key)
|
s.uncommittedStorage[key] = s.GetCommittedState(key)
|
||||||
slotsToPrefetch = append(slotsToPrefetch, key) // Copy needed for closure
|
|
||||||
}
|
}
|
||||||
// Aggregate the dirty storage slots into the pending area. It might
|
// Aggregate the dirty storage slots into the pending area. It might
|
||||||
// be possible that the value of tracked slot here is same with the
|
// be possible that the value of tracked slot here is same with the
|
||||||
|
|
@ -288,11 +258,6 @@ func (s *stateObject) finalise() {
|
||||||
// byzantium fork) and entry is necessary to modify the value back.
|
// byzantium fork) and entry is necessary to modify the value back.
|
||||||
s.pendingStorage[key] = value
|
s.pendingStorage[key] = value
|
||||||
}
|
}
|
||||||
if s.db.prefetcher != nil && len(slotsToPrefetch) > 0 && s.data.Root != types.EmptyRootHash {
|
|
||||||
if err := s.db.prefetcher.prefetchStorage(s.storageTrieID(), s.address, slotsToPrefetch, false); err != nil {
|
|
||||||
log.Error("Failed to prefetch slots", "addr", s.address, "slots", len(slotsToPrefetch), "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if len(s.dirtyStorage) > 0 {
|
if len(s.dirtyStorage) > 0 {
|
||||||
s.dirtyStorage = make(Storage)
|
s.dirtyStorage = make(Storage)
|
||||||
}
|
}
|
||||||
|
|
@ -311,34 +276,16 @@ func (s *stateObject) finalise() {
|
||||||
//
|
//
|
||||||
// It assumes all the dirty storage slots have been finalized before.
|
// It assumes all the dirty storage slots have been finalized before.
|
||||||
func (s *stateObject) updateTrie() (Trie, error) {
|
func (s *stateObject) updateTrie() (Trie, error) {
|
||||||
// Short circuit if nothing was accessed, don't trigger a prefetcher warning
|
// Short circuit if nothing was accessed
|
||||||
if len(s.uncommittedStorage) == 0 {
|
|
||||||
// Nothing was written, so we could stop early. Unless we have both reads
|
|
||||||
// and witness collection enabled, in which case we need to fetch the trie.
|
|
||||||
if s.db.witness == nil || len(s.originStorage) == 0 {
|
|
||||||
return s.trie, nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Retrieve a pretecher populated trie, or fall back to the database. This will
|
|
||||||
// block until all prefetch tasks are done, which are needed for witnesses even
|
|
||||||
// for unmodified state objects.
|
|
||||||
tr := s.getPrefetchedTrie()
|
|
||||||
if tr != nil {
|
|
||||||
// Prefetcher returned a live trie, swap it out for the current one
|
|
||||||
s.trie = tr
|
|
||||||
} else {
|
|
||||||
// Fetcher not running or empty trie, fallback to the database trie
|
|
||||||
var err error
|
|
||||||
tr, err = s.getTrie()
|
|
||||||
if err != nil {
|
|
||||||
s.db.setError(err)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Short circuit if nothing changed, don't bother with hashing anything
|
|
||||||
if len(s.uncommittedStorage) == 0 {
|
if len(s.uncommittedStorage) == 0 {
|
||||||
return s.trie, nil
|
return s.trie, nil
|
||||||
}
|
}
|
||||||
|
// Fetcher not running or empty trie, fallback to the database trie
|
||||||
|
tr, err := s.getTrie()
|
||||||
|
if err != nil {
|
||||||
|
s.db.setError(err)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
// Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes
|
// Perform trie updates before deletions. This prevents resolution of unnecessary trie nodes
|
||||||
// in circumstances similar to the following:
|
// in circumstances similar to the following:
|
||||||
//
|
//
|
||||||
|
|
@ -351,7 +298,6 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
||||||
// Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved.
|
// Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved.
|
||||||
var (
|
var (
|
||||||
deletions []common.Hash
|
deletions []common.Hash
|
||||||
used = make([]common.Hash, 0, len(s.uncommittedStorage))
|
|
||||||
)
|
)
|
||||||
for key, origin := range s.uncommittedStorage {
|
for key, origin := range s.uncommittedStorage {
|
||||||
// Skip noop changes, persist actual changes
|
// Skip noop changes, persist actual changes
|
||||||
|
|
@ -373,8 +319,6 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
||||||
} else {
|
} else {
|
||||||
deletions = append(deletions, key)
|
deletions = append(deletions, key)
|
||||||
}
|
}
|
||||||
// Cache the items for preloading
|
|
||||||
used = append(used, key) // Copy needed for closure
|
|
||||||
}
|
}
|
||||||
for _, key := range deletions {
|
for _, key := range deletions {
|
||||||
if err := tr.DeleteStorage(s.address, key[:]); err != nil {
|
if err := tr.DeleteStorage(s.address, key[:]); err != nil {
|
||||||
|
|
@ -383,9 +327,6 @@ func (s *stateObject) updateTrie() (Trie, error) {
|
||||||
}
|
}
|
||||||
s.db.StorageDeleted.Add(1)
|
s.db.StorageDeleted.Add(1)
|
||||||
}
|
}
|
||||||
if s.db.prefetcher != nil {
|
|
||||||
s.db.prefetcher.used(s.storageTrieID(), nil, used)
|
|
||||||
}
|
|
||||||
s.uncommittedStorage = make(Storage) // empties the commit markers
|
s.uncommittedStorage = make(Storage) // empties the commit markers
|
||||||
return tr, nil
|
return tr, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,6 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/core/tracing"
|
"github.com/ethereum/go-ethereum/core/tracing"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
"github.com/ethereum/go-ethereum/log"
|
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
"github.com/ethereum/go-ethereum/trie/trienode"
|
"github.com/ethereum/go-ethereum/trie/trienode"
|
||||||
|
|
@ -75,10 +74,9 @@ func (m *mutation) isDelete() bool {
|
||||||
// must be created with new root and updated database for accessing post-
|
// must be created with new root and updated database for accessing post-
|
||||||
// commit states.
|
// commit states.
|
||||||
type StateDB struct {
|
type StateDB struct {
|
||||||
db Database
|
db Database
|
||||||
prefetcher *triePrefetcher
|
reader Reader
|
||||||
reader Reader
|
trie Trie // it's resolved on first access
|
||||||
trie Trie // it's resolved on first access
|
|
||||||
|
|
||||||
// originalRoot is the pre-state root, before any changes were made.
|
// originalRoot is the pre-state root, before any changes were made.
|
||||||
// It will be updated when the Commit is called.
|
// It will be updated when the Commit is called.
|
||||||
|
|
@ -133,9 +131,6 @@ type StateDB struct {
|
||||||
// Snapshot and RevertToSnapshot.
|
// Snapshot and RevertToSnapshot.
|
||||||
journal *journal
|
journal *journal
|
||||||
|
|
||||||
// State witness if cross validation is needed
|
|
||||||
witness *stateless.Witness
|
|
||||||
|
|
||||||
// Measurements gathered during execution for debugging purposes
|
// Measurements gathered during execution for debugging purposes
|
||||||
AccountReads time.Duration
|
AccountReads time.Duration
|
||||||
AccountHashes time.Duration
|
AccountHashes time.Duration
|
||||||
|
|
@ -200,47 +195,11 @@ func NewWithReader(root common.Hash, db Database, reader Reader) (*StateDB, erro
|
||||||
// state trie concurrently while the state is mutated so that when we reach the
|
// state trie concurrently while the state is mutated so that when we reach the
|
||||||
// commit phase, most of the needed data is already hot.
|
// commit phase, most of the needed data is already hot.
|
||||||
func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) {
|
func (s *StateDB) StartPrefetcher(namespace string, witness *stateless.Witness) {
|
||||||
// Terminate any previously running prefetcher
|
|
||||||
s.StopPrefetcher()
|
|
||||||
|
|
||||||
// Enable witness collection if requested
|
|
||||||
s.witness = witness
|
|
||||||
|
|
||||||
// With the switch to the Proof-of-Stake consensus algorithm, block production
|
|
||||||
// rewards are now handled at the consensus layer. Consequently, a block may
|
|
||||||
// have no state transitions if it contains no transactions and no withdrawals.
|
|
||||||
// In such cases, the account trie won't be scheduled for prefetching, leading
|
|
||||||
// to unnecessary error logs.
|
|
||||||
//
|
|
||||||
// To prevent this, the account trie is always scheduled for prefetching once
|
|
||||||
// the prefetcher is constructed. For more details, see:
|
|
||||||
// https://github.com/ethereum/go-ethereum/issues/29880
|
|
||||||
opener := func(id trie.ID, addr common.Address) (Trie, error) {
|
|
||||||
if s.db.TrieDB().IsVerkle() {
|
|
||||||
return s.db.OpenTrie(id.StateRoot)
|
|
||||||
}
|
|
||||||
if id.Owner != (common.Hash{}) {
|
|
||||||
return s.db.OpenStorageTrie(id.StateRoot, addr, id.Root, nil)
|
|
||||||
}
|
|
||||||
return s.db.OpenTrie(id.StateRoot)
|
|
||||||
}
|
|
||||||
s.prefetcher = newTriePrefetcher(opener, s.originalRoot, namespace, witness == nil)
|
|
||||||
|
|
||||||
id := trie.StateTrieID(s.originalRoot)
|
|
||||||
if err := s.prefetcher.prefetchAccounts(*id, nil, false); err != nil {
|
|
||||||
log.Error("Failed to prefetch account trie", "root", s.originalRoot, "err", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// StopPrefetcher terminates a running prefetcher and reports any leftover stats
|
// StopPrefetcher terminates a running prefetcher and reports any leftover stats
|
||||||
// from the gathered metrics.
|
// from the gathered metrics.
|
||||||
func (s *StateDB) StopPrefetcher() {
|
func (s *StateDB) StopPrefetcher() {}
|
||||||
if s.prefetcher != nil {
|
|
||||||
s.prefetcher.terminate(false)
|
|
||||||
s.prefetcher.report()
|
|
||||||
s.prefetcher = nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// setError remembers the first non-nil error it is called with.
|
// setError remembers the first non-nil error it is called with.
|
||||||
func (s *StateDB) setError(err error) {
|
func (s *StateDB) setError(err error) {
|
||||||
|
|
@ -368,9 +327,6 @@ func (s *StateDB) TxIndex() int {
|
||||||
func (s *StateDB) GetCode(addr common.Address) []byte {
|
func (s *StateDB) GetCode(addr common.Address) []byte {
|
||||||
stateObject := s.getStateObject(addr)
|
stateObject := s.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
if s.witness != nil {
|
|
||||||
s.witness.AddCode(stateObject.Code())
|
|
||||||
}
|
|
||||||
return stateObject.Code()
|
return stateObject.Code()
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
|
|
@ -379,9 +335,6 @@ func (s *StateDB) GetCode(addr common.Address) []byte {
|
||||||
func (s *StateDB) GetCodeSize(addr common.Address) int {
|
func (s *StateDB) GetCodeSize(addr common.Address) int {
|
||||||
stateObject := s.getStateObject(addr)
|
stateObject := s.getStateObject(addr)
|
||||||
if stateObject != nil {
|
if stateObject != nil {
|
||||||
if s.witness != nil {
|
|
||||||
s.witness.AddCode(stateObject.Code())
|
|
||||||
}
|
|
||||||
return stateObject.CodeSize()
|
return stateObject.CodeSize()
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
|
|
@ -612,13 +565,6 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
|
||||||
if acct == nil {
|
if acct == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
// Schedule the resolved account for prefetching if it's enabled.
|
|
||||||
if s.prefetcher != nil {
|
|
||||||
id := trie.StateTrieID(s.originalRoot)
|
|
||||||
if err = s.prefetcher.prefetchAccounts(*id, []common.Address{addr}, true); err != nil {
|
|
||||||
log.Error("Failed to prefetch account", "addr", addr, "err", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Insert into the live set
|
// Insert into the live set
|
||||||
obj := newObject(s, addr, acct)
|
obj := newObject(s, addr, acct)
|
||||||
s.setStateObject(obj)
|
s.setStateObject(obj)
|
||||||
|
|
@ -710,9 +656,6 @@ func (s *StateDB) Copy() *StateDB {
|
||||||
if s.trie != nil {
|
if s.trie != nil {
|
||||||
state.trie = mustCopyTrie(s.trie)
|
state.trie = mustCopyTrie(s.trie)
|
||||||
}
|
}
|
||||||
if s.witness != nil {
|
|
||||||
state.witness = s.witness.Copy()
|
|
||||||
}
|
|
||||||
if s.accessEvents != nil {
|
if s.accessEvents != nil {
|
||||||
state.accessEvents = s.accessEvents.Copy()
|
state.accessEvents = s.accessEvents.Copy()
|
||||||
}
|
}
|
||||||
|
|
@ -797,7 +740,6 @@ func (s *StateDB) LogsForBurnAccounts() []*types.Log {
|
||||||
// the journal as well as the refunds. Finalise, however, will not push any updates
|
// the journal as well as the refunds. Finalise, however, will not push any updates
|
||||||
// into the tries just yet. Only IntermediateRoot or Commit will do that.
|
// into the tries just yet. Only IntermediateRoot or Commit will do that.
|
||||||
func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
||||||
addressesToPrefetch := make([]common.Address, 0, len(s.journal.dirties))
|
|
||||||
for addr := range s.journal.dirties {
|
for addr := range s.journal.dirties {
|
||||||
obj, exist := s.stateObjects[addr]
|
obj, exist := s.stateObjects[addr]
|
||||||
if !exist {
|
if !exist {
|
||||||
|
|
@ -822,16 +764,6 @@ func (s *StateDB) Finalise(deleteEmptyObjects bool) {
|
||||||
obj.finalise()
|
obj.finalise()
|
||||||
s.markUpdate(addr)
|
s.markUpdate(addr)
|
||||||
}
|
}
|
||||||
// At this point, also ship the address off to the precacher. The precacher
|
|
||||||
// will start loading tries, and when the change is eventually committed,
|
|
||||||
// the commit-phase will be a lot faster
|
|
||||||
addressesToPrefetch = append(addressesToPrefetch, addr) // Copy needed for closure
|
|
||||||
}
|
|
||||||
if s.prefetcher != nil && len(addressesToPrefetch) > 0 {
|
|
||||||
id := trie.StateTrieID(s.originalRoot)
|
|
||||||
if err := s.prefetcher.prefetchAccounts(*id, addressesToPrefetch, false); err != nil {
|
|
||||||
log.Error("Failed to prefetch addresses", "addresses", len(addressesToPrefetch), "err", err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Invalidate journal because reverting across transactions is not allowed.
|
// Invalidate journal because reverting across transactions is not allowed.
|
||||||
s.clearJournalAndRefund()
|
s.clearJournalAndRefund()
|
||||||
|
|
@ -858,15 +790,6 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
}
|
}
|
||||||
s.trie = tr
|
s.trie = tr
|
||||||
}
|
}
|
||||||
// If there was a trie prefetcher operating, terminate it async so that the
|
|
||||||
// individual storage tries can be updated as soon as the disk load finishes.
|
|
||||||
if s.prefetcher != nil {
|
|
||||||
s.prefetcher.terminate(true)
|
|
||||||
defer func() {
|
|
||||||
s.prefetcher.report()
|
|
||||||
s.prefetcher = nil // Pre-byzantium, unset any used up prefetcher
|
|
||||||
}()
|
|
||||||
}
|
|
||||||
// Process all storage updates concurrently. The state object update root
|
// Process all storage updates concurrently. The state object update root
|
||||||
// method will internally call a blocking trie fetch from the prefetcher,
|
// method will internally call a blocking trie fetch from the prefetcher,
|
||||||
// so there's no need to explicitly wait for the prefetchers to finish.
|
// so there's no need to explicitly wait for the prefetchers to finish.
|
||||||
|
|
@ -927,49 +850,10 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
obj := s.stateObjects[addr] // closure for the task runner below
|
obj := s.stateObjects[addr] // closure for the task runner below
|
||||||
workers.Go(func() error {
|
workers.Go(func() error {
|
||||||
obj.updateRoot()
|
obj.updateRoot()
|
||||||
|
|
||||||
// If witness building is enabled and the state object has a trie,
|
|
||||||
// gather the witnesses for its specific storage trie
|
|
||||||
if s.witness != nil && obj.trie != nil {
|
|
||||||
s.witness.AddState(obj.trie.Witness(), obj.addrHash())
|
|
||||||
}
|
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// If witness building is enabled, gather all the read-only accesses.
|
|
||||||
// Skip witness collection in Verkle mode, they will be gathered
|
|
||||||
// together at the end.
|
|
||||||
if s.witness != nil && !s.db.TrieDB().IsVerkle() {
|
|
||||||
// Pull in anything that has been accessed before destruction
|
|
||||||
for _, obj := range s.stateObjectsDestruct {
|
|
||||||
// Skip any objects that haven't touched their storage
|
|
||||||
if len(obj.originStorage) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if trie := obj.getPrefetchedTrie(); trie != nil {
|
|
||||||
s.witness.AddState(trie.Witness(), obj.addrHash())
|
|
||||||
} else if obj.trie != nil {
|
|
||||||
s.witness.AddState(obj.trie.Witness(), obj.addrHash())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Pull in only-read and non-destructed trie witnesses
|
|
||||||
for _, obj := range s.stateObjects {
|
|
||||||
// Skip any objects that have been updated
|
|
||||||
if _, ok := s.mutations[obj.address]; ok {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
// Skip any objects that haven't touched their storage
|
|
||||||
if len(obj.originStorage) == 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
if trie := obj.getPrefetchedTrie(); trie != nil {
|
|
||||||
s.witness.AddState(trie.Witness(), obj.addrHash())
|
|
||||||
} else if obj.trie != nil {
|
|
||||||
s.witness.AddState(obj.trie.Witness(), obj.addrHash())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
workers.Wait()
|
workers.Wait()
|
||||||
s.StorageUpdates += time.Since(start)
|
s.StorageUpdates += time.Since(start)
|
||||||
|
|
||||||
|
|
@ -981,14 +865,7 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
// only a single trie is used for state hashing. Replacing a non-nil verkle tree
|
// only a single trie is used for state hashing. Replacing a non-nil verkle tree
|
||||||
// here could result in losing uncommitted changes from storage.
|
// here could result in losing uncommitted changes from storage.
|
||||||
start = time.Now()
|
start = time.Now()
|
||||||
if s.prefetcher != nil {
|
|
||||||
id := trie.StateTrieID(s.originalRoot)
|
|
||||||
if trie := s.prefetcher.trie(*id); trie == nil {
|
|
||||||
log.Error("Failed to retrieve account pre-fetcher trie")
|
|
||||||
} else {
|
|
||||||
s.trie = trie
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Perform updates before deletions. This prevents resolution of unnecessary trie nodes
|
// Perform updates before deletions. This prevents resolution of unnecessary trie nodes
|
||||||
// in circumstances similar to the following:
|
// in circumstances similar to the following:
|
||||||
//
|
//
|
||||||
|
|
@ -1000,7 +877,6 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
// into a shortnode. This requires `B` to be resolved from disk.
|
// into a shortnode. This requires `B` to be resolved from disk.
|
||||||
// Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved.
|
// Whereas if the created node is handled first, then the collapse is avoided, and `B` is not resolved.
|
||||||
var (
|
var (
|
||||||
usedAddrs []common.Address
|
|
||||||
deletedAddrs []common.Address
|
deletedAddrs []common.Address
|
||||||
)
|
)
|
||||||
for addr, op := range s.mutations {
|
for addr, op := range s.mutations {
|
||||||
|
|
@ -1022,7 +898,6 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
s.CodeUpdateBytes += len(obj.code)
|
s.CodeUpdateBytes += len(obj.code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
usedAddrs = append(usedAddrs, addr) // Copy needed for closure
|
|
||||||
}
|
}
|
||||||
for _, deletedAddr := range deletedAddrs {
|
for _, deletedAddr := range deletedAddrs {
|
||||||
s.deleteStateObject(deletedAddr)
|
s.deleteStateObject(deletedAddr)
|
||||||
|
|
@ -1030,20 +905,10 @@ func (s *StateDB) IntermediateRoot(deleteEmptyObjects bool) common.Hash {
|
||||||
}
|
}
|
||||||
s.AccountUpdates += time.Since(start)
|
s.AccountUpdates += time.Since(start)
|
||||||
|
|
||||||
if s.prefetcher != nil {
|
|
||||||
id := trie.StateTrieID(s.originalRoot)
|
|
||||||
s.prefetcher.used(*id, usedAddrs, nil)
|
|
||||||
}
|
|
||||||
// Track the amount of time wasted on hashing the account trie
|
// Track the amount of time wasted on hashing the account trie
|
||||||
defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now())
|
defer func(start time.Time) { s.AccountHashes += time.Since(start) }(time.Now())
|
||||||
|
|
||||||
hash := s.trie.Hash()
|
return s.trie.Hash()
|
||||||
|
|
||||||
// If witness building is enabled, gather the account trie witness
|
|
||||||
if s.witness != nil {
|
|
||||||
s.witness.AddState(s.trie.Witness(), common.Hash{})
|
|
||||||
}
|
|
||||||
return hash
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetTxContext sets the current transaction hash and index which are
|
// SetTxContext sets the current transaction hash and index which are
|
||||||
|
|
@ -1476,7 +1341,7 @@ func (s *StateDB) markUpdate(addr common.Address) {
|
||||||
|
|
||||||
// Witness retrieves the current state witness being collected.
|
// Witness retrieves the current state witness being collected.
|
||||||
func (s *StateDB) Witness() *stateless.Witness {
|
func (s *StateDB) Witness() *stateless.Witness {
|
||||||
return s.witness
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *StateDB) AccessEvents() *AccessEvents {
|
func (s *StateDB) AccessEvents() *AccessEvents {
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,8 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
//lint:file-ignore U1000 this file intentionally keeps unused helpers for future use
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// triePrefetchMetricsPrefix is the prefix under which to publish the metrics.
|
// triePrefetchMetricsPrefix is the prefix under which to publish the metrics.
|
||||||
triePrefetchMetricsPrefix = "trie/prefetch/"
|
triePrefetchMetricsPrefix = "trie/prefetch/"
|
||||||
|
|
@ -111,6 +113,7 @@ func (p *triePrefetcher) terminate(async bool) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// report aggregates the pre-fetching and usage metrics and reports them.
|
// report aggregates the pre-fetching and usage metrics and reports them.
|
||||||
|
// nolint:unused
|
||||||
func (p *triePrefetcher) report() {
|
func (p *triePrefetcher) report() {
|
||||||
if !metrics.Enabled() {
|
if !metrics.Enabled() {
|
||||||
return
|
return
|
||||||
|
|
@ -205,6 +208,7 @@ func (p *triePrefetcher) trie(id trie.ID) Trie {
|
||||||
|
|
||||||
// used marks a batch of state items used to allow creating statistics as to
|
// used marks a batch of state items used to allow creating statistics as to
|
||||||
// how useful or wasteful the fetcher is.
|
// how useful or wasteful the fetcher is.
|
||||||
|
// nolint:unused
|
||||||
func (p *triePrefetcher) used(id trie.ID, usedAddr []common.Address, usedSlot []common.Hash) {
|
func (p *triePrefetcher) used(id trie.ID, usedAddr []common.Address, usedSlot []common.Hash) {
|
||||||
if fetcher := p.fetchers[id]; fetcher != nil {
|
if fetcher := p.fetchers[id]; fetcher != nil {
|
||||||
fetcher.wait() // ensure the fetcher's idle before poking in its internals
|
fetcher.wait() // ensure the fetcher's idle before poking in its internals
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue