bal execution refactor (wip)

This commit is contained in:
Jared Wasinger 2025-09-29 21:50:48 +08:00
parent cb541b833d
commit 4282087fb0
6 changed files with 6 additions and 327 deletions

View file

@ -210,8 +210,6 @@ type BlockChainConfig struct {
// StateSizeTracking indicates whether the state size tracking is enabled.
StateSizeTracking bool
// EnableBAL enables block access list creation and verification for post-Cancun blocks which contain access lists.
EnableBAL bool
}
// DefaultConfig returns the default config.
@ -1924,7 +1922,7 @@ func (bc *BlockChain) insertChain(chain types.Blocks, setHead bool, makeWitness
start := time.Now()
// construct or verify block access lists if BALs are enabled and
// we are post-selfdestruct removal fork.
enableBAL := (bc.cfg.EnableBAL && bc.chainConfig.IsCancun(block.Number(), block.Time())) || bc.chainConfig.IsAmsterdam(block.Number(), block.Time())
enableBAL := (bc.cfg.EnableBALForTesting && bc.chainConfig.IsCancun(block.Number(), block.Time())) || bc.chainConfig.IsAmsterdam(block.Number(), block.Time())
blockHasAccessList := block.Body().AccessList != nil
makeBAL := enableBAL && !blockHasAccessList
validateBAL := enableBAL && blockHasAccessList

View file

@ -168,6 +168,7 @@ func (r *BALReader) ModifiedAccounts() (res []common.Address) {
}
func (r *BALReader) ValidateStateReads(allReads bal.StateAccesses) error {
fmt.Printf("bal is %v\n", r.block.Body().AccessList.String())
// 1. remove any slots from 'allReads' which were written
// 2. validate that the read set in the BAL matches 'allReads' exactly
for addr, reads := range allReads {
@ -178,6 +179,7 @@ func (r *BALReader) ValidateStateReads(allReads bal.StateAccesses) error {
}
}
fmt.Printf("addr is %x\n", addr)
expectedReads := r.accesses[addr].StorageReads
if len(reads) != len(expectedReads) {
return fmt.Errorf("mismatch between the number of computed reads and number of expected reads")

View file

@ -1,218 +0,0 @@
package state
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/stateless"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types/bal"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie/utils"
"github.com/holiman/uint256"
)
type AccessListCreationDB struct {
idx uint16
inner BlockProcessingDB
accessList *bal.ConstructionBlockAccessList
}
func NewBlockAccessListBuilder(db BlockProcessingDB) *AccessListCreationDB {
return &AccessListCreationDB{0, db, bal.NewConstructionBlockAccessList()}
}
func (a *AccessListCreationDB) SetAccessListIndex(idx int) {
a.idx = uint16(idx)
}
// ConstructedBlockAccessList retrieves the access list that has been constructed
// by the StateDB instance, or nil if BAL construction was not enabled.
func (a *AccessListCreationDB) ConstructedBlockAccessList() *bal.ConstructionBlockAccessList {
return a.accessList
}
func (a *AccessListCreationDB) CreateAccount(address common.Address) {
a.inner.CreateAccount(address)
}
func (a *AccessListCreationDB) CreateContract(address common.Address) {
a.inner.CreateContract(address)
}
func (a *AccessListCreationDB) SubBalance(address common.Address, u *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
return a.inner.SubBalance(address, u, reason)
}
func (a *AccessListCreationDB) AddBalance(address common.Address, u *uint256.Int, reason tracing.BalanceChangeReason) uint256.Int {
return a.inner.AddBalance(address, u, reason)
}
func (a *AccessListCreationDB) GetBalance(address common.Address) *uint256.Int {
return a.inner.GetBalance(address)
}
func (a *AccessListCreationDB) GetNonce(address common.Address) uint64 {
return a.inner.GetNonce(address)
}
func (a *AccessListCreationDB) SetNonce(address common.Address, u uint64, reason tracing.NonceChangeReason) {
a.inner.SetNonce(address, u, reason)
}
func (a *AccessListCreationDB) GetCodeHash(address common.Address) common.Hash {
return a.inner.GetCodeHash(address)
}
func (a *AccessListCreationDB) GetCode(address common.Address) []byte {
return a.inner.GetCode(address)
}
func (a *AccessListCreationDB) SetCode(addr common.Address, code []byte, reason tracing.CodeChangeReason) (prev []byte) {
return a.inner.SetCode(addr, code, reason)
}
func (a *AccessListCreationDB) GetCodeSize(address common.Address) int {
return a.inner.GetCodeSize(address)
}
func (a *AccessListCreationDB) AddRefund(u uint64) {
a.inner.AddRefund(u)
}
func (a *AccessListCreationDB) SubRefund(u uint64) {
a.inner.SubRefund(u)
}
func (a *AccessListCreationDB) GetRefund() uint64 {
return a.inner.GetRefund()
}
func (a *AccessListCreationDB) GetStateAndCommittedState(address common.Address, hash common.Hash) (common.Hash, common.Hash) {
return a.inner.GetStateAndCommittedState(address, hash)
}
func (a *AccessListCreationDB) GetState(address common.Address, hash common.Hash) common.Hash {
return a.inner.GetState(address, hash)
}
func (a *AccessListCreationDB) SetState(address common.Address, hash common.Hash, hash2 common.Hash) common.Hash {
return a.inner.SetState(address, hash, hash2)
}
func (a *AccessListCreationDB) GetStorageRoot(addr common.Address) common.Hash {
return a.inner.GetStorageRoot(addr)
}
func (a *AccessListCreationDB) GetTransientState(addr common.Address, key common.Hash) common.Hash {
return a.inner.GetTransientState(addr, key)
}
func (a *AccessListCreationDB) SetTransientState(addr common.Address, key, value common.Hash) {
a.inner.SetTransientState(addr, key, value)
}
func (a *AccessListCreationDB) SelfDestruct(address common.Address) uint256.Int {
return a.inner.SelfDestruct(address)
}
func (a *AccessListCreationDB) HasSelfDestructed(address common.Address) bool {
return a.inner.HasSelfDestructed(address)
}
func (a *AccessListCreationDB) SelfDestruct6780(address common.Address) (uint256.Int, bool) {
return a.inner.SelfDestruct6780(address)
}
func (a *AccessListCreationDB) Exist(address common.Address) bool {
return a.inner.Exist(address)
}
func (a *AccessListCreationDB) Empty(address common.Address) bool {
return a.inner.Empty(address)
}
func (a *AccessListCreationDB) AddressInAccessList(addr common.Address) bool {
return a.inner.AddressInAccessList(addr)
}
func (a *AccessListCreationDB) SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool) {
return a.inner.SlotInAccessList(addr, slot)
}
func (a *AccessListCreationDB) AddAddressToAccessList(addr common.Address) {
a.inner.AddAddressToAccessList(addr)
}
func (a *AccessListCreationDB) AddSlotToAccessList(addr common.Address, slot common.Hash) {
a.inner.AddSlotToAccessList(addr, slot)
}
func (a *AccessListCreationDB) PointCache() *utils.PointCache {
return a.inner.PointCache()
}
func (a *AccessListCreationDB) Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList) {
a.inner.Prepare(rules, sender, coinbase, dest, precompiles, txAccesses)
}
func (a *AccessListCreationDB) RevertToSnapshot(i int) {
a.inner.RevertToSnapshot(i)
}
func (a *AccessListCreationDB) Snapshot() int {
return a.inner.Snapshot()
}
func (a *AccessListCreationDB) AddLog(log *types.Log) {
a.inner.AddLog(log)
}
func (a *AccessListCreationDB) AddPreimage(hash common.Hash, bytes []byte) {
a.inner.AddPreimage(hash, bytes)
}
func (a *AccessListCreationDB) Witness() *stateless.Witness {
return a.inner.Witness()
}
func (a *AccessListCreationDB) AccessEvents() *AccessEvents {
return a.inner.AccessEvents()
}
func (a *AccessListCreationDB) TxIndex() int {
return a.inner.TxIndex()
}
func (a *AccessListCreationDB) Finalise(b bool) (*bal.StateDiff, *bal.StateAccesses) {
diff, accesses := a.inner.Finalise(b)
a.accessList.ApplyDiff(uint(a.idx), diff)
a.accessList.ApplyAccesses(*accesses) // TODO: can remove the pointer on accesses (map is already a reference type)
return nil, nil // TODO: not sure what to do here. The diff has been applied to the access list so it is "owned" by the access list, not sure why a caller would need it...
}
func (a *AccessListCreationDB) GetLogs(hash common.Hash, blockNumber uint64, blockHash common.Hash, blockTime uint64) []*types.Log {
return a.inner.GetLogs(hash, blockNumber, blockHash, blockTime)
}
func (a *AccessListCreationDB) IntermediateRoot(deleteEmpty bool) common.Hash {
return a.inner.IntermediateRoot(deleteEmpty)
}
func (a *AccessListCreationDB) Database() Database {
return a.inner.Database()
}
func (a *AccessListCreationDB) GetTrie() Trie {
return a.inner.GetTrie()
}
func (s *AccessListCreationDB) SetTxContext(thash common.Hash, ti int) {
s.inner.SetTxContext(thash, ti)
}
func (s *AccessListCreationDB) Error() error {
return s.inner.Error()
}
func (s *AccessListCreationDB) Copy() BlockProcessingDB {
return &AccessListCreationDB{s.idx, s.inner.Copy(), s.accessList.Copy()}
}
var _ BlockProcessingDB = &AccessListCreationDB{}

