cmd,core,eth,miner:

* add method on StateReaderTracker to clear the accumulated reads
* don't factor the BAL size into the payload size during construction in the miner
* simplify miner code for constructing payloads-with-BALs via the use of aformentioned StateReaderTracker clear method
* clean up the configuration of the BAL execution mode based on the preset flag specified
This commit is contained in:
Jared Wasinger 2026-03-10 17:34:11 -04:00
parent 79debd7566
commit a74438510b
8 changed files with 35 additions and 61 deletions

View file

@ -20,6 +20,7 @@ import (
"bufio" "bufio"
"errors" "errors"
"fmt" "fmt"
"github.com/ethereum/go-ethereum/core/types/bal"
"os" "os"
"reflect" "reflect"
"runtime" "runtime"
@ -243,12 +244,12 @@ func makeFullNode(ctx *cli.Context) *node.Node {
if ctx.IsSet(utils.BlockAccessListExecutionModeFlag.Name) { if ctx.IsSet(utils.BlockAccessListExecutionModeFlag.Name) {
val := ctx.String(utils.BlockAccessListExecutionModeFlag.Name) val := ctx.String(utils.BlockAccessListExecutionModeFlag.Name)
switch val { switch val {
case utils.BalExecutionModeFull: case utils.BalExecutionModeOptimized:
cfg.Eth.BALExecutionMode = 0 cfg.Eth.BALExecutionMode = bal.BALExecutionOptimized
case utils.BalExecutionModeNoBatchIO: case utils.BalExecutionModeNoBatchIO:
cfg.Eth.BALExecutionMode = 1 cfg.Eth.BALExecutionMode = bal.BALExecutionNoBatchIO
case utils.BalExecutionModeSequential: case utils.BalExecutionModeSequential:
cfg.Eth.BALExecutionMode = 2 cfg.Eth.BALExecutionMode = bal.BALExecutionSequential
default: default:
utils.Fatalf("invalid option for --bal.executionmode: %s. acceptable values are full|nobatchio|sequential", val) utils.Fatalf("invalid option for --bal.executionmode: %s. acceptable values are full|nobatchio|sequential", val)
} }

View file

@ -1124,13 +1124,13 @@ block access list execution type. possible inputs are:
- sequential: no performance acceleration - sequential: no performance acceleration
- full: parallel transaction execution, state root calculation, async warming of access list reads - full: parallel transaction execution, state root calculation, async warming of access list reads
- nobatchio: same as 'full', but without async warming of access list reads`, - nobatchio: same as 'full', but without async warming of access list reads`,
Value: BalExecutionModeFull, Value: BalExecutionModeOptimized,
Category: flags.MiscCategory, Category: flags.MiscCategory,
} }
) )
const ( const (
BalExecutionModeFull = "full" BalExecutionModeOptimized = "full"
BalExecutionModeNoBatchIO = "nobatchio" BalExecutionModeNoBatchIO = "nobatchio"
BalExecutionModeSequential = "sequential" BalExecutionModeSequential = "sequential"
) )

View file

