From 516f6c33d510e90b188a3496f82d9ada4af5b4ee Mon Sep 17 00:00:00 2001 From: lightclient Date: Wed, 27 Mar 2024 12:38:36 -0600 Subject: [PATCH] all: move 4788 syscall into separate package --- cmd/evm/internal/t8ntool/execution.go | 7 ++- core/chain_makers.go | 13 ++++-- core/state_processor.go | 28 ++---------- core/syscall/syscall.go | 66 +++++++++++++++++++++++++++ miner/worker.go | 15 ++---- 5 files changed, 86 insertions(+), 43 deletions(-) create mode 100644 core/syscall/syscall.go diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 3c09229e1c..f57ad0a4f2 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -30,6 +30,7 @@ import ( "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/syscall" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -192,10 +193,8 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig, chainConfig.DAOForkBlock.Cmp(new(big.Int).SetUint64(pre.Env.Number)) == 0 { misc.ApplyDAOHardFork(statedb) } - if beaconRoot := pre.Env.ParentBeaconBlockRoot; beaconRoot != nil { - evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig) - core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb) - } + header := &types.Header{ParentBeaconRoot: pre.Env.ParentBeaconBlockRoot, Time: pre.Env.Timestamp} + syscall.RunPreBlockHooks(header, statedb, chainConfig) for i := 0; txIt.Next(); i++ { tx, err := txIt.Tx() diff --git a/core/chain_makers.go b/core/chain_makers.go index 1c42ab0c9a..d463a93b90 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -27,6 +27,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/syscall" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/ethdb" @@ -96,12 +97,14 @@ func (b *BlockGen) Difficulty() *big.Int { // SetParentBeaconRoot sets the parent beacon root field of the generated // block. func (b *BlockGen) SetParentBeaconRoot(root common.Hash) { + if len(b.txs) != 0 { + // It's possible for a tx to call the beacon roots contract *before* the + // root is set. This would lead to successful block generation, but be + // considered invalid on import. Panic here to avoid this. + panic("parent beacon root cannot be set after txs are already applied to block") + } b.header.ParentBeaconRoot = &root - var ( - blockContext = NewEVMBlockContext(b.header, b.cm, &b.header.Coinbase) - vmenv = vm.NewEVM(blockContext, vm.TxContext{}, b.statedb, b.cm.config, vm.Config{}) - ) - ProcessBeaconBlockRoot(root, vmenv, b.statedb) + syscall.ProcessBeaconBlockRoot(b.header, b.statedb, b.cm.config) } // addTx adds a transaction to the generated block. If no coinbase has diff --git a/core/state_processor.go b/core/state_processor.go index b1a8938f67..f9a38403c6 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -25,6 +25,7 @@ import ( "github.com/ethereum/go-ethereum/consensus" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/syscall" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" "github.com/ethereum/go-ethereum/crypto" @@ -68,6 +69,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg gp = new(GasPool).AddGas(block.GasLimit()) ) + // Run all pre-block system calls. + syscall.RunPreBlockHooks(header, statedb, p.config) + // Mutate the block and state according to any hard-fork specs if p.config.DAOForkSupport && p.config.DAOForkBlock != nil && p.config.DAOForkBlock.Cmp(block.Number()) == 0 { misc.ApplyDAOHardFork(statedb) @@ -77,9 +81,7 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg vmenv = vm.NewEVM(context, vm.TxContext{}, statedb, p.config, cfg) signer = types.MakeSigner(p.config, header.Number, header.Time) ) - if beaconRoot := block.BeaconRoot(); beaconRoot != nil { - ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb) - } + // Iterate over and process the individual transactions for i, tx := range block.Transactions() { msg, err := TransactionToMessage(tx, signer, header.BaseFee) @@ -182,23 +184,3 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo vmenv := vm.NewEVM(blockContext, txContext, statedb, config, cfg) return ApplyTransactionWithEVM(msg, config, gp, statedb, header.Number, header.Hash(), tx, usedGas, vmenv) } - -// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root -// contract. This method is exported to be used in tests. -func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) { - // If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with - // the new root - msg := &Message{ - From: params.SystemAddress, - GasLimit: 30_000_000, - GasPrice: common.Big0, - GasFeeCap: common.Big0, - GasTipCap: common.Big0, - To: ¶ms.BeaconRootsAddress, - Data: beaconRoot[:], - } - vmenv.Reset(NewEVMTxContext(msg), statedb) - statedb.AddAddressToAccessList(params.BeaconRootsAddress) - _, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560) - statedb.Finalise(true) -} diff --git a/core/syscall/syscall.go b/core/syscall/syscall.go new file mode 100644 index 0000000000..e5f07c58b9 --- /dev/null +++ b/core/syscall/syscall.go @@ -0,0 +1,66 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package syscall + +import ( + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/core/vm" + "github.com/ethereum/go-ethereum/params" + "github.com/holiman/uint256" +) + +var sysTxContext = vm.TxContext{ + Origin: params.SystemAddress, + GasPrice: common.Big0, +} + +func newBlockContext(header *types.Header) vm.BlockContext { + return vm.BlockContext{ + CanTransfer: func(db vm.StateDB, addr common.Address, amount *uint256.Int) bool { return false }, + Transfer: func(vm.StateDB, common.Address, common.Address, *uint256.Int) {}, + GetHash: func(uint64) common.Hash { return common.Hash{} }, + Coinbase: common.Address{}, + BlockNumber: header.Number, + Time: header.Time, + Difficulty: common.Big0, + BaseFee: common.Big0, + BlobBaseFee: common.Big0, + GasLimit: 30_000_000, + Random: &common.Hash{}, + } +} + +// RunPreBlockHooks executes all relevant pre-block operations. It will update statedb. +func RunPreBlockHooks(header *types.Header, statedb *state.StateDB, config *params.ChainConfig) { + ProcessBeaconBlockRoot(header, statedb, config) +} + +// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root +// contract. This method is exported to be used in tests. +func ProcessBeaconBlockRoot(header *types.Header, statedb *state.StateDB, config *params.ChainConfig) { + if header.ParentBeaconRoot == nil { + return + } + // If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with + // the new root + statedb.AddAddressToAccessList(params.BeaconRootsAddress) + evm := vm.NewEVM(newBlockContext(header), sysTxContext, statedb, config, vm.Config{}) + evm.Call(vm.AccountRef(params.SystemAddress), params.BeaconRootsAddress, header.ParentBeaconRoot.Bytes(), 30_000_000, common.U2560) + statedb.Finalise(true) +} diff --git a/miner/worker.go b/miner/worker.go index 9f8d9f663f..a56ba74339 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -28,6 +28,7 @@ import ( "github.com/ethereum/go-ethereum/consensus/misc/eip4844" "github.com/ethereum/go-ethereum/core" "github.com/ethereum/go-ethereum/core/state" + "github.com/ethereum/go-ethereum/core/syscall" "github.com/ethereum/go-ethereum/core/txpool" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/core/vm" @@ -190,17 +191,7 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error) // Could potentially happen if starting to mine in an odd state. // Note genParams.coinbase can be different with header.Coinbase // since clique algorithm can modify the coinbase field in header. - env, err := miner.makeEnv(parent, header, genParams.coinbase) - if err != nil { - log.Error("Failed to create sealing context", "err", err) - return nil, err - } - if header.ParentBeaconRoot != nil { - context := core.NewEVMBlockContext(header, miner.chain, nil) - vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{}) - core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state) - } - return env, nil + return miner.makeEnv(parent, header, genParams.coinbase) } // makeEnv creates a new environment for the sealing block. @@ -211,6 +202,8 @@ func (miner *Miner) makeEnv(parent *types.Header, header *types.Header, coinbase if err != nil { return nil, err } + syscall.RunPreBlockHooks(header, state, miner.chainConfig) + // Note the passed coinbase may be different with header.Coinbase. return &environment{ signer: types.MakeSigner(miner.chainConfig, header.Number, header.Time),