diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 253ebe1111..15973e934d 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -17,6 +17,7 @@ package t8ntool import ( + "context" "encoding/json" "fmt" stdmath "math" @@ -331,27 +332,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, } // Gather the execution-layer triggered requests. - var requests [][]byte - if chainConfig.IsPrague(vmContext.BlockNumber, vmContext.Time) { - requests = [][]byte{} - // EIP-6110 - var allLogs []*types.Log - for _, receipt := range receipts { - allLogs = append(allLogs, receipt.Logs...) - } - if err := core.ParseDepositLogs(&requests, allLogs, chainConfig); err != nil { - return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not parse requests logs: %v", err)) - } - // EIP-7002 - if err := core.ProcessWithdrawalQueue(&requests, evm); err != nil { - return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not process withdrawal requests: %v", err)) - } - // EIP-7251 - if err := core.ProcessConsolidationQueue(&requests, evm); err != nil { - return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("could not process consolidation requests: %v", err)) - } + var allLogs []*types.Log + for _, receipt := range receipts { + allLogs = append(allLogs, receipt.Logs...) + } + requests, err := core.PostExecution(context.Background(), chainConfig, vmContext.BlockNumber, vmContext.Time, allLogs, evm) + if err != nil { + return nil, nil, nil, NewError(ErrorEVM, fmt.Errorf("failed to process post-execution: %v", err)) } - // Commit block root, err := statedb.Commit(vmContext.BlockNumber.Uint64(), chainConfig.IsEIP158(vmContext.BlockNumber), chainConfig.IsCancun(vmContext.BlockNumber, vmContext.Time)) if err != nil { diff --git a/core/chain_makers.go b/core/chain_makers.go index 46cd98de61..7474d892b1 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -17,6 +17,7 @@ package core import ( + "context" "fmt" "math/big" @@ -314,28 +315,17 @@ func (b *BlockGen) collectRequests(readonly bool) (requests [][]byte) { // off the statedb before executing the system calls. statedb = statedb.Copy() } + var blockLogs []*types.Log + for _, r := range b.receipts { + blockLogs = append(blockLogs, r.Logs...) + } + // TODO use the shared EVM throughout the entire generation cycle + blockContext := NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase) + evm := vm.NewEVM(blockContext, statedb, b.cm.config, vm.Config{}) - if b.cm.config.IsPrague(b.header.Number, b.header.Time) { - requests = [][]byte{} - // EIP-6110 deposits - var blockLogs []*types.Log - for _, r := range b.receipts { - blockLogs = append(blockLogs, r.Logs...) - } - if err := ParseDepositLogs(&requests, blockLogs, b.cm.config); err != nil { - panic(fmt.Sprintf("failed to parse deposit log: %v", err)) - } - // create EVM for system calls - blockContext := NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase) - evm := vm.NewEVM(blockContext, statedb, b.cm.config, vm.Config{}) - // EIP-7002 - if err := ProcessWithdrawalQueue(&requests, evm); err != nil { - panic(fmt.Sprintf("could not process withdrawal requests: %v", err)) - } - // EIP-7251 - if err := ProcessConsolidationQueue(&requests, evm); err != nil { - panic(fmt.Sprintf("could not process consolidation requests: %v", err)) - } + requests, err := PostExecution(context.Background(), b.cm.config, b.header.Number, b.header.Time, blockLogs, evm) + if err != nil { + panic(fmt.Sprintf("failed to run post-execution: %v", err)) } return requests } diff --git a/core/state_processor.go b/core/state_processor.go index 9dcb4cf07c..4bffece7ac 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -76,28 +76,18 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated if hooks := cfg.Tracer; hooks != nil { tracingStateDB = state.NewHookedState(statedb, hooks) } - // Mutate the block and state according to any hard-fork specs if config.DAOForkSupport && config.DAOForkBlock != nil && config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(tracingStateDB) } var ( - context vm.BlockContext + context = NewEVMBlockContext(header, p.chain, nil) signer = types.MakeSigner(config, header.Number, header.Time) + evm = vm.NewEVM(context, tracingStateDB, config, cfg) ) - - // Apply pre-execution system calls. - context = NewEVMBlockContext(header, p.chain, nil) - evm := vm.NewEVM(context, tracingStateDB, config, cfg) defer evm.Release() - - if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - ProcessBeaconBlockRoot(*beaconRoot, evm) - } - if config.IsPrague(block.Number(), block.Time()) || config.IsUBT(block.Number(), block.Time()) { - ProcessParentBlockHash(block.ParentHash(), evm) - } - + // Run the pre-execution system calls + PreExecution(ctx, block.BeaconRoot(), block.ParentHash(), config, evm, block.Number(), block.Time()) // Iterate over and process the individual transactions for i, tx := range block.Transactions() { msg, err := TransactionToMessage(tx, signer, header.BaseFee) @@ -119,11 +109,11 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated allLogs = append(allLogs, receipt.Logs...) spanEnd(nil) } - requests, err := postExecution(ctx, config, block, allLogs, evm) + // Run the post-execution system calls + requests, err := PostExecution(ctx, config, block.Number(), block.Time(), allLogs, evm) if err != nil { return nil, err } - // Finalize the block, applying any consensus engine specific extras (e.g. block rewards) p.chain.Engine().Finalize(p.chain, header, tracingStateDB, block.Body()) @@ -135,28 +125,44 @@ func (p *StateProcessor) Process(ctx context.Context, block *types.Block, stated }, nil } -// postExecution processes the post-execution system calls if Prague is enabled. -func postExecution(ctx context.Context, config *params.ChainConfig, block *types.Block, allLogs []*types.Log, evm *vm.EVM) (requests [][]byte, err error) { +// 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) { + _, _, spanEnd := telemetry.StartSpan(ctx, "core.preExecution") + defer spanEnd(nil) + + // EIP-4788 + if beaconRoot != nil { + ProcessBeaconBlockRoot(*beaconRoot, evm) + } + // EIP-2935 + if config.IsPrague(number, time) || config.IsUBT(number, time) { + ProcessParentBlockHash(parent, evm) + } +} + +// PostExecution processes post-execution system calls when Prague is enabled. +// If Prague is not activated, it returns null requests to differentiate from +// empty requests. +func PostExecution(ctx context.Context, config *params.ChainConfig, number *big.Int, time uint64, allLogs []*types.Log, evm *vm.EVM) (requests [][]byte, err error) { _, _, spanEnd := telemetry.StartSpan(ctx, "core.postExecution") defer spanEnd(&err) // Read requests if Prague is enabled. - if config.IsPrague(block.Number(), block.Time()) { + if config.IsPrague(number, time) { requests = [][]byte{} // EIP-6110 if err := ParseDepositLogs(&requests, allLogs, config); err != nil { - return requests, fmt.Errorf("failed to parse deposit logs: %w", err) + return nil, fmt.Errorf("failed to parse deposit logs: %w", err) } // EIP-7002 if err := ProcessWithdrawalQueue(&requests, evm); err != nil { - return requests, fmt.Errorf("failed to process withdrawal queue: %w", err) + return nil, fmt.Errorf("failed to process withdrawal queue: %w", err) } // EIP-7251 if err := ProcessConsolidationQueue(&requests, evm); err != nil { - return requests, fmt.Errorf("failed to process consolidation queue: %w", err) + return nil, fmt.Errorf("failed to process consolidation queue: %w", err) } } - return requests, nil } diff --git a/eth/state_accessor.go b/eth/state_accessor.go index a806a4fc56..53dfb7d458 100644 --- a/eth/state_accessor.go +++ b/eth/state_accessor.go @@ -248,13 +248,10 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block, context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil) evm := vm.NewEVM(context, statedb, eth.blockchain.Config(), vm.Config{}) defer evm.Release() - if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm) - } - // If prague hardfork, insert parent block hash in the state as per EIP-2935. - if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm) - } + + // Run pre-execution system calls + core.PreExecution(ctx, block.BeaconRoot(), block.ParentHash(), eth.blockchain.Config(), evm, block.Number(), block.Time()) + if txIndex == 0 && len(block.Transactions()) == 0 { return nil, context, statedb, release, nil } diff --git a/eth/tracers/api.go b/eth/tracers/api.go index dae11b81de..d9e40f7ec1 100644 --- a/eth/tracers/api.go +++ b/eth/tracers/api.go @@ -372,13 +372,8 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed // as per EIP-4788. context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil) evm := vm.NewEVM(context, statedb, api.backend.ChainConfig(), vm.Config{}) - if beaconRoot := next.BeaconRoot(); beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm) - } - // Insert parent hash in history contract. - if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) { - core.ProcessParentBlockHash(next.ParentHash(), evm) - } + + core.PreExecution(ctx, next.BeaconRoot(), next.ParentHash(), 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 @@ -494,8 +489,8 @@ func (api *API) StandardTraceBlockToFile(ctx context.Context, hash common.Hash, return api.standardTraceBlockToFile(ctx, block, config) } -// IntermediateRoots executes a block (bad- or canon- or side-), and returns a list -// of intermediate roots: the stateroot after each transaction. +// IntermediateRoots executes a block, and returns a list of intermediate roots: +// the stateroot after each transaction. func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config *TraceConfig) ([]common.Hash, error) { block, _ := api.blockByHash(ctx, hash) if block == nil { @@ -517,21 +512,19 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config return nil, err } defer release() + var ( roots []common.Hash signer = types.MakeSigner(api.backend.ChainConfig(), block.Number(), block.Time()) chainConfig = api.backend.ChainConfig() vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) deleteEmptyObjects = chainConfig.IsEIP158(block.Number()) + evm = vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) ) - evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) defer evm.Release() - if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm) - } - if chainConfig.IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm) - } + // Run pre-execution system calls + core.PreExecution(ctx, block.BeaconRoot(), block.ParentHash(), chainConfig, evm, block.Number(), block.Time()) + for i, tx := range block.Transactions() { if err := ctx.Err(); err != nil { return nil, err @@ -548,7 +541,7 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config // N.B: This should never happen while tracing canon blocks, only when tracing bad blocks. return roots, nil } - // calling IntermediateRoot will internally call Finalize on the state + // Calling IntermediateRoot will internally call Finalize on the state // so any modifications are written to the trie roots = append(roots, statedb.IntermediateRoot(deleteEmptyObjects)) } @@ -587,12 +580,9 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac blockCtx := core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil) evm := vm.NewEVM(blockCtx, statedb, api.backend.ChainConfig(), vm.Config{}) defer evm.Release() - if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm) - } - if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm) - } + + // Run pre-execution system calls + core.PreExecution(ctx, block.BeaconRoot(), block.ParentHash(), 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 @@ -760,15 +750,12 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block // Note: This copies the config, to not screw up the main config chainConfig, canon = overrideConfig(chainConfig, config.Overrides) } - evm := vm.NewEVM(vmctx, statedb, chainConfig, vm.Config{}) defer evm.Release() - if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - core.ProcessBeaconBlockRoot(*beaconRoot, evm) - } - if chainConfig.IsPrague(block.Number(), block.Time()) { - core.ProcessParentBlockHash(block.ParentHash(), evm) - } + + // Run pre-execution system calls + core.PreExecution(ctx, block.BeaconRoot(), block.ParentHash(), chainConfig, evm, block.Number(), block.Time()) + for i, tx := range block.Transactions() { // Prepare the transaction for un-traced execution msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee()) @@ -795,6 +782,7 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block return nil, err } dumps = append(dumps, dump.Name()) + // Set up the tracer and EVM for the transaction. var ( writer = bufio.NewWriter(dump) diff --git a/internal/ethapi/simulate.go b/internal/ethapi/simulate.go index e3a14bf5d6..170104fbdf 100644 --- a/internal/ethapi/simulate.go +++ b/internal/ethapi/simulate.go @@ -318,12 +318,9 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, if precompiles != nil { evm.SetPrecompiles(precompiles) } - if sim.chainConfig.IsPrague(header.Number, header.Time) || sim.chainConfig.IsUBT(header.Number, header.Time) { - core.ProcessParentBlockHash(header.ParentHash, evm) - } - if header.ParentBeaconRoot != nil { - core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, evm) - } + // Run pre-execution system calls + core.PreExecution(ctx, header.ParentBeaconRoot, header.ParentHash, sim.chainConfig, evm, header.Number, header.Time) + var allLogs []*types.Log for i, call := range block.Calls { // Terminate if the context is cancelled @@ -393,22 +390,10 @@ func (sim *simulator) processBlock(ctx context.Context, block *simBlock, header, header.BlobGasUsed = &blobGasUsed } - // Process EIP-7685 requests - var requests [][]byte - if sim.chainConfig.IsPrague(header.Number, header.Time) { - requests = [][]byte{} - // EIP-6110 - if err := core.ParseDepositLogs(&requests, allLogs, sim.chainConfig); err != nil { - return nil, nil, nil, err - } - // EIP-7002 - if err := core.ProcessWithdrawalQueue(&requests, evm); err != nil { - return nil, nil, nil, err - } - // EIP-7251 - if err := core.ProcessConsolidationQueue(&requests, evm); err != nil { - return nil, nil, nil, err - } + // Run post-execution system calls + requests, err := core.PostExecution(ctx, sim.chainConfig, header.Number, header.Time, allLogs, evm) + if err != nil { + return nil, nil, nil, err } if requests != nil { reqHash := types.CalcRequestsHash(requests) diff --git a/miner/worker.go b/miner/worker.go index 42e3695025..ccafa20b29 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -208,21 +208,9 @@ func (miner *Miner) generateWork(ctx context.Context, genParam *generateParams, } // Collect consensus-layer requests if Prague is enabled. - var requests [][]byte - if miner.chainConfig.IsPrague(work.header.Number, work.header.Time) { - requests = [][]byte{} - // EIP-6110 deposits - if err := core.ParseDepositLogs(&requests, allLogs, miner.chainConfig); err != nil { - return &newPayloadResult{err: err} - } - // EIP-7002 - if err := core.ProcessWithdrawalQueue(&requests, work.evm); err != nil { - return &newPayloadResult{err: err} - } - // EIP-7251 consolidations - if err := core.ProcessConsolidationQueue(&requests, work.evm); err != nil { - return &newPayloadResult{err: err} - } + requests, err := core.PostExecution(ctx, miner.chainConfig, work.header.Number, work.header.Time, allLogs, work.evm) + if err != nil { + return &newPayloadResult{err: err} } if requests != nil { reqHash := types.CalcRequestsHash(requests) @@ -329,12 +317,8 @@ func (miner *Miner) prepareWork(ctx context.Context, genParams *generateParams, log.Error("Failed to create sealing context", "err", err) return nil, err } - if header.ParentBeaconRoot != nil { - core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, env.evm) - } - if miner.chainConfig.IsPrague(header.Number, header.Time) { - core.ProcessParentBlockHash(header.ParentHash, env.evm) - } + // Run pre-execution system calls + core.PreExecution(ctx, header.ParentBeaconRoot, header.ParentHash, miner.chainConfig, env.evm, header.Number, header.Time) return env, nil }