core/state: rework state reader

This commit is contained in:
Gary Rong 2026-07-14 10:30:38 +08:00
parent b67888ab97
commit 6da4960306

View file

@ -382,30 +382,44 @@ func (r *multiStateReader) Storage(addr common.Address, slot common.Hash) (commo
return common.Hash{}, errors.Join(errs...) return common.Hash{}, errors.Join(errs...)
} }
const stateReaderCacheBuckets = 64
// stateReaderWithCache is a wrapper around StateReader that maintains additional // stateReaderWithCache is a wrapper around StateReader that maintains additional
// state caches to support concurrent state access. // state caches to support concurrent state access.
type stateReaderWithCache struct { type stateReaderWithCache struct {
StateReader StateReader
// Previously resolved state entries. // Account buckets are selected by account address. This reader is typically
accounts map[common.Address]*types.StateAccount // used in scenarios requiring concurrent access to accounts; multiple buckets
accountLock sync.RWMutex // reduce lock contention.
accountBuckets [stateReaderCacheBuckets]struct {
lock sync.RWMutex
accounts map[common.Address]*types.StateAccount
}
// List of storage buckets, each of which is thread-safe. // Storage buckets are selected by both account address and storage key. This
// This reader is typically used in scenarios requiring concurrent // avoids serializing accesses to distinct slots of the same account.
// access to storage. Using multiple buckets helps mitigate storageBuckets [stateReaderCacheBuckets]struct {
// the overhead caused by locking.
storageBuckets [16]struct {
lock sync.RWMutex lock sync.RWMutex
storages map[common.Address]map[common.Hash]common.Hash storages map[common.Address]map[common.Hash]common.Hash
} }
} }
func accountCacheBucket(addr common.Address) int {
return int(addr[0] & (stateReaderCacheBuckets - 1))
}
func storageCacheBucket(addr common.Address, slot common.Hash) int {
return int((addr[0] ^ slot[0] ^ slot[len(slot)-1]) & (stateReaderCacheBuckets - 1))
}
// newStateReaderWithCache constructs the state reader with local cache. // newStateReaderWithCache constructs the state reader with local cache.
func newStateReaderWithCache(sr StateReader) *stateReaderWithCache { func newStateReaderWithCache(sr StateReader) *stateReaderWithCache {
r := &stateReaderWithCache{ r := &stateReaderWithCache{
StateReader: sr, StateReader: sr,
accounts: make(map[common.Address]*types.StateAccount), }
for i := range r.accountBuckets {
r.accountBuckets[i].accounts = make(map[common.Address]*types.StateAccount)
} }
for i := range r.storageBuckets { for i := range r.storageBuckets {
r.storageBuckets[i].storages = make(map[common.Address]map[common.Hash]common.Hash) r.storageBuckets[i].storages = make(map[common.Address]map[common.Hash]common.Hash)
@ -419,10 +433,12 @@ func newStateReaderWithCache(sr StateReader) *stateReaderWithCache {
// //
// An error will be returned if the state is corrupted in the underlying reader. // An error will be returned if the state is corrupted in the underlying reader.
func (r *stateReaderWithCache) account(addr common.Address) (*types.StateAccount, bool, error) { func (r *stateReaderWithCache) account(addr common.Address) (*types.StateAccount, bool, error) {
bucket := &r.accountBuckets[accountCacheBucket(addr)]
// Try to resolve the requested account in the local cache // Try to resolve the requested account in the local cache
r.accountLock.RLock() bucket.lock.RLock()
acct, ok := r.accounts[addr] acct, ok := bucket.accounts[addr]
r.accountLock.RUnlock() bucket.lock.RUnlock()
if ok { if ok {
return acct, true, nil return acct, true, nil
} }
@ -431,9 +447,9 @@ func (r *stateReaderWithCache) account(addr common.Address) (*types.StateAccount
if err != nil { if err != nil {
return nil, false, err return nil, false, err
} }
r.accountLock.Lock() bucket.lock.Lock()
r.accounts[addr] = acct bucket.accounts[addr] = acct
r.accountLock.Unlock() bucket.lock.Unlock()
return acct, false, nil return acct, false, nil
} }
@ -453,7 +469,7 @@ func (r *stateReaderWithCache) storage(addr common.Address, slot common.Hash) (c
var ( var (
value common.Hash value common.Hash
ok bool ok bool
bucket = &r.storageBuckets[addr[0]&0x0f] bucket = &r.storageBuckets[storageCacheBucket(addr, slot)]
) )
// Try to resolve the requested storage slot in the local cache // Try to resolve the requested storage slot in the local cache
bucket.lock.RLock() bucket.lock.RLock()