@ -179,12 +179,6 @@ const (
BlockChainVersion uint64 = 9 BlockChainVersion uint64 = 9
) )
const (
BALExecutionModeFull = 0
BALExecutionModeNoBatchIO = iota
BALExecutionModeSequential = iota
)
// BlockChainConfig contains the configuration of the BlockChain object. // BlockChainConfig contains the configuration of the BlockChain object.
type BlockChainConfig struct { type BlockChainConfig struct {
// Trie database related options // Trie database related options
@ -246,8 +240,7 @@ type BlockChainConfig struct {
StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose) StatelessSelfValidation bool // Generate execution witnesses and self-check against them (testing purpose)
EnableWitnessStats bool // Whether trie access statistics collection is enabled EnableWitnessStats bool // Whether trie access statistics collection is enabled
// TODO clean this config up to use defined constants... BALExecutionMode bal.BALExecutionMode
BALExecutionMode int
} }
// DefaultConfig returns the default config. // DefaultConfig returns the default config.
@ -609,7 +602,7 @@ func (bc *BlockChain) processBlockWithAccessList(parentRoot common.Hash, block *
statedb *state.StateDB statedb *state.StateDB
) )
useAsyncReads := bc.cfg.BALExecutionMode != BALExecutionModeNoBatchIO useAsyncReads := bc.cfg.BALExecutionMode != bal.BALExecutionNoBatchIO
al := block.AccessList() // TODO: make the return of this method not be a pointer al := block.AccessList() // TODO: make the return of this method not be a pointer
accessListReader := bal.NewAccessListReader(*al) accessListReader := bal.NewAccessListReader(*al)
prefetchReader, err := bc.statedb.ReaderEIP7928(parentRoot, accessListReader.StorageKeys(useAsyncReads), runtime.NumCPU()) prefetchReader, err := bc.statedb.ReaderEIP7928(parentRoot, accessListReader.StorageKeys(useAsyncReads), runtime.NumCPU())
@ -2146,7 +2139,7 @@ func (bc *BlockChain) insertChain(ctx context.Context, chain types.Blocks, setHe
return nil, it.index, err return nil, it.index, err
} }
blockHasAccessList := block.AccessList() != nil blockHasAccessList := block.AccessList() != nil
if blockHasAccessList && bc.cfg.BALExecutionMode != BALExecutionModeSequential { if blockHasAccessList && bc.cfg.BALExecutionMode != bal.BALExecutionSequential {
res.stats.reportBALMetrics() res.stats.reportBALMetrics()
} else { } else {
res.stats.reportMetrics() res.stats.reportMetrics()
@ -2265,7 +2258,7 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash,
blockHasAccessList := block.AccessList() != nil blockHasAccessList := block.AccessList() != nil
// optimized execution path for blocks which contain BALs // optimized execution path for blocks which contain BALs
if blockHasAccessList && bc.cfg.BALExecutionMode != BALExecutionModeSequential { if blockHasAccessList && bc.cfg.BALExecutionMode != bal.BALExecutionSequential {
return bc.processBlockWithAccessList(parentRoot, block, config.WriteHead) return bc.processBlockWithAccessList(parentRoot, block, config.WriteHead)
} }

View file

@ -290,6 +290,7 @@ func (r *ReaderWithBlockLevelAccessList) CodeSize(addr common.Address, codeHash
// recorded during state reading operations. // recorded during state reading operations.
type StateReaderTracker interface { type StateReaderTracker interface {
GetStateAccessList() bal.StateAccesses GetStateAccessList() bal.StateAccesses
Clear()
} }
func NewReaderWithTracker(r Reader) Reader { func NewReaderWithTracker(r Reader) Reader {
@ -333,3 +334,7 @@ func (r *readerTracker) Storage(addr common.Address, slot common.Hash) (common.H
func (r *readerTracker) GetStateAccessList() bal.StateAccesses { func (r *readerTracker) GetStateAccessList() bal.StateAccesses {
return r.access return r.access
} }
func (r *readerTracker) Clear() {
r.access = make(bal.StateAccesses)
}

View file

@ -531,3 +531,11 @@ func (a *AccountMutations) Eq(other *AccountMutations) bool {
} }
return true return true
} }
type BALExecutionMode int
const (
BALExecutionOptimized BALExecutionMode = iota
BALExecutionNoBatchIO
BALExecutionSequential
)

View file

@ -19,6 +19,7 @@ package ethconfig
import ( import (
"errors" "errors"
"github.com/ethereum/go-ethereum/core/types/bal"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -210,7 +211,7 @@ type Config struct {
// RangeLimit restricts the maximum range (end - start) for range queries. // RangeLimit restricts the maximum range (end - start) for range queries.
RangeLimit uint64 `toml:",omitempty"` RangeLimit uint64 `toml:",omitempty"`
BALExecutionMode int BALExecutionMode bal.BALExecutionMode
} }
// CreateConsensusEngine creates a consensus engine for the given chain config. // CreateConsensusEngine creates a consensus engine for the given chain config.

View file

@ -3,6 +3,7 @@
package ethconfig package ethconfig
import ( import (
"github.com/ethereum/go-ethereum/core/types/bal"
"time" "time"
"github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common"
@ -68,7 +69,7 @@ func (c Config) MarshalTOML() (interface{}, error) {
TxSyncDefaultTimeout time.Duration `toml:",omitempty"` TxSyncDefaultTimeout time.Duration `toml:",omitempty"`
TxSyncMaxTimeout time.Duration `toml:",omitempty"` TxSyncMaxTimeout time.Duration `toml:",omitempty"`
RangeLimit uint64 `toml:",omitempty"` RangeLimit uint64 `toml:",omitempty"`
BALExecutionMode int BALExecutionMode bal.BALExecutionMode
} }
var enc Config var enc Config
enc.Genesis = c.Genesis enc.Genesis = c.Genesis
@ -340,7 +341,7 @@ func (c *Config) UnmarshalTOML(unmarshal func(interface{}) error) error {
c.RangeLimit = *dec.RangeLimit c.RangeLimit = *dec.RangeLimit
} }
if dec.BALExecutionMode != nil { if dec.BALExecutionMode != nil {
c.BALExecutionMode = *dec.BALExecutionMode c.BALExecutionMode = bal.BALExecutionMode(*dec.BALExecutionMode)
} }
return nil return nil
} }

View file

@ -377,10 +377,6 @@ func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase
}, nil }, nil
} }
var (
errAccessListOversized = errors.New("access list oversized")
)
func (miner *Miner) commitTransaction(env *environment, tx *types.Transaction) (err error) { func (miner *Miner) commitTransaction(env *environment, tx *types.Transaction) (err error) {
if tx.Type() == types.BlobTxType { if tx.Type() == types.BlobTxType {
return miner.commitBlobTransaction(env, tx) return miner.commitBlobTransaction(env, tx)
@ -432,43 +428,19 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (*
snap = env.state.Snapshot() snap = env.state.Snapshot()
gp = env.gasPool.Snapshot() gp = env.gasPool.Snapshot()
) )
var stateCopy *state.StateDB
var prevReader state.Reader
if env.accessList != nil {
prevReader = env.state.Reader()
stateCopy = env.state.WithReader(state.NewReaderWithTracker(env.state.Reader()))
env.evm.StateDB = stateCopy
} else {
stateCopy = env.state
}
mutations, receipt, err := core.ApplyTransaction(env.evm, env.gasPool, stateCopy, env.header, tx) mutations, receipt, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx)
if err != nil { if err != nil {
if env.accessList != nil { if env.accessList != nil {
// transaction couldn't be applied. reset env state to what it was before env.state.Reader().(state.StateReaderTracker).Clear()
env.state = env.state.WithReader(prevReader)
env.evm.StateDB = env.state
} else {
env.state.RevertToSnapshot(snap)
} }
env.state.RevertToSnapshot(snap)
env.gasPool.Set(gp) env.gasPool.Set(gp)
return nil, err
} }
if env.accessList != nil { if env.accessList != nil {
al := env.accessList.Copy() env.accessList.AccumulateMutations(mutations, uint16(env.tcount)+1)
al.AccumulateMutations(mutations, uint16(env.tcount)+1) env.accessList.AccumulateReads(env.state.Reader().(state.StateReaderTracker).GetStateAccessList())
al.AccumulateReads(stateCopy.Reader().(state.StateReaderTracker).GetStateAccessList())
if env.size+tx.Size()+uint64(al.ToEncodingObj().EncodedSize()) >= params.MaxBlockSize-maxBlockSizeBufferZone {
env.gasPool.Set(gp)
// transaction couldn't be applied. reset env state to what it was before
env.state = env.state.WithReader(prevReader)
env.evm.StateDB = env.state
return nil, errAccessListOversized
}
env.state = stateCopy.WithReader(prevReader)
env.evm.StateDB = env.state
env.accessList = al
} }
return receipt, err return receipt, err
} }
@ -481,7 +453,6 @@ func (miner *Miner) commitTransactions(env *environment, plainTxs, blobTxs *tran
if env.gasPool == nil { if env.gasPool == nil {
env.gasPool = core.NewGasPool(gasLimit) env.gasPool = core.NewGasPool(gasLimit)
} }
loop:
for { for {
// Check interruption signal and abort building if it's fired. // Check interruption signal and abort building if it's fired.
if interrupt != nil { if interrupt != nil {
@ -580,12 +551,6 @@ loop:
case errors.Is(err, nil): case errors.Is(err, nil):
// Everything ok, collect the logs and shift in the next transaction from the same account // Everything ok, collect the logs and shift in the next transaction from the same account
txs.Shift() txs.Shift()
case errors.Is(err, errAccessListOversized):
// Transaction can't be applied because it would cause the block to be oversized due to the
// contribution of the state accesses/modifications it makes.
// terminate the payload construction as it's not guaranteed we will be able to find a transaction
// that can fit in a short amount of time.
break loop
default: default:
// Transaction is regarded as invalid, drop all consecutive transactions from // Transaction is regarded as invalid, drop all consecutive transactions from
// the same sender because of `nonce-too-high` clause. // the same sender because of `nonce-too-high` clause.