cmd, core, eth, miner: apply 7997 in block building (#35285)
Some checks are pending
/ Linux Build (push) Waiting to run
/ Linux Build (arm) (push) Waiting to run
/ Keeper Build (push) Waiting to run
/ Windows Build (push) Waiting to run
/ Docker Image (push) Waiting to run

This PR applies the 7997 irregular state transition in t8n, block
building, simulation and tracing.
This commit is contained in:
rjl493456442 2026-07-07 20:40:25 +08:00 committed by GitHub
parent cf35a1b6f6
commit 4d2181aa41
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 82 additions and 28 deletions

View file

@ -242,6 +242,13 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 {
misc.ApplyDAOHardFork(statedb)
}
// EIP-7997: insert the deterministic deployment factory at the Amsterdam
// activation block via an irregular state transition.
if pre.Env.Number > 0 &&
chainConfig.IsAmsterdam(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) &&
!chainConfig.IsAmsterdam(new(big.Int).SetUint64(pre.Env.Number-1), pre.Env.ParentTimestamp) {
misc.ApplyEIP7997(statedb)
}
evm := vm.NewEVM(vmContext, statedb, chainConfig, vmConfig)
if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil {
core.ProcessBeaconBlockRoot(*beaconRoot, evm, blockAccessList)

View file

@ -81,10 +81,9 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(block.Number()) == 0 {
misc.ApplyDAOHardFork(tracingStateDB)
}
// EIP-7997: insert the deterministic deployment factory at the Amsterdam
// activation block via an irregular state transition.
if isEIP7997Transition(config, p.chain, header) {
misc.ApplyEIP7997(tracingStateDB)
parent := p.chain.GetHeader(block.ParentHash(), block.NumberU64()-1)
if parent == nil {
return nil, fmt.Errorf("missing parent %#x", block.ParentHash())
}
var (
context = NewEVMBlockContext(header, p.chain, nil)
@ -98,7 +97,7 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
evm.SetJumpDestCache(jumpDestCache)
}
// Run the pre-execution system calls
blockAccessList.Merge(PreExecution(ctx, block.BeaconRoot(), block.ParentHash(), config, evm, block.Number(), block.Time()))
blockAccessList.Merge(PreExecution(ctx, block.BeaconRoot(), parent, config, evm, block.Number(), block.Time()))
// Iterate over and process the individual transactions
for i, tx := range block.Transactions() {
@ -142,27 +141,20 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated
}, nil
}
// isEIP7997Transition reports whether the given header belongs to the first block
// on which the Amsterdam fork is active.
func isEIP7997Transition(config *params.ChainConfig, chain ChainContext, header *types.Header) bool {
if header.Number.Sign() == 0 || !config.IsAmsterdam(header.Number, header.Time) {
return false
}
parent := chain.GetHeader(header.ParentHash, header.Number.Uint64()-1)
if parent == nil {
return false
}
return !config.IsAmsterdam(parent.Number, parent.Time)
}
// PreExecution processes pre-execution system calls.
func PreExecution(ctx context.Context, beaconRoot *common.Hash, parent common.Hash, config *params.ChainConfig, evm *vm.EVM, number *big.Int, time uint64) *bal.ConstructionBlockAccessList {
// PreExecution processes pre-execution state changes and system calls.
func PreExecution(ctx context.Context, beaconRoot *common.Hash, parent *types.Header, config *params.ChainConfig, evm *vm.EVM, number *big.Int, time uint64) *bal.ConstructionBlockAccessList {
_, _, spanEnd := telemetry.StartSpan(ctx, "core.preExecution")
defer spanEnd(nil)
var blockAccessList *bal.ConstructionBlockAccessList
if config.IsAmsterdam(number, time) {
blockAccessList = bal.NewConstructionBlockAccessList()
// EIP-7997: insert the deterministic deployment factory at the Amsterdam
// activation block via an irregular state transition.
if !config.IsAmsterdam(parent.Number, parent.Time) {
misc.ApplyEIP7997(evm.StateDB)
}
}
// EIP-4788
if beaconRoot != nil {
@ -170,7 +162,7 @@ func PreExecution(ctx context.Context, beaconRoot *common.Hash, parent common.Ha
}
// EIP-2935
if config.IsPrague(number, time) || config.IsUBT(number, time) {
ProcessParentBlockHash(parent, evm, blockAccessList)
ProcessParentBlockHash(parent.Hash(), evm, blockAccessList)
}
return blockAccessList
}

View file

@ -250,7 +250,7 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
defer evm.Release()
// Run pre-execution system calls
core.PreExecution(ctx, block.BeaconRoot(), block.ParentHash(), eth.blockchain.Config(), evm, block.Number(), block.Time())
core.PreExecution(ctx, block.BeaconRoot(), parent.Header(), eth.blockchain.Config(), evm, block.Number(), block.Time())
if txIndex == 0 && len(block.Transactions()) == 0 {
return nil, context, statedb, release, nil

View file

@ -373,7 +373,7 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil)
evm := vm.NewEVM(context, statedb, api.backend.ChainConfig(), vm.Config{})
core.PreExecution(ctx, next.BeaconRoot(), next.ParentHash(), api.backend.ChainConfig(), evm, next.Number(), next.Time())
core.PreExecution(ctx, next.BeaconRoot(), block.Header(), api.backend.ChainConfig(), evm, next.Number(), next.Time())
evm.Release()
// Clean out any pending release functions of trace state. Note this
// step must be done after constructing tracing state, because the
@ -523,7 +523,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
)
defer evm.Release()
// Run pre-execution system calls
core.PreExecution(ctx, block.BeaconRoot(), block.ParentHash(), chainConfig, evm, block.Number(), block.Time())
core.PreExecution(ctx, block.BeaconRoot(), parent.Header(), chainConfig, evm, block.Number(), block.Time())
for i, tx := range block.Transactions() {
if err := ctx.Err(); err != nil {
@ -582,7 +582,7 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
defer evm.Release()
// Run pre-execution system calls
core.PreExecution(ctx, block.BeaconRoot(), block.ParentHash(), api.backend.ChainConfig(), evm, block.Number(), block.Time())
core.PreExecution(ctx, block.BeaconRoot(), parent.Header(), api.backend.ChainConfig(), evm, block.Number(), block.Time())
// JS tracers have high overhead. In this case run a parallel
// process that generates states in one thread and traces txes
@ -754,7 +754,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
defer evm.Release()
// Run pre-execution system calls
core.PreExecution(ctx, block.BeaconRoot(), block.ParentHash(), chainConfig, evm, block.Number(), block.Time())
core.PreExecution(ctx, block.BeaconRoot(), parent.Header(), chainConfig, evm, block.Number(), block.Time())
for i, tx := range block.Transactions() {
// Prepare the transaction for un-traced execution

View file

@ -322,7 +322,7 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header,
evm.SetPrecompiles(precompiles)
}
// Run pre-execution system calls
blockAccessList.Merge(core.PreExecution(ctx, header.ParentBeaconRoot, header.ParentHash, sim.chainConfig, evm, header.Number, header.Time))
blockAccessList.Merge(core.PreExecution(ctx, header.ParentBeaconRoot, parent, sim.chainConfig, evm, header.Number, header.Time))
var allLogs []*types.Log
for i, call := range block.Calls {

View file

@ -17,6 +17,7 @@
package miner
import (
"bytes"
"context"
"math/big"
"reflect"
@ -26,6 +27,7 @@ import (
"github.com/ethereum/go-ethereum/beacon/engine"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/consensus"
"github.com/ethereum/go-ethereum/consensus/beacon"
"github.com/ethereum/go-ethereum/consensus/clique"
"github.com/ethereum/go-ethereum/consensus/ethash"
"github.com/ethereum/go-ethereum/core"
@ -115,6 +117,7 @@ func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine
copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes())
e.Authorize(testBankAddress)
case *ethash.Ethash:
case *beacon.Beacon:
default:
t.Fatalf("unexpected consensus engine type: %T", engine)
}
@ -194,6 +197,58 @@ func TestBuildPayload(t *testing.T) {
}
}
// TestBuildPayloadAmsterdamTransition verifies that a locally built payload for
// the first Amsterdam block contains the EIP-7997 deterministic deployment
// factory, i.e. the block-building path applies the same irregular state
// transition as block processing and the resulting block is importable.
func TestBuildPayloadAmsterdamTransition(t *testing.T) {
var (
db = rawdb.NewMemoryDatabase()
recipient = common.HexToAddress("0xdeadbeef")
)
config := new(params.ChainConfig)
*config = *params.MergedTestChainConfig
config.AmsterdamTime = new(uint64)
*config.AmsterdamTime = 1 // genesis (t=0) is pre-Amsterdam, the first block crosses the fork
w, b := newTestWorker(t, config, beacon.New(ethash.NewFaker()), db, 0)
var (
beaconRoot = common.Hash{0x01}
slotNum = uint64(1)
)
payload, err := w.buildPayload(context.Background(), &BuildPayloadArgs{
Parent: b.chain.CurrentBlock().Hash(),
Timestamp: 1,
FeeRecipient: recipient,
Withdrawals: types.Withdrawals{},
BeaconRoot: &beaconRoot,
SlotNum: &slotNum,
}, false)
if err != nil {
t.Fatalf("Failed to build payload %v", err)
}
block := payload.empty
if !config.IsAmsterdam(block.Number(), block.Time()) {
t.Fatal("transition block is not an Amsterdam block")
}
// The block must be importable: Process applies EIP-7997 independently, so
// a payload built without the factory would fail the state root check here.
if _, err := b.chain.InsertChain(types.Blocks{block}); err != nil {
t.Fatalf("failed to insert transition block: %v", err)
}
statedb, err := b.chain.StateAt(block.Header())
if err != nil {
t.Fatalf("failed to open state at transition block: %v", err)
}
if code := statedb.GetCode(params.DeterministicFactoryAddress); !bytes.Equal(code, params.DeterministicFactoryCode) {
t.Fatalf("factory code missing from built payload state:\n got %x\nwant %x", code, params.DeterministicFactoryCode)
}
if nonce := statedb.GetNonce(params.DeterministicFactoryAddress); nonce != 1 {
t.Fatalf("factory nonce = %d, want 1", nonce)
}
}
func TestPayloadId(t *testing.T) {
t.Parallel()
ids := make(map[string]int)

View file

@ -326,7 +326,7 @@ func (miner *Miner) prepareWork(ctx context.Context, genParams *generateParams,
return nil, err
}
// Run pre-execution system calls
env.bal.Merge(core.PreExecution(ctx, header.ParentBeaconRoot, header.ParentHash, miner.chainConfig, env.evm, header.Number, header.Time))
env.bal.Merge(core.PreExecution(ctx, header.ParentBeaconRoot, parent, miner.chainConfig, env.evm, header.Number, header.Time))
return env, nil
}