mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-12 01:41:36 +00:00
core/state: remove the reader tracker
This commit is contained in:
parent
91b3543b61
commit
121607dfab
2 changed files with 10 additions and 145 deletions
|
|
@ -16,6 +16,14 @@
|
||||||
|
|
||||||
package state
|
package state
|
||||||
|
|
||||||
|
import (
|
||||||
|
"sync"
|
||||||
|
|
||||||
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
|
"github.com/ethereum/go-ethereum/core/types/bal"
|
||||||
|
)
|
||||||
|
|
||||||
// The EIP27928 reader utilizes a hierarchical architecture to optimize state
|
// The EIP27928 reader utilizes a hierarchical architecture to optimize state
|
||||||
// access during block execution:
|
// access during block execution:
|
||||||
//
|
//
|
||||||
|
|
@ -37,14 +45,7 @@ package state
|
||||||
// for the entire block.
|
// for the entire block.
|
||||||
//
|
//
|
||||||
// The architecture can be illustrated by the diagram below:
|
// The architecture can be illustrated by the diagram below:
|
||||||
|
//
|
||||||
// [ Block Level Read List ] <────────────────┐
|
|
||||||
// ▲ │ ( Aggregate )
|
|
||||||
// │ │
|
|
||||||
// ┌───────┴───────┐ ┌───────┴───────┐
|
|
||||||
// │ readerTracker │ │ readerTracker │ (State read tracking)
|
|
||||||
// └───────┬───────┘ └───────┬───────┘
|
|
||||||
// │ │
|
|
||||||
// ┌──────────────┴──────────────┐ ┌──────────────┴──────────────┐
|
// ┌──────────────┴──────────────┐ ┌──────────────┴──────────────┐
|
||||||
// │ ReaderWithBlockLevelAL │ │ ReaderWithBlockLevelAL │
|
// │ ReaderWithBlockLevelAL │ │ ReaderWithBlockLevelAL │
|
||||||
// │ (Pre-state + Mutations) │ │ (Pre-state + Mutations) │
|
// │ (Pre-state + Mutations) │ │ (Pre-state + Mutations) │
|
||||||
|
|
@ -68,15 +69,6 @@ package state
|
||||||
// Instead, it directly utilizes the readerTracker, wrapped around the
|
// Instead, it directly utilizes the readerTracker, wrapped around the
|
||||||
// base reader, to construct the access list.
|
// base reader, to construct the access list.
|
||||||
|
|
||||||
import (
|
|
||||||
"maps"
|
|
||||||
"sync"
|
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
|
||||||
"github.com/ethereum/go-ethereum/core/types/bal"
|
|
||||||
)
|
|
||||||
|
|
||||||
type fetchTask struct {
|
type fetchTask struct {
|
||||||
addr common.Address
|
addr common.Address
|
||||||
slots []common.Hash
|
slots []common.Hash
|
||||||
|
|
@ -94,6 +86,7 @@ type prefetchStateReader struct {
|
||||||
closeOnce sync.Once
|
closeOnce sync.Once
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// nolint:unused
|
||||||
func newPrefetchStateReader(reader StateReader, accessList map[common.Address][]common.Hash, nThreads int) *prefetchStateReader {
|
func newPrefetchStateReader(reader StateReader, accessList map[common.Address][]common.Hash, nThreads int) *prefetchStateReader {
|
||||||
tasks := make([]*fetchTask, 0, len(accessList))
|
tasks := make([]*fetchTask, 0, len(accessList))
|
||||||
for addr, slots := range accessList {
|
for addr, slots := range accessList {
|
||||||
|
|
@ -252,75 +245,3 @@ func (r *ReaderWithBlockLevelAccessList) Code(addr common.Address, codeHash comm
|
||||||
func (r *ReaderWithBlockLevelAccessList) CodeSize(addr common.Address, codeHash common.Hash) (int, error) {
|
func (r *ReaderWithBlockLevelAccessList) CodeSize(addr common.Address, codeHash common.Hash) (int, error) {
|
||||||
panic("implement me")
|
panic("implement me")
|
||||||
}
|
}
|
||||||
|
|
||||||
// StorageAccessList represents a set of storage slots accessed within an account.
|
|
||||||
type StorageAccessList map[common.Hash]struct{}
|
|
||||||
|
|
||||||
// StateAccessList maps account addresses to their respective accessed storage slots.
|
|
||||||
type StateAccessList map[common.Address]StorageAccessList
|
|
||||||
|
|
||||||
// Merge merges the entries from the other StateAccessList into the receiver.
|
|
||||||
func (s StateAccessList) Merge(other StateAccessList) {
|
|
||||||
for addr, otherSlots := range other {
|
|
||||||
slots, exists := s[addr]
|
|
||||||
if !exists {
|
|
||||||
s[addr] = otherSlots
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
maps.Copy(slots, otherSlots)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// StateReaderTracker defines the capability to retrieve the access footprint
|
|
||||||
// recorded during state reading operations.
|
|
||||||
type StateReaderTracker interface {
|
|
||||||
GetStateAccessList() StateAccessList
|
|
||||||
}
|
|
||||||
|
|
||||||
type readerTracker struct {
|
|
||||||
Reader
|
|
||||||
access StateAccessList
|
|
||||||
lock sync.RWMutex
|
|
||||||
}
|
|
||||||
|
|
||||||
func newReaderTracker(reader Reader) *readerTracker {
|
|
||||||
return &readerTracker{
|
|
||||||
Reader: reader,
|
|
||||||
access: make(StateAccessList),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Account implements StateReader, tracking the accessed address locally.
|
|
||||||
func (r *readerTracker) Account(addr common.Address) (*types.StateAccount, error) {
|
|
||||||
r.lock.Lock()
|
|
||||||
defer r.lock.Unlock()
|
|
||||||
|
|
||||||
_, exists := r.access[addr]
|
|
||||||
if !exists {
|
|
||||||
r.access[addr] = make(StorageAccessList)
|
|
||||||
}
|
|
||||||
return r.Reader.Account(addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Storage implements StateReader, tracking the accessed slot identifier locally.
|
|
||||||
func (r *readerTracker) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
|
||||||
r.lock.Lock()
|
|
||||||
defer r.lock.Unlock()
|
|
||||||
|
|
||||||
list, exists := r.access[addr]
|
|
||||||
if !exists {
|
|
||||||
list = make(StorageAccessList)
|
|
||||||
r.access[addr] = list
|
|
||||||
}
|
|
||||||
list[slot] = struct{}{}
|
|
||||||
|
|
||||||
return r.Reader.Storage(addr, slot)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetStateAccessList implements StateReaderTracker, returning the access footprint.
|
|
||||||
func (r *readerTracker) GetStateAccessList() StateAccessList {
|
|
||||||
r.lock.RLock()
|
|
||||||
defer r.lock.RUnlock()
|
|
||||||
|
|
||||||
return r.access
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,6 @@ package state
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"maps"
|
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
@ -144,58 +143,3 @@ func TestPrefetchReader(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeFakeSlots(n int) map[common.Hash]struct{} {
|
|
||||||
slots := make(map[common.Hash]struct{})
|
|
||||||
for i := 0; i < n; i++ {
|
|
||||||
slots[testrand.Hash()] = struct{}{}
|
|
||||||
}
|
|
||||||
return slots
|
|
||||||
}
|
|
||||||
|
|
||||||
type noopStateReader struct{}
|
|
||||||
|
|
||||||
func (r *noopStateReader) Account(addr common.Address) (*types.StateAccount, error) { return nil, nil }
|
|
||||||
func (r *noopStateReader) Storage(addr common.Address, slot common.Hash) (common.Hash, error) {
|
|
||||||
return common.Hash{}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type noopCodeReader struct{}
|
|
||||||
|
|
||||||
func (r *noopCodeReader) Has(addr common.Address, codeHash common.Hash) bool { return false }
|
|
||||||
|
|
||||||
func (r *noopCodeReader) Code(addr common.Address, codeHash common.Hash) []byte {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (r *noopCodeReader) CodeSize(addr common.Address, codeHash common.Hash) int {
|
|
||||||
return 0
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestReaderWithTracker(t *testing.T) {
|
|
||||||
var r Reader = newReaderTracker(newReader(&noopCodeReader{}, &noopStateReader{}))
|
|
||||||
|
|
||||||
accesses := map[common.Address]map[common.Hash]struct{}{
|
|
||||||
testrand.Address(): makeFakeSlots(10),
|
|
||||||
testrand.Address(): makeFakeSlots(0),
|
|
||||||
}
|
|
||||||
for addr, slots := range accesses {
|
|
||||||
r.Account(addr)
|
|
||||||
for slot := range slots {
|
|
||||||
r.Storage(addr, slot)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
got := r.(StateReaderTracker).GetStateAccessList()
|
|
||||||
if len(got) != len(accesses) {
|
|
||||||
t.Fatalf("Unexpected access list, want: %d, got: %d", len(accesses), len(got))
|
|
||||||
}
|
|
||||||
for addr, slots := range got {
|
|
||||||
entry, ok := accesses[addr]
|
|
||||||
if !ok {
|
|
||||||
t.Fatal("Unexpected access list")
|
|
||||||
}
|
|
||||||
if !maps.Equal(slots, entry) {
|
|
||||||
t.Fatal("Unexpected slots")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue