core/state: invoke prefetcher

This commit is contained in:
Gary Rong 2026-03-20 16:05:46 +08:00 committed by CPerezz
parent 1ae462f08d
commit 38c7021c73
No known key found for this signature in database
GPG key ID: 62045F34B97177DD
3 changed files with 32 additions and 2 deletions

View file

@ -80,10 +80,10 @@ type Hasher interface {
// asynchronously warm up trie/state data ahead of mutations or hashing. // asynchronously warm up trie/state data ahead of mutations or hashing.
type Prefetcher interface { type Prefetcher interface {
// PrefetchAccount schedules the account for prefetching. // PrefetchAccount schedules the account for prefetching.
PrefetchAccount(addresses []common.Address) PrefetchAccount(addresses []common.Address, read bool)
// PrefetchStorage schedules the storage slot for prefetching. // PrefetchStorage schedules the storage slot for prefetching.
PrefetchStorage(addr common.Address, keys []common.Hash) PrefetchStorage(addr common.Address, keys []common.Hash, read bool)
} }
// WitnessCollector is an optional extension implemented by hashers that can // WitnessCollector is an optional extension implemented by hashers that can

View file

@ -191,6 +191,12 @@ func (s *stateObject) GetCommittedState(key common.Hash) common.Hash {
s.db.StorageReads += time.Since(start) s.db.StorageReads += time.Since(start)
s.originStorage[key] = value s.originStorage[key] = value
// Schedule the resolved storage slots for prefetching if it's enabled.
prefetch, ok := s.db.hasher.(Prefetcher)
if ok {
prefetch.PrefetchStorage(s.address, []common.Hash{key}, true)
}
return value return value
} }
@ -223,6 +229,7 @@ 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
@ -235,6 +242,7 @@ 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)
} }
// 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
@ -251,6 +259,12 @@ func (s *stateObject) finalise() {
// of the newly-created object as it's no longer eligible for self-destruct // of the newly-created object as it's no longer eligible for self-destruct
// by EIP-6780. For non-newly-created objects, it's a no-op. // by EIP-6780. For non-newly-created objects, it's a no-op.
s.newContract = false s.newContract = false
// Schedule the resolved storage slots for prefetching if it's enabled.
prefetch, ok := s.db.hasher.(Prefetcher)
if ok {
prefetch.PrefetchStorage(s.address, slotsToPrefetch, false)
}
} }
// updateTrie is responsible for persisting cached storage changes into the // updateTrie is responsible for persisting cached storage changes into the

View file

@ -555,6 +555,12 @@ func (s *StateDB) getStateObject(addr common.Address) *stateObject {
// 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)
// Schedule the resolved account for prefetching if it's enabled.
prefetcher, ok := s.hasher.(Prefetcher)
if ok {
prefetcher.PrefetchAccount([]common.Address{addr}, true)
}
return obj return obj
} }
@ -725,6 +731,7 @@ 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 {
@ -749,9 +756,18 @@ 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 prefetcher. The prefetcher
// will start loading tries, and when the change is eventually committed,
// the commit-phase will be a lot faster
addressesToPrefetch = append(addressesToPrefetch, addr)
} }
// Invalidate journal because reverting across transactions is not allowed. // Invalidate journal because reverting across transactions is not allowed.
s.clearJournalAndRefund() s.clearJournalAndRefund()
prefetcher, ok := s.hasher.(Prefetcher)
if ok {
prefetcher.PrefetchAccount(addressesToPrefetch, false)
}
} }
// IntermediateRoot computes the current root hash of the state trie. // IntermediateRoot computes the current root hash of the state trie.