Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
34 changes: 13 additions & 21 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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() {
Expand Down Expand Up @@ -142,35 +141,28 @@ 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 {
ProcessBeaconBlockRoot(*beaconRoot, evm, blockAccessList)
}
// EIP-2935
if config.IsPrague(number, time) || config.IsUBT(number, time) {
ProcessParentBlockHash(parent, evm, blockAccessList)
ProcessParentBlockHash(parent.Hash(), evm, blockAccessList)
}
return blockAccessList
}
Expand Down
2 changes: 1 addition & 1 deletion eth/state_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion internal/ethapi/simulate.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
55 changes: 55 additions & 0 deletions miner/payload_building_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package miner

import (
"bytes"
"context"
"math/big"
"reflect"
Expand All @@ -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"
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
Loading