View file

@ -1,103 +0,0 @@
package state
import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/stateless"
"github.com/ethereum/go-ethereum/core/tracing"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/types/bal"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie/utils"
"github.com/holiman/uint256"
)
type BlockProcessingDB interface {
CreateAccount(common.Address)
CreateContract(common.Address)
SubBalance(common.Address, *uint256.Int, tracing.BalanceChangeReason) uint256.Int
AddBalance(common.Address, *uint256.Int, tracing.BalanceChangeReason) uint256.Int
GetBalance(common.Address) *uint256.Int
GetNonce(common.Address) uint64
SetNonce(common.Address, uint64, tracing.NonceChangeReason)
GetCodeHash(common.Address) common.Hash
GetCode(common.Address) []byte
// SetCode sets the new code for the address, and returns the previous code, if any.
SetCode(addr common.Address, code []byte, reason tracing.CodeChangeReason) (prev []byte)
GetCodeSize(common.Address) int
AddRefund(uint64)
SubRefund(uint64)
GetRefund() uint64
GetStateAndCommittedState(common.Address, common.Hash) (common.Hash, common.Hash)
GetState(common.Address, common.Hash) common.Hash
SetState(common.Address, common.Hash, common.Hash) common.Hash
GetStorageRoot(addr common.Address) common.Hash
GetTransientState(addr common.Address, key common.Hash) common.Hash
SetTransientState(addr common.Address, key, value common.Hash)
SelfDestruct(common.Address) uint256.Int
HasSelfDestructed(common.Address) bool
// SelfDestruct6780 is post-EIP6780 selfdestruct, which means that it's a
// send-all-to-beneficiary, unless the contract was created in this same
// transaction, in which case it will be destructed.
// This method returns the prior balance, along with a boolean which is
// true iff the object was indeed destructed.
SelfDestruct6780(common.Address) (uint256.Int, bool)
// Exist reports whether the given account exists in
// Notably this also returns true for self-destructed accounts within the current transaction.
Exist(common.Address) bool
// Empty returns whether the given account is empty. Empty
// is defined according to EIP161 (balance = nonce = code = 0).
Empty(common.Address) bool
AddressInAccessList(addr common.Address) bool
SlotInAccessList(addr common.Address, slot common.Hash) (addressOk bool, slotOk bool)
// AddAddressToAccessList adds the given address to the access list. This operation is safe to perform
// even if the feature/fork is not active yet
AddAddressToAccessList(addr common.Address)
// AddSlotToAccessList adds the given (address,slot) to the access list. This operation is safe to perform
// even if the feature/fork is not active yet
AddSlotToAccessList(addr common.Address, slot common.Hash)
// PointCache returns the point cache used in computations
PointCache() *utils.PointCache
Prepare(rules params.Rules, sender, coinbase common.Address, dest *common.Address, precompiles []common.Address, txAccesses types.AccessList)
RevertToSnapshot(int)
Snapshot() int
AddLog(*types.Log)
AddPreimage(common.Hash, []byte)
Witness() *stateless.Witness
AccessEvents() *AccessEvents
// Finalise must be invoked at the end of a transaction
Finalise(bool) (*bal.StateDiff, *bal.StateAccesses)
// These two methods are not used in the EVM. however, I need them to be part of the interface
// so that block processing/production can use instances of this interface so that the StateDB
// wrapped with BAL creation functionality can be passed in case of BALs
GetLogs(hash common.Hash, blockNumber uint64, blockHash common.Hash, blockTime uint64) []*types.Log
IntermediateRoot(deleteEmpty bool) common.Hash
Database() Database
GetTrie() Trie
SetTxContext(thash common.Hash, ti int)
Error() error
TxIndex() int
Copy() BlockProcessingDB
}

View file

@ -778,7 +778,7 @@ func (s *StateDB) CreateContract(addr common.Address) {
// Copy creates a deep, independent copy of the state.
// Snapshots of the copied state cannot be applied to the copy.
func (s *StateDB) Copy() BlockProcessingDB {
func (s *StateDB) Copy() *StateDB {
// Copy all the basic fields, initialize the memory ones
state := &StateDB{
db: s.db,

View file

@ -158,8 +158,8 @@ func (t *BlockTest) createTestBlockChain(config *params.ChainConfig, snapshotter
Tracer: tracer,
StatelessSelfValidation: witness,
},
NoPrefetch: true,
EnableBAL: createAndVerifyBAL,
NoPrefetch: true,
EnableBALForTesting: createAndVerifyBAL,
}
if snapshotter {
options.SnapshotLimit = 1