From 6ded1620dbd417791e618d90defa14f783a22711 Mon Sep 17 00:00:00 2001 From: Marius van der Wijden Date: Thu, 23 Apr 2026 10:30:49 +0200 Subject: [PATCH] core: apply fixes for BAL (claude) --- core/chain_makers.go | 6 ++-- core/state_processor.go | 23 ++++++++++++++-- internal/ethapi/simulate.go | 4 +-- miner/worker.go | 55 +++++++++++++++++++++++++++++++------ 4 files changed, 72 insertions(+), 16 deletions(-) diff --git a/core/chain_makers.go b/core/chain_makers.go index 5d83d64157..17bdd8ffa8 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -465,8 +465,10 @@ func GenerateChain(config *params.ChainConfig, parent *types.Block, engine conse body.Withdrawals = make([]*types.Withdrawal, 0) } } - // Assemble the block for delivery. - block := AssembleBlock(b.engine, cm, b.header, statedb, &body, b.receipts) + // Assemble the block for delivery. When Amsterdam is active, + // pass the accumulated BAL so engine.Finalize's accesses and + // mutations are folded in and the BAL is attached to the block. + block := AssembleBlock(b.engine, cm, b.header, statedb, &body, b.receipts, b.accessList) // Write state changes to db root, err := statedb.Commit(b.header.Number.Uint64(), config.IsEIP158(b.header.Number), config.IsCancun(b.header.Number, b.header.Time)) diff --git a/core/state_processor.go b/core/state_processor.go index ace4106db5..5e6ed61cb7 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -408,9 +408,26 @@ func onSystemCallStart(tracer *tracing.Hooks, ctx *tracing.VMContext) { } // AssembleBlock finalizes the state and assembles the block with provided -// body and receipts. -func AssembleBlock(engine consensus.Engine, chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt) *types.Block { - engine.Finalize(chain, header, state, body) +// body and receipts. When accessList is non-nil (EIP-7928 / Amsterdam), the +// accesses and mutations produced by engine.Finalize (e.g. withdrawal balance +// changes) are accumulated into it as block-finalize entries, the computed +// BAL hash is written into the header, and the finalized BAL is attached to +// the returned block. +func AssembleBlock(engine consensus.Engine, chain consensus.ChainHeaderReader, header *types.Header, state *state.StateDB, body *types.Body, receipts []*types.Receipt, accessList *bal.ConstructionBlockAccessList) *types.Block { + finalizeAccesses, finalizeMutations := engine.Finalize(chain, header, state, body) + if accessList != nil { + if finalizeMutations != nil { + accessList.AddBlockFinalizeMutations(finalizeMutations) + } + if finalizeAccesses != nil { + accessList.AddAccesses(finalizeAccesses) + } + encoded := accessList.ToEncodingObj() + balHash := encoded.Hash() + header.BlockAccessListHash = &balHash + header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) + return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)).WithAccessListUnsafe(encoded) + } header.Root = state.IntermediateRoot(chain.Config().IsEIP158(header.Number)) return types.NewBlock(header, body, receipts, trie.NewStackTrie(nil)) } diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index 1fd41c9426..909cb26007 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -423,8 +423,8 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, } chainHeadReader := &simChainHeadReader{ctx, sim.b} - // Assemble the block - b := core.AssembleBlock(sim.b.Engine(), chainHeadReader, header, sim.state, blockBody, receipts) + // Assemble the block. Simulated blocks don't carry a BAL. + b := core.AssembleBlock(sim.b.Engine(), chainHeadReader, header, sim.state, blockBody, receipts, nil) repairLogs(callResults, b.Hash()) return b, callResults, senders, nil diff --git a/miner/worker.go b/miner/worker.go index 5e97ae3113..0d590e4a3b 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -32,6 +32,7 @@ import ( "github.com/ethereum/go-ethereum/core/stateless" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/types/bal" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/internal/telemetry" "github.com/ethereum/go-ethereum/log" @@ -73,6 +74,14 @@ type environment struct { blobs int witness *stateless.Witness + + // accessList accumulates the block's BAL (EIP-7928). Non-nil only when + // Amsterdam is active. Populated from pre-tx system calls + // (ProcessBeaconBlockRoot, ProcessParentBlockHash) in prepareWork, each + // transaction in applyTransaction, post-tx system calls + // (ProcessWithdrawalQueue, ProcessConsolidationQueue) in generateWork, + // and finally engine.Finalize inside AssembleBlock. + accessList *bal.ConstructionBlockAccessList } // txFitsSize reports whether the transaction fits into the block size limit. @@ -213,21 +222,33 @@ func (miner *Miner) generateWork(ctx context.Context, genParam *generateParams, return &newPayloadResult{err: err} } // EIP-7002 - if _, _, err := core.ProcessWithdrawalQueue(&requests, work.evm); err != nil { + wqAccesses, wqMutations, err := core.ProcessWithdrawalQueue(&requests, work.evm) + if err != nil { return &newPayloadResult{err: err} } // EIP-7251 consolidations - if _, _, err := core.ProcessConsolidationQueue(&requests, work.evm); err != nil { + cqAccesses, cqMutations, err := core.ProcessConsolidationQueue(&requests, work.evm) + if err != nil { return &newPayloadResult{err: err} } + if work.accessList != nil { + postMut := bal.NewStateMutations() + postMut.Merge(wqMutations) + postMut.Merge(cqMutations) + work.accessList.AddBlockFinalizeMutations(postMut) + work.accessList.AddAccesses(wqAccesses) + work.accessList.AddAccesses(cqAccesses) + } } if requests != nil { reqHash := types.CalcRequestsHash(requests) work.header.RequestsHash = &reqHash } - // Assemble the block for delivery. + // Assemble the block for delivery. AssembleBlock calls engine.Finalize + // and, when a BAL is supplied, folds its accesses/mutations into the BAL, + // sets header.BlockAccessListHash, and attaches the BAL to the block. _, _, assembleSpanEnd := telemetry.StartSpan(ctx, "miner.AssembleBlock") - block := core.AssembleBlock(miner.engine, miner.chain, work.header, work.state, &body, work.receipts) + block := core.AssembleBlock(miner.engine, miner.chain, work.header, work.state, &body, work.receipts, work.accessList) assembleSpanEnd(nil) return &newPayloadResult{ @@ -327,10 +348,18 @@ func (miner *Miner) prepareWork(ctx context.Context, genParams *generateParams, return nil, err } if header.ParentBeaconRoot != nil { - core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm) + accesses, mutations := core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm) + if env.accessList != nil { + env.accessList.AddBlockInitMutations(mutations) + env.accessList.AddAccesses(accesses) + } } if miner.chainConfig.IsPrague(header.Number, header.Time) { - core.ProcessParentBlockHash(header.ParentHash, env.evm) + accesses, mutations := core.ProcessParentBlockHash(header.ParentHash, env.evm) + if env.accessList != nil { + env.accessList.AddBlockInitMutations(mutations) + env.accessList.AddAccesses(accesses) + } } return env, nil } @@ -351,7 +380,7 @@ func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase } state.StartPrefetcher("miner", bundle) // Note the passed coinbase may be different with header.Coinbase. - return &environment{ + env := &environment{ signer: types.MakeSigner(miner.chainConfig, header.Number, header.Time), state: state, size: uint64(header.Size()), @@ -360,7 +389,11 @@ func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase header: header, witness: state.Witness(), evm: vm.NewEVM(core.NewEVMBlockContext(header, miner.chain, &coinbase), state, miner.chainConfig, vm.Config{}), - }, nil + } + if miner.chainConfig.IsAmsterdam(header.Number, header.Time) { + env.accessList = bal.NewConstructionBlockAccessList() + } + return env, nil } func (miner *Miner) commitTransaction(ctx context.Context, env *environment, tx *types.Transaction) (err error) { @@ -414,12 +447,16 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (* snap = env.state.Snapshot() gp = env.gasPool.Snapshot() ) - _, _, receipt, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx) + txAccesses, txMutations, receipt, err := core.ApplyTransaction(env.evm, env.gasPool, env.state, env.header, tx) if err != nil { env.state.RevertToSnapshot(snap) env.gasPool.Set(gp) return nil, err } + if env.accessList != nil { + env.accessList.AddTransactionMutations(txMutations, env.tcount) + env.accessList.AddAccesses(txAccesses) + } env.header.GasUsed = env.gasPool.Used() return receipt, nil }