diff --git a/build/checksums.txt b/build/checksums.txt index 26e9eb2678..5efe9dd96f 100644 --- a/build/checksums.txt +++ b/build/checksums.txt @@ -5,10 +5,10 @@ # https://github.com/ethereum/execution-spec-tests/releases/download/v5.1.0 a3192784375acec7eaec492799d5c5d0c47a2909a3cc40178898e4ecd20cc416 fixtures_develop.tar.gz -# version:spec-tests-bal v5.2.0 +# version:spec-tests-bal v5.3.0 # https://github.com/ethereum/execution-spec-tests/releases -# https://github.com/ethereum/execution-spec-tests/releases/download/bal%40v5.2.0 -a0dc6f4070da4dab4831f4e8fddfc087c10a5120a6a683257e963d9c6713378a fixtures_bal.tar.gz +# https://github.com/ethereum/execution-spec-tests/releases/download/bal%40v5.3.0 +a1840f2e74d7d53f9f36f969bfd280407829b21e85bea206ba907453fdc47ac4 fixtures_bal.tar.gz # version:golang 1.25.7 # https://go.dev/dl/ diff --git a/cmd/evm/internal/t8ntool/transaction.go b/cmd/evm/internal/t8ntool/transaction.go index 3a457eeaec..daf853b2e6 100644 --- a/cmd/evm/internal/t8ntool/transaction.go +++ b/cmd/evm/internal/t8ntool/transaction.go @@ -133,15 +133,16 @@ func Transaction(ctx *cli.Context) error { } // Check intrinsic gas rules := chainConfig.Rules(common.Big0, true, 0) - gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) + gasCostPerStateByte := core.CostPerStateByte(&types.Header{}, chainConfig) + gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules, gasCostPerStateByte) if err != nil { r.Error = err results = append(results, r) continue } - r.IntrinsicGas = gas - if tx.Gas() < gas { - r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrIntrinsicGas, tx.Gas(), gas) + r.IntrinsicGas = gas.RegularGas + if tx.Gas() < gas.RegularGas { + r.Error = fmt.Errorf("%w: have %d, want %d", core.ErrIntrinsicGas, tx.Gas(), gas.RegularGas) results = append(results, r) continue } diff --git a/core/bench_test.go b/core/bench_test.go index 932188f8e2..27f17f30c1 100644 --- a/core/bench_test.go +++ b/core/bench_test.go @@ -89,7 +89,8 @@ func genValueTx(nbytes int) func(int, *BlockGen) { data := make([]byte, nbytes) return func(i int, gen *BlockGen) { toaddr := common.Address{} - gas, _ := IntrinsicGas(data, nil, nil, false, false, false, false) + gasCostPerStateByte := CostPerStateByte(gen.header, gen.cm.config) + gas, _ := IntrinsicGas(data, nil, nil, false, params.Rules{}, gasCostPerStateByte) signer := gen.Signer() gasPrice := big.NewInt(0) if gen.header.BaseFee != nil { @@ -99,7 +100,7 @@ func genValueTx(nbytes int) func(int, *BlockGen) { Nonce: gen.TxNonce(benchRootAddr), To: &toaddr, Value: big.NewInt(1), - Gas: gas, + Gas: gas.RegularGas, Data: data, GasPrice: gasPrice, }) diff --git a/core/bintrie_witness_test.go b/core/bintrie_witness_test.go index 7704ba41fb..fded3c37fd 100644 --- a/core/bintrie_witness_test.go +++ b/core/bintrie_witness_test.go @@ -63,12 +63,12 @@ var ( func TestProcessVerkle(t *testing.T) { var ( code = common.FromHex(`6060604052600a8060106000396000f360606040526008565b00`) - intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, nil, true, true, true, true) + intrinsicContractCreationGas, _ = IntrinsicGas(code, nil, nil, true, params.Rules{IsHomestead: true, IsIstanbul: true, IsShanghai: true}, 0) // A contract creation that calls EXTCODECOPY in the constructor. Used to ensure that the witness // will not contain that copied data. // Source: https://gist.github.com/gballet/a23db1e1cb4ed105616b5920feb75985 codeWithExtCodeCopy = common.FromHex(`0x60806040526040516100109061017b565b604051809103906000f08015801561002c573d6000803e3d6000fd5b506000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555034801561007857600080fd5b5060008067ffffffffffffffff8111156100955761009461024a565b5b6040519080825280601f01601f1916602001820160405280156100c75781602001600182028036833780820191505090505b50905060008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1690506020600083833c81610101906101e3565b60405161010d90610187565b61011791906101a3565b604051809103906000f080158015610133573d6000803e3d6000fd5b50600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff160217905550505061029b565b60d58061046783390190565b6102068061053c83390190565b61019d816101d9565b82525050565b60006020820190506101b86000830184610194565b92915050565b6000819050602082019050919050565b600081519050919050565b6000819050919050565b60006101ee826101ce565b826101f8846101be565b905061020381610279565b925060208210156102435761023e7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8360200360080261028e565b831692505b5050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600061028582516101d9565b80915050919050565b600082821b905092915050565b6101bd806102aa6000396000f3fe608060405234801561001057600080fd5b506004361061002b5760003560e01c8063f566852414610030575b600080fd5b61003861004e565b6040516100459190610146565b60405180910390f35b6000600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff166381ca91d36040518163ffffffff1660e01b815260040160206040518083038186803b1580156100b857600080fd5b505afa1580156100cc573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906100f0919061010a565b905090565b60008151905061010481610170565b92915050565b6000602082840312156101205761011f61016b565b5b600061012e848285016100f5565b91505092915050565b61014081610161565b82525050565b600060208201905061015b6000830184610137565b92915050565b6000819050919050565b600080fd5b61017981610161565b811461018457600080fd5b5056fea2646970667358221220a6a0e11af79f176f9c421b7b12f441356b25f6489b83d38cc828a701720b41f164736f6c63430008070033608060405234801561001057600080fd5b5060b68061001f6000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c8063ab5ed15014602d575b600080fd5b60336047565b604051603e9190605d565b60405180910390f35b60006001905090565b6057816076565b82525050565b6000602082019050607060008301846050565b92915050565b600081905091905056fea26469706673582212203a14eb0d5cd07c277d3e24912f110ddda3e553245a99afc4eeefb2fbae5327aa64736f6c63430008070033608060405234801561001057600080fd5b5060405161020638038061020683398181016040528101906100329190610063565b60018160001c6100429190610090565b60008190555050610145565b60008151905061005d8161012e565b92915050565b60006020828403121561007957610078610129565b5b60006100878482850161004e565b91505092915050565b600061009b826100f0565b91506100a6836100f0565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff038211156100db576100da6100fa565b5b828201905092915050565b6000819050919050565b6000819050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600080fd5b610137816100e6565b811461014257600080fd5b50565b60b3806101536000396000f3fe6080604052348015600f57600080fd5b506004361060285760003560e01c806381ca91d314602d575b600080fd5b60336047565b604051603e9190605a565b60405180910390f35b60005481565b6054816073565b82525050565b6000602082019050606d6000830184604d565b92915050565b600081905091905056fea26469706673582212209bff7098a2f526de1ad499866f27d6d0d6f17b74a413036d6063ca6a0998ca4264736f6c63430008070033`) - intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, nil, true, true, true, true) + intrinsicCodeWithExtCodeCopyGas, _ = IntrinsicGas(codeWithExtCodeCopy, nil, nil, true, params.Rules{IsHomestead: true, IsIstanbul: true, IsShanghai: true}, 0) signer = types.LatestSigner(testVerkleChainConfig) testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291") bcdb = rawdb.NewMemoryDatabase() // Database for the blockchain @@ -97,11 +97,11 @@ func TestProcessVerkle(t *testing.T) { txCost1 := params.TxGas txCost2 := params.TxGas - contractCreationCost := intrinsicContractCreationGas + + contractCreationCost := intrinsicContractCreationGas.RegularGas + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation */ params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* creation with value */ 739 /* execution costs */ - codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas + + codeWithExtCodeCopyGas := intrinsicCodeWithExtCodeCopyGas.RegularGas + params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (tx) */ params.WitnessChunkReadCost + params.WitnessChunkWriteCost + params.WitnessBranchReadCost + params.WitnessBranchWriteCost + /* creation (CREATE at pc=0x20) */ params.WitnessChunkReadCost + params.WitnessChunkWriteCost + /* write code hash */ @@ -199,7 +199,7 @@ func TestProcessParentBlockHash(t *testing.T) { if isVerkle { chainConfig = testVerkleChainConfig } - vmContext := NewEVMBlockContext(header, nil, new(common.Address)) + vmContext := NewEVMBlockContext(header, &BlockChain{chainConfig: chainConfig}, new(common.Address)) evm := vm.NewEVM(vmContext, statedb, chainConfig, vm.Config{}) ProcessParentBlockHash(header.ParentHash, evm) } diff --git a/core/block_validator.go b/core/block_validator.go index 3a5379d1a9..63047d0941 100644 --- a/core/block_validator.go +++ b/core/block_validator.go @@ -49,7 +49,7 @@ func NewBlockValidator(config *params.ChainConfig, blockchain *BlockChain) *Bloc // validated at this point. func (v *BlockValidator) ValidateBody(block *types.Block) error { // check EIP 7934 RLP-encoded block size cap - if v.config.IsOsaka(block.Number(), block.Time()) && block.Size() > params.MaxBlockSize { + if v.config.IsOsaka(block.Number(), block.Time()) && block.ConsensusSize() > params.MaxBlockSize { return ErrBlockOversized } // Check whether the block is already imported. diff --git a/core/blockchain.go b/core/blockchain.go index d88687c245..6345e05609 100644 --- a/core/blockchain.go +++ b/core/blockchain.go @@ -2418,6 +2418,11 @@ func (bc *BlockChain) ProcessBlock(ctx context.Context, parentRoot common.Hash, bc.reportBadBlock(block, res, err) return nil, err } + // EIP-7928: Validate BAL items do not exceed block gas limit + if err := computedAccessList.ValidateGasLimit(block.Header().GasLimit); err != nil { + bc.reportBadBlock(block, res, err) + return nil, err + } if block.AccessList() == nil { // attach the computed access list to the block so it gets persisted // when the block is written to disk diff --git a/core/blockchain_test.go b/core/blockchain_test.go index ce7e60f71e..30a0685f6d 100644 --- a/core/blockchain_test.go +++ b/core/blockchain_test.go @@ -3866,7 +3866,8 @@ func TestTransientStorageReset(t *testing.T) { Data: initCode, }) nonce++ - b.AddTxWithVMConfig(tx, vmConfig) + bc := &BlockChain{chainConfig: gspec.Config} + b.AddTxWithVMConfig(bc, tx, vmConfig) tx, _ = types.SignNewTx(key, signer, &types.LegacyTx{ Nonce: nonce, @@ -3874,7 +3875,7 @@ func TestTransientStorageReset(t *testing.T) { Gas: 100000, To: &destAddress, }) - b.AddTxWithVMConfig(tx, vmConfig) + b.AddTxWithVMConfig(bc, tx, vmConfig) nonce++ }) diff --git a/core/chain_makers.go b/core/chain_makers.go index 7d8f42e48f..c9ed6e7045 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -164,8 +164,8 @@ func (b *BlockGen) AddTxWithChain(bc *BlockChain, tx *types.Transaction) { // AddTxWithVMConfig adds a transaction to the generated block. If no coinbase has // been set, the block's coinbase is set to the zero address. // The evm interpreter can be customized with the provided vm config. -func (b *BlockGen) AddTxWithVMConfig(tx *types.Transaction, config vm.Config) { - b.addTx(nil, config, tx) +func (b *BlockGen) AddTxWithVMConfig(bc *BlockChain, tx *types.Transaction, config vm.Config) { + b.addTx(bc, config, tx) } // GetBalance returns the balance of the given address at the generated block. diff --git a/core/evm.go b/core/evm.go index c79ef205cf..b76502e181 100644 --- a/core/evm.go +++ b/core/evm.go @@ -68,21 +68,33 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common } return vm.BlockContext{ - CanTransfer: CanTransfer, - Transfer: Transfer, - GetHash: GetHashFn(header, chain), - Coinbase: beneficiary, - BlockNumber: new(big.Int).Set(header.Number), - Time: header.Time, - Difficulty: new(big.Int).Set(header.Difficulty), - BaseFee: baseFee, - BlobBaseFee: blobBaseFee, - GasLimit: header.GasLimit, - Random: random, - SlotNum: slotNum, + CanTransfer: CanTransfer, + Transfer: Transfer, + GetHash: GetHashFn(header, chain), + Coinbase: beneficiary, + BlockNumber: new(big.Int).Set(header.Number), + Time: header.Time, + Difficulty: new(big.Int).Set(header.Difficulty), + BaseFee: baseFee, + BlobBaseFee: blobBaseFee, + GasLimit: header.GasLimit, + Random: random, + SlotNum: slotNum, + CostPerGasByte: CostPerStateByte(header, chain.Config()), } } +// CostPerStateByte computes the cost per one byte of state creation +// after EIP-8037 +func CostPerStateByte(header *types.Header, config *params.ChainConfig) uint64 { + if config.IsAmsterdam(header.Number, header.Time) { + return 1174 + // TODO (MariusVanDerWijden): for devnet-3 we hardcode the costPerStateByte + //return ((header.GasLimit / 2) * 7200 * 365) / params.TargetStateGrowthPerYear + } + return 0 +} + // NewEVMTxContext creates a new transaction context for a single transaction. func NewEVMTxContext(msg *Message) vm.TxContext { ctx := vm.TxContext{ diff --git a/core/gaspool.go b/core/gaspool.go index 14f5abd93c..690882c7b1 100644 --- a/core/gaspool.go +++ b/core/gaspool.go @@ -27,6 +27,11 @@ type GasPool struct { remaining uint64 initial uint64 cumulativeUsed uint64 + + // EIP-8037: per-dimension cumulative sums for Amsterdam. + // Block gas used = max(cumulativeRegular, cumulativeState). + cumulativeRegular uint64 + cumulativeState uint64 } // NewGasPool initializes the gasPool with the given amount. @@ -68,20 +73,41 @@ func (gp *GasPool) ReturnGas(returned uint64, gasUsed uint64) error { return nil } +// ReturnGasAmsterdam handles 2D gas accounting for Amsterdam (EIP-8037). +// It undoes the SubGas deduction fully and accumulates per-dimension block totals. +func (gp *GasPool) ReturnGasAmsterdam(returned, txRegular, txState, receiptGasUsed uint64) error { + if gp.remaining > math.MaxUint64-returned { + return fmt.Errorf("%w: remaining: %d, returned: %d", ErrGasLimitOverflow, gp.remaining, returned) + } + // Undo SubGas deduction fully (Amsterdam uses cumulative tracking) + gp.remaining += returned + // Accumulate 2D block dimensions + gp.cumulativeRegular += txRegular + gp.cumulativeState += txState + gp.cumulativeUsed += receiptGasUsed + return nil +} + // Gas returns the amount of gas remaining in the pool. func (gp *GasPool) Gas() uint64 { return gp.remaining } -// CumulativeUsed returns the amount of cumulative consumed gas (refunded included). +// CumulativeUsed returns the cumulative gas consumed for receipt tracking. +// For Amsterdam blocks, this is the sum of per-tx tx_gas_used_after_refund +// (what users pay), not the 2D block-level metric. func (gp *GasPool) CumulativeUsed() uint64 { return gp.cumulativeUsed } -// Used returns the amount of consumed gas. +// Used returns the amount of consumed gas. For Amsterdam blocks with +// 2D gas accounting (EIP-8037), returns max(sum_regular, sum_state). func (gp *GasPool) Used() uint64 { + if gp.cumulativeRegular > 0 || gp.cumulativeState > 0 { + return max(gp.cumulativeRegular, gp.cumulativeState) + } if gp.initial < gp.remaining { - panic("gas used underflow") + panic(fmt.Sprintf("gas used underflow: %v %v", gp.initial, gp.remaining)) } return gp.initial - gp.remaining } @@ -89,9 +115,11 @@ func (gp *GasPool) Used() uint64 { // Snapshot returns the deep-copied object as the snapshot. func (gp *GasPool) Snapshot() *GasPool { return &GasPool{ - initial: gp.initial, - remaining: gp.remaining, - cumulativeUsed: gp.cumulativeUsed, + initial: gp.initial, + remaining: gp.remaining, + cumulativeUsed: gp.cumulativeUsed, + cumulativeRegular: gp.cumulativeRegular, + cumulativeState: gp.cumulativeState, } } @@ -100,6 +128,14 @@ func (gp *GasPool) Set(other *GasPool) { gp.initial = other.initial gp.remaining = other.remaining gp.cumulativeUsed = other.cumulativeUsed + gp.cumulativeRegular = other.cumulativeRegular + gp.cumulativeState = other.cumulativeState +} + +// AmsterdamDimensions returns the per-dimension cumulative gas values +// for 2D gas accounting (EIP-8037). +func (gp *GasPool) AmsterdamDimensions() (regular, state uint64) { + return gp.cumulativeRegular, gp.cumulativeState } func (gp *GasPool) String() string { diff --git a/core/parallel_state_processor.go b/core/parallel_state_processor.go index 5e72dd4e6e..cb82a674c6 100644 --- a/core/parallel_state_processor.go +++ b/core/parallel_state_processor.go @@ -95,28 +95,25 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, tExecStar }) var ( - // total gas used not applying refunds - blockGas = uint64(0) - // total gas used applying refunds - execGas = uint64(0) + // Per-dimension cumulative sums for 2D block gas (EIP-8037). + sumRegular uint64 + sumState uint64 + cumulativeReceipt uint64 // cumulative receipt gas (what users pay) ) var allLogs []*types.Log var allReceipts []*types.Receipt for _, result := range results { - blockGas += result.blockGas - execGas += result.execGas - result.receipt.CumulativeGasUsed = blockGas - if blockGas > header.GasLimit { - return &ProcessResultWithMetrics{ - ProcessResult: &ProcessResult{Error: fmt.Errorf("gas limit exceeded")}, - } - } + sumRegular += result.txRegular + sumState += result.txState + cumulativeReceipt += result.execGas + result.receipt.CumulativeGasUsed = cumulativeReceipt allLogs = append(allLogs, result.receipt.Logs...) allReceipts = append(allReceipts, result.receipt) } - // Block gas limit is enforced against usedGas (pre-refund after Amsterdam, post-refund before). - if blockGas > header.GasLimit { + // Block gas = max(sum_regular, sum_state) per EIP-8037. + blockGasUsed := max(sumRegular, sumState) + if blockGasUsed > header.GasLimit { return &ProcessResultWithMetrics{ ProcessResult: &ProcessResult{Error: fmt.Errorf("gas limit exceeded")}, } @@ -177,7 +174,7 @@ func (p *ParallelStateProcessor) prepareExecResult(block *types.Block, tExecStar Receipts: allReceipts, Requests: requests, Logs: allLogs, - GasUsed: execGas, + GasUsed: blockGasUsed, }, PostProcessTime: tPostprocess, ExecTime: tExec, @@ -191,6 +188,10 @@ type txExecResult struct { blockGas uint64 execGas uint64 + // Per-tx dimensional gas for Amsterdam 2D gas accounting (EIP-8037). + txRegular uint64 + txState uint64 + stateReads bal.StateAccesses } @@ -292,7 +293,6 @@ func (p *ParallelStateProcessor) execTx(block *types.Block, tx *types.Transactio gp := NewGasPool(block.GasLimit()) db.SetTxContext(tx.Hash(), balIdx-1) - var gasUsed uint64 mut, receipt, err := ApplyTransactionWithEVM(msg, gp, db, block.Number(), block.Hash(), context.Time, tx, evm) if err != nil { err := fmt.Errorf("could not apply tx %d [%v]: %w", balIdx, tx.Hash().Hex(), err) @@ -305,11 +305,14 @@ func (p *ParallelStateProcessor) execTx(block *types.Block, tx *types.Transactio return &txExecResult{err: err} } + txRegular, txState := gp.AmsterdamDimensions() return &txExecResult{ idx: balIdx, receipt: receipt, execGas: receipt.GasUsed, - blockGas: gasUsed, + blockGas: gp.Used(), + txRegular: txRegular, + txState: txState, stateReads: db.Reader().(state.StateReaderTracker).GetStateAccessList(), } } diff --git a/core/state_processor.go b/core/state_processor.go index 89487feb1e..e6533ad05a 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -19,10 +19,11 @@ package core import ( "context" "fmt" - "github.com/ethereum/go-ethereum/core/types/bal" "math/big" "sort" + "github.com/ethereum/go-ethereum/core/types/bal" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/consensus/misc" "github.com/ethereum/go-ethereum/core/state" @@ -297,7 +298,7 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, evm *vm.EVM) bal.StateMutati } evm.SetTxContext(NewEVMTxContext(msg)) evm.StateDB.AddAddressToAccessList(params.BeaconRootsAddress) - _, _, _ = evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) + _, _, _ = evm.Call(msg.From, *msg.To, msg.Data, vm.GasCosts{RegularGas: 30_000_000}, common.U2560) return evm.StateDB.Finalise(true) } @@ -321,7 +322,7 @@ func ProcessParentBlockHash(prevHash common.Hash, evm *vm.EVM) bal.StateMutation } evm.SetTxContext(NewEVMTxContext(msg)) evm.StateDB.AddAddressToAccessList(params.HistoryStorageAddress) - _, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) + _, _, err := evm.Call(msg.From, *msg.To, msg.Data, vm.GasCosts{RegularGas: 30_000_000}, common.U2560) if err != nil { panic(err) } @@ -361,7 +362,7 @@ func processRequestsSystemCall(requests *[][]byte, evm *vm.EVM, requestType byte } evm.SetTxContext(NewEVMTxContext(msg)) evm.StateDB.AddAddressToAccessList(addr) - ret, _, err := evm.Call(msg.From, *msg.To, msg.Data, 30_000_000, common.U2560) + ret, _, err := evm.Call(msg.From, *msg.To, msg.Data, vm.GasCosts{RegularGas: 30_000_000}, common.U2560) mut := evm.StateDB.Finalise(true) if err != nil { return nil, fmt.Errorf("system call failed to execute: %v", err) diff --git a/core/state_transition.go b/core/state_transition.go index 21a29173ed..614e279e4e 100644 --- a/core/state_transition.go +++ b/core/state_transition.go @@ -19,6 +19,9 @@ package core import ( "bytes" "fmt" + "math" + "math/big" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/tracing" "github.com/ethereum/go-ethereum/core/types" @@ -26,8 +29,6 @@ import ( "github.com/ethereum/go-ethereum/crypto/kzg4844" "github.com/ethereum/go-ethereum/params" "github.com/holiman/uint256" - "math" - "math/big" ) // ExecutionResult includes all output after executing given evm @@ -67,13 +68,20 @@ func (result *ExecutionResult) Revert() []byte { } // IntrinsicGas computes the 'intrinsic gas' for a message with the given data. -func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.SetCodeAuthorization, isContractCreation, isHomestead, isEIP2028, isEIP3860 bool) (uint64, error) { +// costPerStateByte needs to be set post-Amsterdam. +func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.SetCodeAuthorization, isContractCreation bool, rules params.Rules, costPerStateByte uint64) (vm.GasCosts, error) { // Set the starting gas for the raw transaction - var gas uint64 - if isContractCreation && isHomestead { - gas = params.TxGasContractCreation + var gas vm.GasCosts + if isContractCreation && rules.IsHomestead { + if rules.IsAmsterdam { + // EIP-8037: account creation is state gas; base tx + CREATE overhead is regular gas. + gas.RegularGas = params.TxGas + params.CreateGasAmsterdam + gas.StateGas = params.AccountCreationSize * costPerStateByte + } else { + gas.RegularGas = params.TxGasContractCreation + } } else { - gas = params.TxGas + gas.RegularGas = params.TxGas } dataLen := uint64(len(data)) // Bump the required gas by the amount of transactional data @@ -84,33 +92,38 @@ func IntrinsicGas(data []byte, accessList types.AccessList, authList []types.Set // Make sure we don't exceed uint64 for all data combinations nonZeroGas := params.TxDataNonZeroGasFrontier - if isEIP2028 { + if rules.IsIstanbul { nonZeroGas = params.TxDataNonZeroGasEIP2028 } - if (math.MaxUint64-gas)/nonZeroGas < nz { - return 0, ErrGasUintOverflow + if (math.MaxUint64-gas.RegularGas)/nonZeroGas < nz { + return vm.GasCosts{}, ErrGasUintOverflow } - gas += nz * nonZeroGas + gas.RegularGas += nz * nonZeroGas - if (math.MaxUint64-gas)/params.TxDataZeroGas < z { - return 0, ErrGasUintOverflow + if (math.MaxUint64-gas.RegularGas)/params.TxDataZeroGas < z { + return vm.GasCosts{}, ErrGasUintOverflow } - gas += z * params.TxDataZeroGas + gas.RegularGas += z * params.TxDataZeroGas - if isContractCreation && isEIP3860 { + if isContractCreation && rules.IsShanghai { lenWords := toWordSize(dataLen) - if (math.MaxUint64-gas)/params.InitCodeWordGas < lenWords { - return 0, ErrGasUintOverflow + if (math.MaxUint64-gas.RegularGas)/params.InitCodeWordGas < lenWords { + return vm.GasCosts{}, ErrGasUintOverflow } - gas += lenWords * params.InitCodeWordGas + gas.RegularGas += lenWords * params.InitCodeWordGas } } if accessList != nil { - gas += uint64(len(accessList)) * params.TxAccessListAddressGas - gas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas + gas.RegularGas += uint64(len(accessList)) * params.TxAccessListAddressGas + gas.RegularGas += uint64(accessList.StorageKeys()) * params.TxAccessListStorageKeyGas } if authList != nil { - gas += uint64(len(authList)) * params.CallNewAccountGas + if rules.IsAmsterdam { + gas.RegularGas += uint64(len(authList)) * params.TxAuthTupleRegularGas + gas.StateGas += uint64(len(authList)) * (params.AuthorizationCreationSize + params.AccountCreationSize) * costPerStateByte + } else { + gas.RegularGas += uint64(len(authList)) * params.CallNewAccountGas + } } return gas, nil } @@ -243,8 +256,8 @@ func ApplyMessage(evm *vm.EVM, msg *Message, gp *GasPool) (*ExecutionResult, err type stateTransition struct { gp *GasPool msg *Message - gasRemaining uint64 - initialGas uint64 + gasRemaining vm.GasCosts + initialGas vm.GasCosts state vm.StateDB evm *vm.EVM } @@ -303,9 +316,14 @@ func (st *stateTransition) buyGas() error { if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil { st.evm.Config.Tracer.OnGasChange(0, st.msg.GasLimit, tracing.GasChangeTxInitialBalance) } - st.gasRemaining = st.msg.GasLimit - st.initialGas = st.msg.GasLimit + st.gasRemaining.RegularGas = st.msg.GasLimit + // After Amsterdam we limit the regular gas to 16k, the data gas to the transaction limit + limit := st.msg.GasLimit + if st.evm.ChainConfig().IsAmsterdam(st.evm.Context.BlockNumber, st.evm.Context.Time) { + limit = min(st.msg.GasLimit, params.MaxTxGas) + } + st.initialGas = vm.GasCosts{RegularGas: limit, StateGas: st.msg.GasLimit - limit} mgvalU256, _ := uint256.FromBig(mgval) st.state.SubBalance(st.msg.From, mgvalU256, tracing.BalanceDecreaseGasBuy) return nil @@ -329,9 +347,10 @@ func (st *stateTransition) preCheck() error { } } isOsaka := st.evm.ChainConfig().IsOsaka(st.evm.Context.BlockNumber, st.evm.Context.Time) + isAmsterdam := st.evm.ChainConfig().IsAmsterdam(st.evm.Context.BlockNumber, st.evm.Context.Time) if !msg.SkipTransactionChecks { // Verify tx gas limit does not exceed EIP-7825 cap. - if isOsaka && msg.GasLimit > params.MaxTxGas { + if !isAmsterdam && isOsaka && msg.GasLimit > params.MaxTxGas { return fmt.Errorf("%w (cap: %d, tx: %d)", ErrGasLimitTooHigh, params.MaxTxGas, msg.GasLimit) } // Make sure the sender is an EOA @@ -447,13 +466,26 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { ) // Check clauses 4-5, subtract intrinsic gas if everything is correct - gas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.SetCodeAuthorizations, contractCreation, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) + gas, err := IntrinsicGas(msg.Data, msg.AccessList, msg.SetCodeAuthorizations, contractCreation, rules, st.evm.Context.CostPerGasByte) if err != nil { return nil, err } - if st.gasRemaining < gas { - return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining, gas) + if rules.IsAmsterdam { + // EIP-8037: total intrinsic must fit within the transaction gas limit. + if msg.GasLimit < gas.Sum() { + return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, msg.GasLimit, gas.Sum()) + } + // Split remaining execution gas into regular and state reservoir. + executionGas := msg.GasLimit - gas.Sum() + regularGas := min(params.MaxTxGas-gas.RegularGas, executionGas) + st.gasRemaining = vm.GasCosts{RegularGas: regularGas, StateGas: executionGas - regularGas} + } else { + if st.gasRemaining.Underflow(gas) { + return nil, fmt.Errorf("%w: have %d, want %d", ErrIntrinsicGas, st.gasRemaining.RegularGas, gas.RegularGas) + } + st.gasRemaining.Sub(gas) } + // Gas limit suffices for the floor data cost (EIP-7623) if rules.IsPrague { floorDataGas, err = FloorDataGas(msg.Data) @@ -465,9 +497,12 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { } } if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { - t.OnGasChange(st.gasRemaining, st.gasRemaining-gas, tracing.GasChangeTxIntrinsicGas) + if rules.IsAmsterdam { + t.OnGasChange(msg.GasLimit, st.gasRemaining.RegularGas+st.gasRemaining.StateGas, tracing.GasChangeTxIntrinsicGas) + } else { + t.OnGasChange(st.gasRemaining.RegularGas+gas.RegularGas, st.gasRemaining.RegularGas, tracing.GasChangeTxIntrinsicGas) + } } - st.gasRemaining -= gas if rules.IsEIP4762 { st.evm.AccessEvents.AddTxOrigin(msg.From) @@ -499,8 +534,9 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { st.state.Prepare(rules, msg.From, st.evm.Context.Coinbase, msg.To, vm.ActivePrecompiles(rules), msg.AccessList) var ( - ret []byte - vmerr error // vm errors do not effect consensus and are therefore not assigned to err + ret []byte + vmerr error // vm errors do not effect consensus and are therefore not assigned to err + authRefund uint64 ) if contractCreation { ret, _, st.gasRemaining, vmerr = st.evm.Create(msg.From, msg.Data, st.gasRemaining, value) @@ -512,7 +548,8 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { if msg.SetCodeAuthorizations != nil { for _, auth := range msg.SetCodeAuthorizations { // Note errors are ignored, we simply skip invalid authorizations here. - st.applyAuthorization(&auth) + refund, _ := st.applyAuthorization(rules, &auth) + authRefund += refund } } @@ -533,34 +570,48 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { // gas allowance required to complete execution. peakGasUsed := st.gasUsed() + // EIP-8037: Capture pre-refund remaining for 2D gas accounting. + var preRefundRemaining uint64 + if rules.IsAmsterdam { + preRefundRemaining = st.gasRemaining.Sum() + } + // Compute refund counter, capped to a refund quotient. - st.gasRemaining += st.calcRefund() + st.gasRemaining.RegularGas += st.calcRefund() if rules.IsPrague { // After EIP-7623: Data-heavy transactions pay the floor gas. if st.gasUsed() < floorDataGas { - prev := st.gasRemaining - st.gasRemaining = st.initialGas - floorDataGas + prev := st.gasRemaining.RegularGas + // When the calldata floor exceeds actual gas used, any + // remaining state gas must also be consumed + targetRemaining := (st.initialGas.RegularGas + st.initialGas.StateGas) - floorDataGas + st.gasRemaining.StateGas = 0 + st.gasRemaining.RegularGas = targetRemaining if t := st.evm.Config.Tracer; t != nil && t.OnGasChange != nil { - t.OnGasChange(prev, st.gasRemaining, tracing.GasChangeTxDataFloor) + t.OnGasChange(prev, st.gasRemaining.RegularGas, tracing.GasChangeTxDataFloor) } } if peakGasUsed < floorDataGas { peakGasUsed = floorDataGas } } - // Return gas to the user - st.returnGas() - // Return gas to the gas pool + returned := st.returnGas() + if rules.IsAmsterdam { - // Refund is excluded for returning - err = st.gp.ReturnGas(st.initialGas-peakGasUsed, st.gasUsed()) + // EIP-8037: 2D gas accounting for Amsterdam. + // tx_state = adjusted_intrinsic_state + exec_state_used (spec: set_delegation adjusts intrinsic) + // tx_regular = total_dimensional_used - tx_state + txState := (gas.StateGas - authRefund) + st.gasRemaining.StateGasCharged + txRegular := (msg.GasLimit - preRefundRemaining) - txState - st.evm.CollisionBurned + txRegular = max(txRegular, floorDataGas) + if err := st.gp.ReturnGasAmsterdam(returned, txRegular, txState, st.gasUsed()); err != nil { + return nil, err + } } else { - // Refund is included for returning - err = st.gp.ReturnGas(st.gasRemaining, st.gasUsed()) - } - if err != nil { - return nil, err + if err := st.gp.ReturnGas(returned, st.gasUsed()); err != nil { + return nil, err + } } effectiveTip := msg.GasPrice if rules.IsLondon { @@ -573,7 +624,9 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { // are 0. This avoids a negative effectiveTip being applied to // the coinbase when simulating calls. } else { - fee := new(uint256.Int).SetUint64(st.gasUsed()) + // For Amsterdam, the fee is based on what the user pays (receipt gas used). + feeGas := st.gasUsed() + fee := new(uint256.Int).SetUint64(feeGas) fee.Mul(fee, effectiveTipU256) // always read the coinbase account to include it in the BAL (TODO check this is actually part of the spec) @@ -586,8 +639,9 @@ func (st *stateTransition) execute() (*ExecutionResult, error) { st.evm.AccessEvents.AddAccount(st.evm.Context.Coinbase, true, math.MaxUint64) } } + usedGas := st.gasUsed() return &ExecutionResult{ - UsedGas: peakGasUsed, + UsedGas: usedGas, MaxUsedGas: peakGasUsed, Err: vmerr, ReturnData: ret, @@ -626,16 +680,23 @@ func (st *stateTransition) validateAuthorization(auth *types.SetCodeAuthorizatio } // applyAuthorization applies an EIP-7702 code delegation to the state. -func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization) error { +func (st *stateTransition) applyAuthorization(rules params.Rules, auth *types.SetCodeAuthorization) (uint64, error) { authority, err := st.validateAuthorization(auth) if err != nil { - return err + return 0, err } // If the account already exists in state, refund the new account cost // charged in the intrinsic calculation. + var refund uint64 if st.state.Exist(authority) { - st.state.AddRefund(params.CallNewAccountGas - params.TxAuthTupleGas) + if rules.IsAmsterdam { + // EIP-8037: refund account creation state gas to the reservoir + refund = params.AccountCreationSize * st.evm.Context.CostPerGasByte + st.gasRemaining.StateGas += refund + } else { + st.state.AddRefund(params.CallNewAccountGas - params.TxAuthTupleGas) + } } prevDelegation, isDelegated := types.ParseDelegation(st.state.GetCode(authority)) @@ -647,7 +708,7 @@ func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization) if isDelegated { st.state.SetCode(authority, nil, tracing.CodeChangeAuthorizationClear) } - return nil + return refund, nil } // install delegation to auth.Address if the delegation changed @@ -655,7 +716,7 @@ func (st *stateTransition) applyAuthorization(auth *types.SetCodeAuthorization) st.state.SetCode(authority, types.AddressToDelegation(auth.Address), tracing.CodeChangeAuthorization) } - return nil + return refund, nil } // calcRefund computes refund counter, capped to a refund quotient. @@ -672,26 +733,30 @@ func (st *stateTransition) calcRefund() uint64 { refund = st.state.GetRefund() } if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && refund > 0 { - st.evm.Config.Tracer.OnGasChange(st.gasRemaining, st.gasRemaining+refund, tracing.GasChangeTxRefunds) + st.evm.Config.Tracer.OnGasChange(st.gasRemaining.RegularGas, st.gasRemaining.RegularGas+refund, tracing.GasChangeTxRefunds) } return refund } // returnGas returns ETH for remaining gas, // exchanged at the original rate. -func (st *stateTransition) returnGas() { - remaining := uint256.NewInt(st.gasRemaining) +func (st *stateTransition) returnGas() uint64 { + gas := st.gasRemaining.RegularGas + st.gasRemaining.StateGas + remaining := uint256.NewInt(gas) remaining.Mul(remaining, uint256.MustFromBig(st.msg.GasPrice)) st.state.AddBalance(st.msg.From, remaining, tracing.BalanceIncreaseGasReturn) - if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && st.gasRemaining > 0 { - st.evm.Config.Tracer.OnGasChange(st.gasRemaining, 0, tracing.GasChangeTxLeftOverReturned) + if st.evm.Config.Tracer != nil && st.evm.Config.Tracer.OnGasChange != nil && gas > 0 { + st.evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeTxLeftOverReturned) } + return gas } // gasUsed returns the amount of gas used up by the state transition. +// For Amsterdam (2D gas), this includes both regular and state gas consumed. func (st *stateTransition) gasUsed() uint64 { - return st.initialGas - st.gasRemaining + return (st.initialGas.RegularGas + st.initialGas.StateGas) - + (st.gasRemaining.RegularGas + st.gasRemaining.StateGas) } // blobGasUsed returns the amount of blob gas used by the message. diff --git a/core/txpool/validation.go b/core/txpool/validation.go index 13b1bfa312..f5d8e1d800 100644 --- a/core/txpool/validation.go +++ b/core/txpool/validation.go @@ -125,13 +125,23 @@ func ValidateTransaction(tx *types.Transaction, head *types.Header, signer types } // Ensure the transaction has more gas than the bare minimum needed to cover // the transaction metadata - intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, true, rules.IsIstanbul, rules.IsShanghai) + gasCostPerStateByte := core.CostPerStateByte(head, opts.Config) + intrGas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules, gasCostPerStateByte) if err != nil { return err } - if tx.Gas() < intrGas { - return fmt.Errorf("%w: gas %v, minimum needed %v", core.ErrIntrinsicGas, tx.Gas(), intrGas) + if gasCostPerStateByte != 0 { + // We require transactions to pay for 110% of intrinsic gas in order to + // prevent situations where a change in gas limit invalidates a lot + // of transactions in the txpool + if tx.Gas() < (intrGas.RegularGas*10)/9 { + return fmt.Errorf("%w: gas %v, minimum needed %v", core.ErrIntrinsicGas, tx.Gas(), intrGas.RegularGas) + } } + if tx.Gas() < intrGas.RegularGas { + return fmt.Errorf("%w: gas %v, minimum needed %v", core.ErrIntrinsicGas, tx.Gas(), intrGas.RegularGas) + } + // Ensure the transaction can cover floor data gas. if rules.IsPrague { floorDataGas, err := core.FloorDataGas(tx.Data()) diff --git a/core/types/bal/bal_encoding.go b/core/types/bal/bal_encoding.go index 124b7712c9..e18be842b0 100644 --- a/core/types/bal/bal_encoding.go +++ b/core/types/bal/bal_encoding.go @@ -23,12 +23,13 @@ import ( "encoding/json" "errors" "fmt" - "github.com/ethereum/go-ethereum/log" "io" "maps" "slices" "strings" + "github.com/ethereum/go-ethereum/log" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/params" @@ -131,6 +132,31 @@ func (e BlockAccessList) Validate(blockTxCount int) error { return nil } +// ValidateGasLimit checks that the total number of BAL items (addresses + +// unique storage keys) does not exceed block_gas_limit / GasBlockAccessListItem. +// See EIP-7928 validate_block_access_list_gas_limit. +func (e BlockAccessList) ValidateGasLimit(blockGasLimit uint64) error { + var balItems uint64 + for _, account := range e { + // Count each address as one item + balItems++ + // Count unique storage keys across both reads and writes + uniqueSlots := make(map[common.Hash]struct{}) + for _, sc := range account.StorageChanges { + uniqueSlots[sc.Slot.ToHash()] = struct{}{} + } + for _, sr := range account.StorageReads { + uniqueSlots[sr.ToHash()] = struct{}{} + } + balItems += uint64(len(uniqueSlots)) + } + limit := blockGasLimit / params.GasBlockAccessListItem + if balItems > limit { + return fmt.Errorf("block access list exceeds gas limit: %d items exceeds limit of %d", balItems, limit) + } + return nil +} + // Hash computes the keccak256 hash of the access list func (e *BlockAccessList) Hash() common.Hash { var enc bytes.Buffer @@ -388,10 +414,10 @@ func (e *AccountAccess) validate(blockTxCount int) error { } } - // validate that code changes could plausibly be correct (none exceed - // max code size of a contract) + // validate that code changes could plausibly be correct + // (none exceed max code size of a contract) for _, codeChange := range e.CodeChanges { - if len(codeChange.Code) > params.MaxCodeSize { + if len(codeChange.Code) > params.MaxCodeSizeAmsterdam { return fmt.Errorf("code change contained oversized code") } } diff --git a/core/types/block.go b/core/types/block.go index 1bf003d1ea..ed988ddaab 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -462,6 +462,19 @@ func (b *Block) Size() uint64 { return uint64(c) } +// ConsensusSize returns the RLP encoded size of the block without the BAL +// (block access list), which is not part of the consensus encoding. +func (b *Block) ConsensusSize() uint64 { + c := writeCounter(0) + rlp.Encode(&c, &extblock{ + Header: b.header, + Txs: b.transactions, + Uncles: b.uncles, + Withdrawals: b.withdrawals, + }) + return uint64(c) +} + // SanityCheck can be used to prevent that unbounded fields are // stuffed with junk data to add processing overhead func (b *Block) SanityCheck() error { diff --git a/core/vm/contract.go b/core/vm/contract.go index 165ca833f8..9aac8dcb03 100644 --- a/core/vm/contract.go +++ b/core/vm/contract.go @@ -42,12 +42,12 @@ type Contract struct { IsDeployment bool IsSystemCall bool - Gas uint64 + Gas GasCosts value *uint256.Int } // NewContract returns a new contract environment for the execution of EVM. -func NewContract(caller common.Address, address common.Address, value *uint256.Int, gas uint64, jumpDests JumpDestCache) *Contract { +func NewContract(caller common.Address, address common.Address, value *uint256.Int, gas GasCosts, jumpDests JumpDestCache) *Contract { // Initialize the jump analysis cache if it's nil, mostly for tests if jumpDests == nil { jumpDests = newMapJumpDests() @@ -126,26 +126,34 @@ func (c *Contract) Caller() common.Address { } // UseGas attempts the use gas and subtracts it and returns true on success -func (c *Contract) UseGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) (ok bool) { - if c.Gas < gas { +func (c *Contract) UseGas(gas GasCosts, logger *tracing.Hooks, reason tracing.GasChangeReason) (ok bool) { + if c.Gas.Underflow(gas) { return false } if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored { - logger.OnGasChange(c.Gas, c.Gas-gas, reason) + logger.OnGasChange(c.Gas.RegularGas, c.Gas.RegularGas-gas.RegularGas, reason) } - c.Gas -= gas + c.Gas.Sub(gas) return true } // RefundGas refunds gas to the contract -func (c *Contract) RefundGas(gas uint64, logger *tracing.Hooks, reason tracing.GasChangeReason) { - if gas == 0 { +func (c *Contract) RefundGas(err error, gas GasCosts, logger *tracing.Hooks, reason tracing.GasChangeReason) { + // If the preceding call errored, return the state gas + // to the parent call + if err != nil { + gas.StateGas += gas.StateGasCharged + gas.StateGasCharged = 0 + } + if gas.RegularGas == 0 && gas.StateGas == 0 && gas.StateGasCharged == 0 { return } if logger != nil && logger.OnGasChange != nil && reason != tracing.GasChangeIgnored { - logger.OnGasChange(c.Gas, c.Gas+gas, reason) + logger.OnGasChange(c.Gas.RegularGas, c.Gas.RegularGas+gas.RegularGas, reason) } - c.Gas += gas + c.Gas.RegularGas += gas.RegularGas + c.Gas.StateGas = gas.StateGas + c.Gas.StateGasCharged += gas.StateGasCharged } // Address returns the contracts address diff --git a/core/vm/eips.go b/core/vm/eips.go index 3ccd9aaaf0..8dcceaa9cc 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -44,6 +44,7 @@ var activators = map[int]func(*JumpTable){ 7939: enable7939, 8024: enable8024, 7843: enable7843, + 8037: enable8037, } // EnableEIP enables the given EIP on the config. @@ -381,8 +382,8 @@ func opExtCodeCopyEIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, er addr := common.Address(a.Bytes20()) code := evm.StateDB.GetCode(addr) paddedCodeCopy, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(code, uint64CodeOffset, length.Uint64()) - consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas) - scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified) + consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(addr, copyOffset, nonPaddedCopyLength, uint64(len(code)), false, scope.Contract.Gas.RegularGas) + scope.Contract.UseGas(GasCosts{RegularGas: consumed}, evm.Config.Tracer, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } @@ -407,8 +408,8 @@ func opPush1EIP4762(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { // touch next chunk if PUSH1 is at the boundary. if so, *pc has // advanced past this boundary. contractAddr := scope.Contract.Address() - consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) - scope.Contract.UseGas(wanted, evm.Config.Tracer, tracing.GasChangeUnspecified) + consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, *pc+1, uint64(1), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas.RegularGas) + scope.Contract.UseGas(GasCosts{RegularGas: wanted}, evm.Config.Tracer, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } @@ -435,8 +436,8 @@ func makePushEIP4762(size uint64, pushByteSize int) executionFunc { if !scope.Contract.IsDeployment && !scope.Contract.IsSystemCall { contractAddr := scope.Contract.Address() - consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas) - scope.Contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeUnspecified) + consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(contractAddr, uint64(start), uint64(pushByteSize), uint64(len(scope.Contract.Code)), false, scope.Contract.Gas.RegularGas) + scope.Contract.UseGas(GasCosts{RegularGas: consumed}, evm.Config.Tracer, tracing.GasChangeUnspecified) if consumed < wanted { return nil, ErrOutOfGas } @@ -596,3 +597,16 @@ func enable7843(jt *JumpTable) { maxStack: maxStack(0, 1), } } + +// enable8037 enables the multidimensional-metering as specified in EIP-8037. +func enable8037(jt *JumpTable) { + // EIP-8037: CREATE/CREATE2 constant gas changes from 32000 to 9000 regular; + // the account creation cost moves to state gas (in dynamicGas). + jt[CREATE].constantGas = params.CreateGasAmsterdam + jt[CREATE].dynamicGas = gasCreateEip8037 + jt[CREATE2].constantGas = params.CreateGasAmsterdam + jt[CREATE2].dynamicGas = gasCreate2Eip8037 + jt[CALL].dynamicGas = makeCallVariantGasCall(gasCall8037, gasCallStateless) + jt[SELFDESTRUCT].dynamicGas = gasSelfdestruct8037 + jt[SSTORE].dynamicGas = gasSStore8037 +} diff --git a/core/vm/evm.go b/core/vm/evm.go index dde3c43be4..53dbb8b76d 100644 --- a/core/vm/evm.go +++ b/core/vm/evm.go @@ -67,6 +67,8 @@ type BlockContext struct { BlobBaseFee *big.Int // Provides information for BLOBBASEFEE (0 if vm runs with NoBaseFee flag and 0 blob gas price) Random *common.Hash // Provides information for PREVRANDAO SlotNum uint64 // Provides information for SLOTNUM + + CostPerGasByte uint64 // EIP-8037 } // TxContext provides the EVM with information about a transaction. @@ -127,6 +129,14 @@ type EVM struct { readOnly bool // Whether to throw on stateful modifications returnData []byte // Last CALL's return data for subsequent reuse + + // CollisionBurned accumulates regular gas burned in CREATE/CREATE2 address + // collisions. The spec burns this gas (deducts from gas_left) but does NOT + // count it in regular_gas_used, so it must be excluded from txRegular in + // 2D block gas accounting. + // TODO (MariusVanDerWijden) this seems to be the best way to conform to the current + // spec, I wonder if it makes sense to change the spec. + CollisionBurned uint64 } // NewEVM constructs an EVM instance with the supplied block context, state @@ -215,6 +225,7 @@ func (evm *EVM) SetTxContext(txCtx TxContext) { txCtx.AccessEvents = state.NewAccessEvents() } evm.TxContext = txCtx + evm.CollisionBurned = 0 } // Cancel cancels any running EVM operation. This may be called concurrently and @@ -236,11 +247,11 @@ func isSystemCall(caller common.Address) bool { // parameters. It also handles any necessary value transfer required and takse // the necessary steps to create accounts and reverses the state in case of an // execution error or failed value transfer. -func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, gas GasCosts, value *uint256.Int) (ret []byte, leftOverGas GasCosts, err error) { // Capture the tracer start/end events in debug mode if evm.Config.Tracer != nil { evm.captureBegin(evm.depth, CALL, caller, addr, input, gas, value.ToBig()) - defer func(startGas uint64) { + defer func(startGas GasCosts) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } @@ -255,6 +266,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g return nil, gas, ErrInsufficientBalance } snapshot := evm.StateDB.Snapshot() + p, isPrecompile := evm.precompile(addr) if !evm.StateDB.Exist(addr) { if !isPrecompile && evm.chainRules.IsEIP4762 && !isSystemCall(caller) { @@ -265,12 +277,12 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g // list in write mode. If there is enough gas paying for the addition of the code // hash leaf to the access list, then account creation will proceed unimpaired. // Thus, only pay for the creation of the code hash leaf here. - wgas := evm.AccessEvents.CodeHashGas(addr, true, gas, false) - if gas < wgas { + wgas := evm.AccessEvents.CodeHashGas(addr, true, gas.RegularGas, false) + if gas.RegularGas < wgas { evm.StateDB.RevertToSnapshot(snapshot) - return nil, 0, ErrOutOfGas + return nil, GasCosts{}, ErrOutOfGas } - gas -= wgas + gas.RegularGas -= wgas } if !isPrecompile && evm.chainRules.IsEIP158 && value.IsZero() { @@ -291,7 +303,7 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g if evm.chainRules.IsAmsterdam { stateDB = evm.StateDB } - ret, gas, err = RunPrecompiledContract(stateDB, p, addr, input, gas, evm.Config.Tracer) + ret, gas.RegularGas, err = RunPrecompiledContract(stateDB, p, addr, input, gas.RegularGas, evm.Config.Tracer) } else { // Initialise a new contract and set the code that is to be used by the EVM. code := evm.resolveCode(addr) @@ -311,15 +323,13 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g // when we're in homestead this also counts for code storage gas errors. if err != nil { evm.StateDB.RevertToSnapshot(snapshot) - if err != ErrExecutionReverted { + isRevert := err == ErrExecutionReverted + if !isRevert { if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) + evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution) } - gas = 0 + gas.RegularGas = 0 } - // TODO: consider clearing up unused snapshots: - //} else { - // evm.StateDB.DiscardSnapshot(snapshot) } return ret, gas, err } @@ -331,11 +341,11 @@ func (evm *EVM) Call(caller common.Address, addr common.Address, input []byte, g // // CallCode differs from Call in the sense that it executes the given address' // code with the caller as context. -func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byte, gas GasCosts, value *uint256.Int) (ret []byte, leftOverGas GasCosts, err error) { // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { evm.captureBegin(evm.depth, CALLCODE, caller, addr, input, gas, value.ToBig()) - defer func(startGas uint64) { + defer func(startGas GasCosts) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } @@ -358,7 +368,7 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt if evm.chainRules.IsAmsterdam { stateDB = evm.StateDB } - ret, gas, err = RunPrecompiledContract(stateDB, p, addr, input, gas, evm.Config.Tracer) + ret, gas.RegularGas, err = RunPrecompiledContract(stateDB, p, addr, input, gas.RegularGas, evm.Config.Tracer) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -369,11 +379,12 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt } if err != nil { evm.StateDB.RevertToSnapshot(snapshot) - if err != ErrExecutionReverted { + isRevert := err == ErrExecutionReverted + if !isRevert { if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) + evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution) } - gas = 0 + gas.RegularGas = 0 } } return ret, gas, err @@ -384,12 +395,12 @@ func (evm *EVM) CallCode(caller common.Address, addr common.Address, input []byt // // DelegateCall differs from CallCode in the sense that it executes the given address' // code with the caller as context and the caller is set to the caller of the caller. -func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, addr common.Address, input []byte, gas uint64, value *uint256.Int) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, addr common.Address, input []byte, gas GasCosts, value *uint256.Int) (ret []byte, leftOverGas GasCosts, err error) { // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { // DELEGATECALL inherits value from parent call evm.captureBegin(evm.depth, DELEGATECALL, caller, addr, input, gas, value.ToBig()) - defer func(startGas uint64) { + defer func(startGas GasCosts) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } @@ -405,7 +416,7 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, if evm.chainRules.IsAmsterdam { stateDB = evm.StateDB } - ret, gas, err = RunPrecompiledContract(stateDB, p, addr, input, gas, evm.Config.Tracer) + ret, gas.RegularGas, err = RunPrecompiledContract(stateDB, p, addr, input, gas.RegularGas, evm.Config.Tracer) } else { // Initialise a new contract and make initialise the delegate values // @@ -417,11 +428,12 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, } if err != nil { evm.StateDB.RevertToSnapshot(snapshot) - if err != ErrExecutionReverted { + isRevert := err == ErrExecutionReverted + if !isRevert { if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) + evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution) } - gas = 0 + gas.RegularGas = 0 } } return ret, gas, err @@ -431,11 +443,11 @@ func (evm *EVM) DelegateCall(originCaller common.Address, caller common.Address, // as parameters while disallowing any modifications to the state during the call. // Opcodes that attempt to perform such modifications will result in exceptions // instead of performing the modifications. -func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []byte, gas uint64) (ret []byte, leftOverGas uint64, err error) { +func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []byte, gas GasCosts) (ret []byte, leftOverGas GasCosts, err error) { // Invoke tracer hooks that signal entering/exiting a call frame if evm.Config.Tracer != nil { evm.captureBegin(evm.depth, STATICCALL, caller, addr, input, gas, nil) - defer func(startGas uint64) { + defer func(startGas GasCosts) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } @@ -461,7 +473,7 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b if evm.chainRules.IsAmsterdam { stateDB = evm.StateDB } - ret, gas, err = RunPrecompiledContract(stateDB, p, addr, input, gas, evm.Config.Tracer) + ret, gas.RegularGas, err = RunPrecompiledContract(stateDB, p, addr, input, gas.RegularGas, evm.Config.Tracer) } else { // Initialise a new contract and set the code that is to be used by the EVM. // The contract is a scoped environment for this execution context only. @@ -476,19 +488,19 @@ func (evm *EVM) StaticCall(caller common.Address, addr common.Address, input []b } if err != nil { evm.StateDB.RevertToSnapshot(snapshot) - if err != ErrExecutionReverted { + isRevert := err == ErrExecutionReverted + if !isRevert { if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) + evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution) } - - gas = 0 + gas.RegularGas = 0 } } return ret, gas, err } // create creates a new contract using code as deployment code. -func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas uint64, err error) { +func (evm *EVM) create(caller common.Address, code []byte, gas GasCosts, value *uint256.Int, address common.Address, typ OpCode) (ret []byte, createAddress common.Address, leftOverGas GasCosts, err error) { // Depth check execution. Fail if we're trying to execute above the // limit. var nonce uint64 @@ -508,24 +520,23 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui } if evm.Config.Tracer != nil { evm.captureBegin(evm.depth, typ, caller, address, code, gas, value.ToBig()) - defer func(startGas uint64) { + defer func(startGas GasCosts) { evm.captureEnd(evm.depth, startGas, leftOverGas, ret, err) }(gas) } if err != nil { return nil, common.Address{}, gas, err } - // Charge the contract creation init gas in verkle mode if evm.chainRules.IsEIP4762 { - statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address, gas) - if statelessGas > gas { - return nil, common.Address{}, 0, ErrOutOfGas + statelessGas := evm.AccessEvents.ContractCreatePreCheckGas(address, gas.RegularGas) + if statelessGas > gas.RegularGas { + return nil, common.Address{}, GasCosts{}, ErrOutOfGas } if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, gas-statelessGas, tracing.GasChangeWitnessContractCollisionCheck) + evm.Config.Tracer.OnGasChange(gas.RegularGas, gas.RegularGas-statelessGas, tracing.GasChangeWitnessContractCollisionCheck) } - gas = gas - statelessGas + gas.RegularGas = gas.RegularGas - statelessGas } // We add this to the access list _before_ taking a snapshot. Even if the @@ -545,14 +556,17 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui (contractHash != (common.Hash{}) && contractHash != types.EmptyCodeHash) || // non-empty code (storageRoot != (common.Hash{}) && storageRoot != types.EmptyRootHash) { // non-empty storage if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, 0, tracing.GasChangeCallFailedExecution) + evm.Config.Tracer.OnGasChange(gas.RegularGas, 0, tracing.GasChangeCallFailedExecution) } - return nil, common.Address{}, 0, ErrContractAddressCollision + evm.CollisionBurned += gas.RegularGas + gas.RegularGas = 0 + return nil, common.Address{}, gas, ErrContractAddressCollision } // Create a new account on the state only if the object was not present. // It might be possible the contract code is deployed to a pre-existent // account with non-zero balance. snapshot := evm.StateDB.Snapshot() + if !evm.StateDB.Exist(address) { evm.StateDB.CreateAccount(address) } @@ -567,14 +581,14 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui } // Charge the contract creation init gas in verkle mode if evm.chainRules.IsEIP4762 { - consumed, wanted := evm.AccessEvents.ContractCreateInitGas(address, gas) + consumed, wanted := evm.AccessEvents.ContractCreateInitGas(address, gas.RegularGas) if consumed < wanted { - return nil, common.Address{}, 0, ErrOutOfGas + return nil, common.Address{}, GasCosts{}, ErrOutOfGas } if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { - evm.Config.Tracer.OnGasChange(gas, gas-consumed, tracing.GasChangeWitnessContractInit) + evm.Config.Tracer.OnGasChange(gas.RegularGas, gas.RegularGas-consumed, tracing.GasChangeWitnessContractInit) } - gas = gas - consumed + gas.RegularGas = gas.RegularGas - consumed } evm.Context.Transfer(evm.StateDB, caller, address, value, evm.Context.BlockNumber, &evm.chainRules) @@ -590,8 +604,14 @@ func (evm *EVM) create(caller common.Address, code []byte, gas uint64, value *ui ret, err = evm.initNewContract(contract, address) if err != nil && (evm.chainRules.IsHomestead || err != ErrCodeStoreOutOfGas) { evm.StateDB.RevertToSnapshot(snapshot) + + // On ExceptionalHalt, burn remaining regular gas. On REVERT, preserve + // remaining regular gas. State gas is always preserved. if err != ErrExecutionReverted { - contract.UseGas(contract.Gas, evm.Config.Tracer, tracing.GasChangeCallFailedExecution) + if evm.Config.Tracer != nil && evm.Config.Tracer.OnGasChange != nil { + evm.Config.Tracer.OnGasChange(contract.Gas.RegularGas, 0, tracing.GasChangeCallFailedExecution) + } + contract.Gas.RegularGas = 0 } } return ret, address, contract.Gas, err @@ -605,29 +625,45 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b return ret, err } - // Check whether the max code size has been exceeded, assign err if the case. - if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil { - return ret, err - } - - // Reject code starting with 0xEF if EIP-3541 is enabled. + // Check prefix before gas calculation. if len(ret) >= 1 && ret[0] == 0xEF && evm.chainRules.IsLondon { return ret, ErrInvalidCode } + // Charge code storage gas. if !evm.chainRules.IsEIP4762 { - createDataGas := uint64(len(ret)) * params.CreateDataGas - if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { - return ret, ErrCodeStoreOutOfGas + if evm.chainRules.IsAmsterdam { + // EIP-8037: spec charges state gas first (charge_state_gas), then + // regular gas (charge_gas). If state gas succeeds but regular gas + // fails, state_gas_used is still recorded. + stateGas := GasCosts{StateGas: uint64(len(ret)) * evm.Context.CostPerGasByte} + if !contract.UseGas(stateGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { + return ret, ErrCodeStoreOutOfGas + } + words := (uint64(len(ret)) + 31) / 32 + regularGas := GasCosts{RegularGas: words * params.Keccak256WordGas} + if !contract.UseGas(regularGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { + return ret, ErrCodeStoreOutOfGas + } + } else { + createDataGas := GasCosts{RegularGas: uint64(len(ret)) * params.CreateDataGas} + if !contract.UseGas(createDataGas, evm.Config.Tracer, tracing.GasChangeCallCodeStorage) { + return ret, ErrCodeStoreOutOfGas + } } } else { - consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true, contract.Gas) - contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) + consumed, wanted := evm.AccessEvents.CodeChunksRangeGas(address, 0, uint64(len(ret)), uint64(len(ret)), true, contract.Gas.RegularGas) + contract.UseGas(GasCosts{RegularGas: consumed}, evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) if len(ret) > 0 && (consumed < wanted) { return ret, ErrCodeStoreOutOfGas } } + // Verify max code size after gas calculation. + if err := CheckMaxCodeSize(&evm.chainRules, uint64(len(ret))); err != nil { + return ret, err + } + if len(ret) > 0 { evm.StateDB.SetCode(address, ret, tracing.CodeChangeContractCreation) } @@ -635,7 +671,7 @@ func (evm *EVM) initNewContract(contract *Contract, address common.Address) ([]b } // Create creates a new contract using code as deployment code. -func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { +func (evm *EVM) Create(caller common.Address, code []byte, gas GasCosts, value *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas GasCosts, err error) { contractAddr = crypto.CreateAddress(caller, evm.StateDB.GetNonce(caller)) return evm.create(caller, code, gas, value, contractAddr, CREATE) } @@ -644,7 +680,7 @@ func (evm *EVM) Create(caller common.Address, code []byte, gas uint64, value *ui // // The different between Create2 with Create is Create2 uses keccak256(0xff ++ msg.sender ++ salt ++ keccak256(init_code))[12:] // instead of the usual sender-and-nonce-hash as the address where the contract is initialized at. -func (evm *EVM) Create2(caller common.Address, code []byte, gas uint64, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas uint64, err error) { +func (evm *EVM) Create2(caller common.Address, code []byte, gas GasCosts, endowment *uint256.Int, salt *uint256.Int) (ret []byte, contractAddr common.Address, leftOverGas GasCosts, err error) { inithash := crypto.Keccak256Hash(code) contractAddr = crypto.CreateAddress2(caller, salt.Bytes32(), inithash[:]) return evm.create(caller, code, gas, endowment, contractAddr, CREATE2) @@ -682,20 +718,20 @@ func (evm *EVM) resolveCodeHash(addr common.Address) common.Hash { // ChainConfig returns the environment's chain configuration func (evm *EVM) ChainConfig() *params.ChainConfig { return evm.chainConfig } -func (evm *EVM) captureBegin(depth int, typ OpCode, from common.Address, to common.Address, input []byte, startGas uint64, value *big.Int) { +func (evm *EVM) captureBegin(depth int, typ OpCode, from common.Address, to common.Address, input []byte, startGas GasCosts, value *big.Int) { tracer := evm.Config.Tracer if tracer.OnEnter != nil { - tracer.OnEnter(depth, byte(typ), from, to, input, startGas, value) + tracer.OnEnter(depth, byte(typ), from, to, input, startGas.RegularGas, value) } if tracer.OnGasChange != nil { - tracer.OnGasChange(0, startGas, tracing.GasChangeCallInitialBalance) + tracer.OnGasChange(0, startGas.RegularGas, tracing.GasChangeCallInitialBalance) } } -func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret []byte, err error) { +func (evm *EVM) captureEnd(depth int, startGas GasCosts, leftOverGas GasCosts, ret []byte, err error) { tracer := evm.Config.Tracer - if leftOverGas != 0 && tracer.OnGasChange != nil { - tracer.OnGasChange(leftOverGas, 0, tracing.GasChangeCallLeftOverReturned) + if leftOverGas.RegularGas != 0 && tracer.OnGasChange != nil { + tracer.OnGasChange(leftOverGas.RegularGas, 0, tracing.GasChangeCallLeftOverReturned) } var reverted bool if err != nil { @@ -705,7 +741,7 @@ func (evm *EVM) captureEnd(depth int, startGas uint64, leftOverGas uint64, ret [ reverted = false } if tracer.OnExit != nil { - tracer.OnExit(depth, ret, startGas-leftOverGas, VMErrorFromErr(err), reverted) + tracer.OnExit(depth, ret, startGas.RegularGas-leftOverGas.RegularGas, VMErrorFromErr(err), reverted) } } diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index 72f72201ee..570c957fbd 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -64,26 +64,26 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { // EXTCODECOPY (stack position 3) // RETURNDATACOPY (stack position 2) func memoryCopierGas(stackpos int) gasFunc { - return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { // Gas for expanding the memory gas, err := memoryGasCost(mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } // And gas for copying data, charged per word at param.CopyGas words, overflow := stack.Back(stackpos).Uint64WithOverflow() if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } if gas, overflow = math.SafeAdd(gas, words); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas}, nil } } @@ -95,9 +95,9 @@ var ( gasReturnDataCopy = memoryCopierGas(2) ) -func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { if evm.readOnly { - return 0, ErrWriteProtection + return GasCosts{}, ErrWriteProtection } var ( y, x = stack.Back(1), stack.Back(0) @@ -114,12 +114,12 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi // 3. From a non-zero to a non-zero (CHANGE) switch { case current == (common.Hash{}) && y.Sign() != 0: // 0 => non 0 - return params.SstoreSetGas, nil + return GasCosts{RegularGas: params.SstoreSetGas}, nil case current != (common.Hash{}) && y.Sign() == 0: // non 0 => 0 evm.StateDB.AddRefund(params.SstoreRefundGas) - return params.SstoreClearGas, nil + return GasCosts{RegularGas: params.SstoreClearGas}, nil default: // non 0 => non 0 (or 0 => 0) - return params.SstoreResetGas, nil + return GasCosts{RegularGas: params.SstoreResetGas}, nil } } @@ -139,16 +139,16 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi // (2.2.2.2.) Otherwise, add 4800 gas to refund counter. value := common.Hash(y.Bytes32()) if current == value { // noop (1) - return params.NetSstoreNoopGas, nil + return GasCosts{RegularGas: params.NetSstoreNoopGas}, nil } if original == current { if original == (common.Hash{}) { // create slot (2.1.1) - return params.NetSstoreInitGas, nil + return GasCosts{RegularGas: params.NetSstoreInitGas}, nil } if value == (common.Hash{}) { // delete slot (2.1.2b) evm.StateDB.AddRefund(params.NetSstoreClearRefund) } - return params.NetSstoreCleanGas, nil // write existing slot (2.1.2) + return GasCosts{RegularGas: params.NetSstoreCleanGas}, nil // write existing slot (2.1.2) } if original != (common.Hash{}) { if current == (common.Hash{}) { // recreate slot (2.2.1.1) @@ -164,7 +164,7 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi evm.StateDB.AddRefund(params.NetSstoreResetRefund) } } - return params.NetSstoreDirtyGas, nil + return GasCosts{RegularGas: params.NetSstoreDirtyGas}, nil } // Here come the EIP2200 rules: @@ -182,13 +182,13 @@ func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySi // (2.2.2.) If original value equals new value (this storage slot is reset): // (2.2.2.1.) If original value is 0, add SSTORE_SET_GAS - SLOAD_GAS to refund counter. // (2.2.2.2.) Otherwise, add SSTORE_RESET_GAS - SLOAD_GAS gas to refund counter. -func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { if evm.readOnly { - return 0, ErrWriteProtection + return GasCosts{}, ErrWriteProtection } // If we fail the minimum gas availability invariant, fail (0) - if contract.Gas <= params.SstoreSentryGasEIP2200 { - return 0, errors.New("not enough gas for reentrancy sentry") + if contract.Gas.RegularGas <= params.SstoreSentryGasEIP2200 { + return GasCosts{}, errors.New("not enough gas for reentrancy sentry") } // Gas sentry honoured, do the actual gas calculation based on the stored value var ( @@ -198,16 +198,16 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m value := common.Hash(y.Bytes32()) if current == value { // noop (1) - return params.SloadGasEIP2200, nil + return GasCosts{RegularGas: params.SloadGasEIP2200}, nil } if original == current { if original == (common.Hash{}) { // create slot (2.1.1) - return params.SstoreSetGasEIP2200, nil + return GasCosts{RegularGas: params.SstoreSetGasEIP2200}, nil } if value == (common.Hash{}) { // delete slot (2.1.2b) evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200) } - return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2) + return GasCosts{RegularGas: params.SstoreResetGasEIP2200}, nil // write existing slot (2.1.2) } if original != (common.Hash{}) { if current == (common.Hash{}) { // recreate slot (2.2.1.1) @@ -223,62 +223,66 @@ func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200) } } - return params.SloadGasEIP2200, nil // dirty update (2.2) + return GasCosts{RegularGas: params.SloadGasEIP2200}, nil // dirty update (2.2) } func makeGasLog(n uint64) gasFunc { - return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { requestedSize, overflow := stack.Back(1).Uint64WithOverflow() if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } gas, err := memoryGasCost(mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } var memorySizeGas uint64 if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas}, nil } } -func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasKeccak256(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } wordGas, overflow := stack.Back(1).Uint64WithOverflow() if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Keccak256WordGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } if gas, overflow = math.SafeAdd(gas, wordGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas}, nil } // pureMemoryGascost is used by several operations, which aside from their // static cost have a dynamic cost which is solely based on the memory // expansion -func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return memoryGasCost(mem, memorySize) +func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return GasCosts{}, err + } + return GasCosts{RegularGas: gas}, nil } var ( @@ -290,64 +294,65 @@ var ( gasCreate = pureMemoryGascost ) -func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } wordGas, overflow := stack.Back(2).Uint64WithOverflow() if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Keccak256WordGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } if gas, overflow = math.SafeAdd(gas, wordGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas}, nil } -func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCreateEip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } size, overflow := stack.Back(2).Uint64WithOverflow() if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } if err := CheckMaxInitCodeSize(&evm.chainRules, size); err != nil { - return 0, err + return GasCosts{}, err } // Since size <= the protocol-defined maximum initcode size limit, these multiplication cannot overflow moreGas := params.InitCodeWordGas * ((size + 31) / 32) if gas, overflow = math.SafeAdd(gas, moreGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas}, nil } -func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + +func gasCreate2Eip3860(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } size, overflow := stack.Back(2).Uint64WithOverflow() if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } if err := CheckMaxInitCodeSize(&evm.chainRules, size); err != nil { - return 0, err + return GasCosts{}, err } // Since size <= the protocol-defined maximum initcode size limit, these multiplication cannot overflow moreGas := (params.InitCodeWordGas + params.Keccak256WordGas) * ((size + 31) / 32) if gas, overflow = math.SafeAdd(gas, moreGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas}, nil } -func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) var ( @@ -355,12 +360,12 @@ func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, mem overflow bool ) if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas}, nil } -func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) var ( @@ -368,12 +373,12 @@ func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memor overflow bool ) if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas}, nil } -func gasCallStateless(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCallStateless(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { var ( gas uint64 transfersValue = !stack.Back(2).IsZero() @@ -381,7 +386,7 @@ func gasCallStateless(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m if transfersValue { if evm.readOnly { - return 0, ErrWriteProtection + return GasCosts{}, ErrWriteProtection } else if !evm.chainRules.IsEIP4762 { gas += params.CallValueTransferGas } @@ -389,24 +394,24 @@ func gasCallStateless(evm *EVM, contract *Contract, stack *Stack, mem *Memory, m memoryGas, err := memoryGasCost(mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } var overflow bool if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas}, nil } -func gasCallStateful(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCallStateful(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { var ( gas uint64 transfersValue = !stack.Back(2).IsZero() address = common.Address(stack.Back(1).Bytes20()) ) if evm.readOnly && transfersValue { - return 0, ErrWriteProtection + return GasCosts{}, ErrWriteProtection } if evm.chainRules.IsEIP158 { @@ -417,42 +422,42 @@ func gasCallStateful(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me gas += params.CallNewAccountGas } - return gas, nil + return GasCosts{RegularGas: gas}, nil } -func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { stateless, err := gasCallStateless(evm, contract, stack, mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } stateful, err := gasCallStateful(evm, contract, stack, mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } - gas, overflow := math.SafeAdd(stateless, stateful) + gas, overflow := math.SafeAdd(stateless.RegularGas, stateful.RegularGas) if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas.RegularGas, gas, stack.Back(0)) if err != nil { - return 0, err + return GasCosts{}, err } if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas}, nil } -func gasCallCodeStateful(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return 0, nil +func gasCallCodeStateful(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + return GasCosts{}, nil } -func gasCallCodeStateless(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCallCodeStateless(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { memoryGas, err := memoryGasCost(mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } var ( gas uint64 @@ -465,96 +470,95 @@ func gasCallCodeStateless(evm *EVM, contract *Contract, stack *Stack, mem *Memor } } if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas}, nil } -func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { var overflow bool gas, err := gasCallCodeStateless(evm, contract, stack, mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } - evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas.RegularGas, gas.RegularGas, stack.Back(0)) if err != nil { - return 0, err + return GasCosts{}, err } - if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { - return 0, ErrGasUintOverflow + if gas.RegularGas, overflow = math.SafeAdd(gas.RegularGas, evm.callGasTemp); overflow { + return GasCosts{}, ErrGasUintOverflow } return gas, nil } -func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { var ( err error - gas uint64 + gas GasCosts ) gas, err = gasDelegateCallStateless(evm, contract, stack, mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } - evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas.RegularGas, gas.RegularGas, stack.Back(0)) if err != nil { - return 0, err + return GasCosts{}, err } var overflow bool - if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { - return 0, ErrGasUintOverflow + if gas.RegularGas, overflow = math.SafeAdd(gas.RegularGas, evm.callGasTemp); overflow { + return GasCosts{}, ErrGasUintOverflow } return gas, nil } -func gasDelegateCallStateful(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return 0, nil +func gasDelegateCallStateful(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + return GasCosts{}, nil } -func gasDelegateCallStateless(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasDelegateCallStateless(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } - return gas, nil + return GasCosts{RegularGas: gas}, nil } -func gasStaticCallStateless(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasStaticCallStateless(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } - return gas, nil + return GasCosts{RegularGas: gas}, nil } -func gasStaticCallStateful(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return 0, nil +func gasStaticCallStateful(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + return GasCosts{}, nil } -func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { gas, err := gasStaticCallStateless(evm, contract, stack, mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } - evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas.RegularGas, gas.RegularGas, stack.Back(0)) if err != nil { - return 0, err + return GasCosts{}, err } var overflow bool - if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { - return 0, ErrGasUintOverflow + if gas.RegularGas, overflow = math.SafeAdd(gas.RegularGas, evm.callGasTemp); overflow { + return GasCosts{}, ErrGasUintOverflow } return gas, nil } -func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { if evm.readOnly { - return 0, ErrWriteProtection + return GasCosts{}, ErrWriteProtection } - var gas uint64 // EIP150 homestead gas reprice fork: @@ -562,8 +566,8 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me gas = params.SelfdestructGasEIP150 var address = common.Address(stack.Back(0).Bytes20()) - if gas > contract.Gas { - return gas, nil + if gas > contract.Gas.RegularGas { + return GasCosts{RegularGas: gas}, nil } if evm.chainRules.IsEIP158 { @@ -579,5 +583,165 @@ func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me if !evm.StateDB.HasSelfDestructed(contract.Address()) { evm.StateDB.AddRefund(params.SelfdestructRefundGas) } + return GasCosts{RegularGas: gas}, nil +} + +func gasCreateEip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return GasCosts{}, err + } + size, overflow := stack.Back(2).Uint64WithOverflow() + if overflow { + return GasCosts{}, ErrGasUintOverflow + } + // Cap word gas at MaxInitCodeSizeAmsterdam to avoid overflow. + // The actual init code size check happens in create() for graceful failure. + wordSize := min(size, params.MaxInitCodeSizeAmsterdam) + words := (wordSize + 31) / 32 + // Account creation is a fixed state gas cost, not proportional to init code size. + // Code storage state gas is charged separately in initNewContract. + stateGas := params.AccountCreationSize * evm.Context.CostPerGasByte + // CREATE uses InitCodeWordGas (EIP-3860); Keccak256WordGas is only for CREATE2. + wordGas := params.InitCodeWordGas * words + return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil +} + +func gasCreate2Eip8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return GasCosts{}, err + } + size, overflow := stack.Back(2).Uint64WithOverflow() + if overflow { + return GasCosts{}, ErrGasUintOverflow + } + // Cap word gas at MaxInitCodeSizeAmsterdam to avoid overflow. + // The actual init code size check happens in create() for graceful failure. + wordSize := min(size, params.MaxInitCodeSizeAmsterdam) + words := (wordSize + 31) / 32 + // Account creation is a fixed state gas cost, not proportional to init code size. + // Code storage state gas is charged separately in initNewContract. + stateGas := params.AccountCreationSize * evm.Context.CostPerGasByte + // CREATE2 charges both InitCodeWordGas (EIP-3860) and Keccak256WordGas (for address hashing). + wordGas := (params.InitCodeWordGas + params.Keccak256WordGas) * words + return GasCosts{RegularGas: gas + wordGas, StateGas: stateGas}, nil +} + +// gasCall8037 is the stateful gas calculator for CALL in Amsterdam (EIP-8037). +// It only returns the state-dependent gas (account creation as state gas). +// Memory gas, transfer gas, and callGas are handled by gasCallStateless and +// makeCallVariantGasCall. +func gasCall8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + var ( + gas GasCosts + transfersValue = !stack.Back(2).IsZero() + address = common.Address(stack.Back(1).Bytes20()) + ) + if evm.chainRules.IsEIP158 { + if transfersValue && evm.StateDB.Empty(address) { + gas.StateGas += params.AccountCreationSize * evm.Context.CostPerGasByte + } + } else if !evm.StateDB.Exist(address) { + gas.StateGas += params.AccountCreationSize * evm.Context.CostPerGasByte + } return gas, nil } + +func gasSelfdestruct8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + if evm.readOnly { + return GasCosts{}, ErrWriteProtection + } + var ( + gas GasCosts + address = common.Address(stack.peek().Bytes20()) + ) + if !evm.StateDB.AddressInAccessList(address) { + // If the caller cannot afford the cost, this change will be rolled back + evm.StateDB.AddAddressToAccessList(address) + gas.RegularGas = params.ColdAccountAccessCostEIP2929 + } + // Check we have enough regular gas before we add the address to the BAL + if contract.Gas.RegularGas < gas.RegularGas { + return gas, nil + } + // if empty and transfers value + if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { + gas.StateGas += params.AccountCreationSize * evm.Context.CostPerGasByte + } + return gas, nil +} + +func gasSStore8037(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + if evm.readOnly { + return GasCosts{}, ErrWriteProtection + } + // If we fail the minimum gas availability invariant, fail (0) + if contract.Gas.RegularGas <= params.SstoreSentryGasEIP2200 { + return GasCosts{}, errors.New("not enough gas for reentrancy sentry") + } + // Gas sentry honoured, do the actual gas calculation based on the stored value + var ( + y, x = stack.Back(1), stack.peek() + slot = common.Hash(x.Bytes32()) + current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), slot) + cost GasCosts + ) + // Check slot presence in the access list + if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent { + cost = GasCosts{RegularGas: params.ColdSloadCostEIP2929} + // If the caller cannot afford the cost, this change will be rolled back + evm.StateDB.AddSlotToAccessList(contract.Address(), slot) + } + value := common.Hash(y.Bytes32()) + + if current == value { // noop (1) + // EIP 2200 original clause: + // return params.SloadGasEIP2200, nil + return GasCosts{RegularGas: cost.RegularGas + params.WarmStorageReadCostEIP2929}, nil // SLOAD_GAS + } + if original == current { + if original == (common.Hash{}) { // create slot (2.1.1) + // EIP-8037: Charge state gas first (before regular gas), matching the + // spec's charge_state_gas → charge_gas ordering. This ensures that + // state_gas_used is recorded even if the subsequent regular gas charge + // fails with OOG. + stateGas := GasCosts{StateGas: params.StorageCreationSize * evm.Context.CostPerGasByte} + if contract.Gas.Underflow(stateGas) { + return GasCosts{}, errors.New("out of gas for state gas") + } + contract.Gas.Sub(stateGas) + return GasCosts{RegularGas: cost.RegularGas + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929}, nil + } + if value == (common.Hash{}) { // delete slot (2.1.2b) + evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP3529) + } + // EIP-2200 original clause: + // return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2) + return GasCosts{RegularGas: cost.RegularGas + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929}, nil // write existing slot (2.1.2) + } + if original != (common.Hash{}) { + if current == (common.Hash{}) { // recreate slot (2.2.1.1) + evm.StateDB.SubRefund(params.SstoreClearsScheduleRefundEIP3529) + } else if value == (common.Hash{}) { // delete slot (2.2.1.2) + evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP3529) + } + } + if original == value { + if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) + // EIP 2200 Original clause: + //evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200) + evm.StateDB.AddRefund(params.StorageCreationSize*evm.Context.CostPerGasByte + params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929 - params.WarmStorageReadCostEIP2929) + } else { // reset to original existing slot (2.2.2.2) + // EIP 2200 Original clause: + // evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200) + // - SSTORE_RESET_GAS redefined as (5000 - COLD_SLOAD_COST) + // - SLOAD_GAS redefined as WARM_STORAGE_READ_COST + // Final: (5000 - COLD_SLOAD_COST) - WARM_STORAGE_READ_COST + evm.StateDB.AddRefund((params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929) - params.WarmStorageReadCostEIP2929) + } + } + // EIP-2200 original clause: + //return params.SloadGasEIP2200, nil // dirty update (2.2) + return GasCosts{RegularGas: cost.RegularGas + params.WarmStorageReadCostEIP2929}, nil // dirty update (2.2) +} diff --git a/core/vm/gas_table_test.go b/core/vm/gas_table_test.go index e9b1d3771b..cb932899d7 100644 --- a/core/vm/gas_table_test.go +++ b/core/vm/gas_table_test.go @@ -98,11 +98,11 @@ func TestEIP2200(t *testing.T) { } evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, Config{ExtraEips: []int{2200}}) - _, gas, err := evm.Call(common.Address{}, address, nil, tt.gaspool, new(uint256.Int)) + _, gas, err := evm.Call(common.Address{}, address, nil, GasCosts{RegularGas: tt.gaspool}, new(uint256.Int)) if !errors.Is(err, tt.failure) { t.Errorf("test %d: failure mismatch: have %v, want %v", i, err, tt.failure) } - if used := tt.gaspool - gas; used != tt.used { + if used := tt.gaspool - gas.RegularGas; used != tt.used { t.Errorf("test %d: gas used mismatch: have %v, want %v", i, used, tt.used) } if refund := evm.StateDB.GetRefund(); refund != tt.refund { @@ -154,11 +154,11 @@ func TestCreateGas(t *testing.T) { evm := NewEVM(vmctx, statedb, params.AllEthashProtocolChanges, config) var startGas = uint64(testGas) - ret, gas, err := evm.Call(common.Address{}, address, nil, startGas, new(uint256.Int)) + ret, gas, err := evm.Call(common.Address{}, address, nil, GasCosts{RegularGas: startGas}, new(uint256.Int)) if err != nil { return false } - gasUsed = startGas - gas + gasUsed = startGas - gas.RegularGas if len(ret) != 32 { t.Fatalf("test %d: expected 32 bytes returned, have %d", i, len(ret)) } diff --git a/core/vm/gascosts.go b/core/vm/gascosts.go new file mode 100644 index 0000000000..32f4455b36 --- /dev/null +++ b/core/vm/gascosts.go @@ -0,0 +1,60 @@ +package vm + +import "fmt" + +type GasCosts struct { + RegularGas uint64 + StateGas uint64 + + // StateGasCharged tracks the cumulative state gas charged during execution. + StateGasCharged uint64 +} + +func (g GasCosts) Max() uint64 { + return max(g.RegularGas, g.StateGas) +} + +func (g GasCosts) Sum() uint64 { + return g.RegularGas + g.StateGas +} + +// Underflow returns true if the operation would underflow. +// When state gas exceeds the reservoir, the excess spills to regular gas. +// The check accounts for regular gas already consumed by b.RegularGas. +func (g GasCosts) Underflow(b GasCosts) bool { + if b.RegularGas > g.RegularGas { + return true + } + if b.StateGas > g.StateGas { + spillover := b.StateGas - g.StateGas + remainingRegular := g.RegularGas - b.RegularGas + if spillover > remainingRegular { + return true + } + } + return false +} + +// Sub doesn't check for underflows +func (g *GasCosts) Sub(b GasCosts) { + g.RegularGas -= b.RegularGas + g.StateGasCharged += b.StateGas + if b.StateGas > g.StateGas { + diff := b.StateGas - g.StateGas + g.StateGas = 0 + g.RegularGas -= diff + } else { + g.StateGas -= b.StateGas + } +} + +// Add doesn't check for overflows +func (g *GasCosts) Add(b GasCosts) { + g.RegularGas += b.RegularGas + g.StateGas += b.StateGas + g.StateGasCharged += b.StateGasCharged +} + +func (g GasCosts) String() string { + return fmt.Sprintf("<%v,%v>", g.RegularGas, g.StateGas) +} diff --git a/core/vm/instructions.go b/core/vm/instructions.go index e5425636d2..1092f779f6 100644 --- a/core/vm/instructions.go +++ b/core/vm/instructions.go @@ -563,7 +563,7 @@ func opMsize(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { } func opGas(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { - scope.Stack.push(new(uint256.Int).SetUint64(scope.Contract.Gas)) + scope.Stack.push(new(uint256.Int).SetUint64(scope.Contract.Gas.RegularGas)) return nil, nil } @@ -658,15 +658,24 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { gas = scope.Contract.Gas ) if evm.chainRules.IsEIP150 { - gas -= gas / 64 + gas.RegularGas -= gas.RegularGas / 64 + } + + // EIP-7954: check init code size after gas is charged (by the gas function) + // but before execution. This aborts the caller's execution, ensuring all + // regular gas is consumed while the state gas spill is tracked. + if evm.chainRules.IsAmsterdam { + if err := CheckMaxInitCodeSize(&evm.chainRules, uint64(len(input))); err != nil { + return nil, err + } } // reuse size int for stackvalue stackvalue := size - scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation) + scope.Contract.UseGas(GasCosts{RegularGas: gas.RegularGas}, evm.Config.Tracer, tracing.GasChangeCallContractCreation) - res, addr, returnGas, suberr := evm.Create(scope.Contract.Address(), input, gas, &value) + res, addr, returnGas, suberr := evm.Create(scope.Contract.Address(), input, GasCosts{RegularGas: gas.RegularGas, StateGas: scope.Contract.Gas.StateGas}, &value) // Push item on the stack based on the returned error. If the ruleset is // homestead we must check for CodeStoreOutOfGasError (homestead only // rule) and treat as an error, if the ruleset is frontier we must @@ -680,7 +689,7 @@ func opCreate(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { } scope.Stack.push(&stackvalue) - scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(suberr, returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { evm.returnData = res // set REVERT data to return data buffer @@ -703,11 +712,21 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { ) // Apply EIP150 - gas -= gas / 64 - scope.Contract.UseGas(gas, evm.Config.Tracer, tracing.GasChangeCallContractCreation2) + gas.RegularGas -= gas.RegularGas / 64 + + // EIP-7954: check init code size after gas is charged (by the gas function) + // but before execution. This aborts the caller's execution, ensuring all + // regular gas is consumed while the state gas spill is tracked. + if evm.chainRules.IsAmsterdam { + if err := CheckMaxInitCodeSize(&evm.chainRules, uint64(len(input))); err != nil { + return nil, err + } + } + + scope.Contract.UseGas(GasCosts{RegularGas: gas.RegularGas}, evm.Config.Tracer, tracing.GasChangeCallContractCreation2) // reuse size int for stackvalue stackvalue := size - res, addr, returnGas, suberr := evm.Create2(scope.Contract.Address(), input, gas, + res, addr, returnGas, suberr := evm.Create2(scope.Contract.Address(), input, GasCosts{RegularGas: gas.RegularGas, StateGas: scope.Contract.Gas.StateGas}, &endowment, &salt) // Push item on the stack based on the returned error. if suberr != nil { @@ -716,7 +735,8 @@ func opCreate2(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { stackvalue.SetBytes(addr.Bytes()) } scope.Stack.push(&stackvalue) - scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + + scope.Contract.RefundGas(suberr, returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) if suberr == ErrExecutionReverted { evm.returnData = res // set REVERT data to return data buffer @@ -744,7 +764,7 @@ func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { if !value.IsZero() { gas += params.CallStipend } - ret, returnGas, err := evm.Call(scope.Contract.Address(), toAddr, args, gas, &value) + ret, returnGas, err := evm.Call(scope.Contract.Address(), toAddr, args, GasCosts{RegularGas: gas, StateGas: scope.Contract.Gas.StateGas}, &value) if err != nil { temp.Clear() @@ -756,7 +776,7 @@ func opCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(err, returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) evm.returnData = ret return ret, nil @@ -778,7 +798,7 @@ func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { gas += params.CallStipend } - ret, returnGas, err := evm.CallCode(scope.Contract.Address(), toAddr, args, gas, &value) + ret, returnGas, err := evm.CallCode(scope.Contract.Address(), toAddr, args, GasCosts{RegularGas: gas, StateGas: scope.Contract.Gas.StateGas}, &value) if err != nil { temp.Clear() } else { @@ -789,7 +809,7 @@ func opCallCode(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(err, returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) evm.returnData = ret return ret, nil @@ -807,7 +827,8 @@ func opDelegateCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - ret, returnGas, err := evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, gas, scope.Contract.value) + stateGas := scope.Contract.Gas.StateGas + ret, returnGas, err := evm.DelegateCall(scope.Contract.Caller(), scope.Contract.Address(), toAddr, args, GasCosts{RegularGas: gas, StateGas: stateGas}, scope.Contract.value) if err != nil { temp.Clear() } else { @@ -818,7 +839,7 @@ func opDelegateCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(err, returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) evm.returnData = ret return ret, nil @@ -836,7 +857,8 @@ func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { // Get arguments from the memory. args := scope.Memory.GetPtr(inOffset.Uint64(), inSize.Uint64()) - ret, returnGas, err := evm.StaticCall(scope.Contract.Address(), toAddr, args, gas) + stateGas := scope.Contract.Gas.StateGas + ret, returnGas, err := evm.StaticCall(scope.Contract.Address(), toAddr, args, GasCosts{RegularGas: gas, StateGas: stateGas}) if err != nil { temp.Clear() } else { @@ -847,7 +869,7 @@ func opStaticCall(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) { scope.Memory.Set(retOffset.Uint64(), retSize.Uint64(), ret) } - scope.Contract.RefundGas(returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) + scope.Contract.RefundGas(err, returnGas, evm.Config.Tracer, tracing.GasChangeCallLeftOverRefunded) evm.returnData = ret return ret, nil diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 4c6d093d2e..ed3b67a642 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -565,7 +565,7 @@ func TestOpTstore(t *testing.T) { mem = NewMemory() caller = common.Address{} to = common.Address{1} - contract = NewContract(caller, to, new(uint256.Int), 0, nil) + contract = NewContract(caller, to, new(uint256.Int), GasCosts{RegularGas: 0, StateGas: 0}, nil) scopeContext = ScopeContext{mem, stack, contract} value = common.Hex2Bytes("abcdef00000000000000abba000000000deaf000000c0de00100000000133700") ) @@ -879,7 +879,7 @@ func TestOpMCopy(t *testing.T) { if dynamicCost, err := gasMcopy(evm, nil, stack, mem, memorySize); err != nil { t.Error(err) } else { - haveGas = GasFastestStep + dynamicCost + haveGas = GasFastestStep + dynamicCost.RegularGas } // Expand mem if memorySize > 0 { diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 620c069fc8..f2b37c8ce3 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -166,15 +166,15 @@ func (evm *EVM) Run(contract *Contract, input []byte, readOnly bool) (ret []byte for { if debug { // Capture pre-execution values for tracing. - logged, pcCopy, gasCopy = false, pc, contract.Gas + logged, pcCopy, gasCopy = false, pc, contract.Gas.RegularGas } if isEIP4762 && !contract.IsDeployment && !contract.IsSystemCall { // if the PC ends up in a new "chunk" of verkleized code, charge the // associated costs. contractAddr := contract.Address() - consumed, wanted := evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, contract.Gas) - contract.UseGas(consumed, evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) + consumed, wanted := evm.TxContext.AccessEvents.CodeChunksRangeGas(contractAddr, pc, 1, uint64(len(contract.Code)), false, contract.Gas.RegularGas) + contract.UseGas(GasCosts{RegularGas: consumed}, evm.Config.Tracer, tracing.GasChangeWitnessCodeChunk) if consumed < wanted { return nil, ErrOutOfGas } @@ -192,10 +192,10 @@ func (evm *EVM) Run(contract *Contract, input []byte, readOnly bool) (ret []byte return nil, &ErrStackOverflow{stackLen: sLen, limit: operation.maxStack} } // for tracing: this gas consumption event is emitted below in the debug section. - if contract.Gas < cost { + if contract.Gas.RegularGas < cost { return nil, ErrOutOfGas } else { - contract.Gas -= cost + contract.Gas.RegularGas -= cost } // All ops with a dynamic memory usage also has a dynamic gas cost. @@ -218,17 +218,17 @@ func (evm *EVM) Run(contract *Contract, input []byte, readOnly bool) (ret []byte } // Consume the gas and return an error if not enough gas is available. // cost is explicitly set so that the capture state defer method can get the proper cost - var dynamicCost uint64 + var dynamicCost GasCosts dynamicCost, err = operation.dynamicGas(evm, contract, stack, mem, memorySize) - cost += dynamicCost // for tracing + cost += dynamicCost.RegularGas // for tracing if err != nil { return nil, fmt.Errorf("%w: %v", ErrOutOfGas, err) } // for tracing: this gas consumption event is emitted below in the debug section. - if contract.Gas < dynamicCost { + if contract.Gas.Underflow(dynamicCost) { return nil, ErrOutOfGas } else { - contract.Gas -= dynamicCost + contract.Gas.Sub(dynamicCost) } } diff --git a/core/vm/interpreter_test.go b/core/vm/interpreter_test.go index f0bf9cf1e4..1c27b2c752 100644 --- a/core/vm/interpreter_test.go +++ b/core/vm/interpreter_test.go @@ -55,7 +55,7 @@ func TestLoopInterrupt(t *testing.T) { timeout := make(chan bool) go func(evm *EVM) { - _, _, err := evm.Call(common.Address{}, address, nil, math.MaxUint64, new(uint256.Int)) + _, _, err := evm.Call(common.Address{}, address, nil, GasCosts{RegularGas: math.MaxUint64}, new(uint256.Int)) errChannel <- err }(evm) @@ -85,7 +85,7 @@ func BenchmarkInterpreter(b *testing.B) { value = uint256.NewInt(0) stack = newstack() mem = NewMemory() - contract = NewContract(common.Address{}, common.Address{}, value, startGas, nil) + contract = NewContract(common.Address{}, common.Address{}, value, GasCosts{RegularGas: startGas, StateGas: 0}, nil) ) stack.push(uint256.NewInt(123)) stack.push(uint256.NewInt(123)) diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index a2e2c91194..c6fb57021b 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -24,7 +24,7 @@ import ( type ( executionFunc func(pc *uint64, evm *EVM, callContext *ScopeContext) ([]byte, error) - gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 + gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (GasCosts, error) // last parameter is the requested memory size as a uint64 // memorySizeFunc returns the required size, and whether the operation overflowed a uint64 memorySizeFunc func(*Stack) (size uint64, overflow bool) ) @@ -97,6 +97,7 @@ func newAmsterdamInstructionSet() JumpTable { instructionSet := newOsakaInstructionSet() enable7843(&instructionSet) // EIP-7843 (SLOTNUM opcode) enable8024(&instructionSet) // EIP-8024 (Backward compatible SWAPN, DUPN, EXCHANGE) + enable8037(&instructionSet) // EIP-8037 (State creation gas cost increase) return validate(instructionSet) } diff --git a/core/vm/operations_acl.go b/core/vm/operations_acl.go index 716a82ab97..f087d93322 100644 --- a/core/vm/operations_acl.go +++ b/core/vm/operations_acl.go @@ -27,24 +27,24 @@ import ( ) func makeGasSStoreFunc(clearingRefund uint64) gasFunc { - return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { if evm.readOnly { - return 0, ErrWriteProtection + return GasCosts{}, ErrWriteProtection } // If we fail the minimum gas availability invariant, fail (0) - if contract.Gas <= params.SstoreSentryGasEIP2200 { - return 0, errors.New("not enough gas for reentrancy sentry") + if contract.Gas.RegularGas <= params.SstoreSentryGasEIP2200 { + return GasCosts{}, errors.New("not enough gas for reentrancy sentry") } // Gas sentry honoured, do the actual gas calculation based on the stored value var ( y, x = stack.Back(1), stack.peek() slot = common.Hash(x.Bytes32()) current, original = evm.StateDB.GetStateAndCommittedState(contract.Address(), slot) - cost = uint64(0) + cost = GasCosts{RegularGas: 0} ) // Check slot presence in the access list if _, slotPresent := evm.StateDB.SlotInAccessList(contract.Address(), slot); !slotPresent { - cost = params.ColdSloadCostEIP2929 + cost = GasCosts{RegularGas: params.ColdSloadCostEIP2929} // If the caller cannot afford the cost, this change will be rolled back evm.StateDB.AddSlotToAccessList(contract.Address(), slot) } @@ -53,18 +53,18 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc { if current == value { // noop (1) // EIP 2200 original clause: // return params.SloadGasEIP2200, nil - return cost + params.WarmStorageReadCostEIP2929, nil // SLOAD_GAS + return GasCosts{RegularGas: cost.RegularGas + params.WarmStorageReadCostEIP2929}, nil // SLOAD_GAS } if original == current { if original == (common.Hash{}) { // create slot (2.1.1) - return cost + params.SstoreSetGasEIP2200, nil + return GasCosts{RegularGas: cost.RegularGas + params.SstoreSetGasEIP2200}, nil } if value == (common.Hash{}) { // delete slot (2.1.2b) evm.StateDB.AddRefund(clearingRefund) } // EIP-2200 original clause: // return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2) - return cost + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929), nil // write existing slot (2.1.2) + return GasCosts{RegularGas: cost.RegularGas + (params.SstoreResetGasEIP2200 - params.ColdSloadCostEIP2929)}, nil // write existing slot (2.1.2) } if original != (common.Hash{}) { if current == (common.Hash{}) { // recreate slot (2.2.1.1) @@ -89,7 +89,7 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc { } // EIP-2200 original clause: //return params.SloadGasEIP2200, nil // dirty update (2.2) - return cost + params.WarmStorageReadCostEIP2929, nil // dirty update (2.2) + return GasCosts{RegularGas: cost.RegularGas + params.WarmStorageReadCostEIP2929}, nil // dirty update (2.2) } } @@ -98,7 +98,7 @@ func makeGasSStoreFunc(clearingRefund uint64) gasFunc { // whose storage is being read) is not yet in accessed_storage_keys, // charge 2100 gas and add the pair to accessed_storage_keys. // If the pair is already in accessed_storage_keys, charge 100 gas. -func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { loc := stack.peek() slot := common.Hash(loc.Bytes32()) // Check slot presence in the access list @@ -106,9 +106,9 @@ func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me // If the caller cannot afford the cost, this change will be rolled back // If he does afford it, we can skip checking the same thing later on, during execution evm.StateDB.AddSlotToAccessList(contract.Address(), slot) - return params.ColdSloadCostEIP2929, nil + return GasCosts{RegularGas: params.ColdSloadCostEIP2929}, nil } - return params.WarmStorageReadCostEIP2929, nil + return GasCosts{RegularGas: params.WarmStorageReadCostEIP2929}, nil } // gasExtCodeCopyEIP2929 implements extcodecopy according to EIP-2929 @@ -116,11 +116,11 @@ func gasSLoadEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, me // > If the target is not in accessed_addresses, // > charge COLD_ACCOUNT_ACCESS_COST gas, and add the address to accessed_addresses. // > Otherwise, charge WARM_STORAGE_READ_COST gas. -func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { // memory expansion first (dynamic part of pre-2929 implementation) gas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } addr := common.Address(stack.peek().Bytes20()) // Check slot presence in the access list @@ -128,8 +128,8 @@ func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memo evm.StateDB.AddAddressToAccessList(addr) var overflow bool // We charge (cold-warm), since 'warm' is already charged as constantGas - if gas, overflow = math.SafeAdd(gas, params.ColdAccountAccessCostEIP2929-params.WarmStorageReadCostEIP2929); overflow { - return 0, ErrGasUintOverflow + if gas.RegularGas, overflow = math.SafeAdd(gas.RegularGas, params.ColdAccountAccessCostEIP2929-params.WarmStorageReadCostEIP2929); overflow { + return GasCosts{}, ErrGasUintOverflow } return gas, nil } @@ -143,16 +143,16 @@ func gasExtCodeCopyEIP2929(evm *EVM, contract *Contract, stack *Stack, mem *Memo // - extcodehash, // - extcodesize, // - (ext) balance -func gasEip2929AccountCheck(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasEip2929AccountCheck(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { addr := common.Address(stack.peek().Bytes20()) // Check slot presence in the access list if !evm.StateDB.AddressInAccessList(addr) { // If the caller cannot afford the cost, this change will be rolled back evm.StateDB.AddAddressToAccessList(addr) // The warm storage read cost is already charged as constantGas - return params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929, nil + return GasCosts{RegularGas: params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929}, nil } - return 0, nil + return GasCosts{RegularGas: 0}, nil } var ( @@ -186,13 +186,13 @@ var ( // makeSelfdestructGasFn can create the selfdestruct dynamic gas function for EIP-2929 and EIP-3529 func makeSelfdestructGasFn(refundsEnabled bool) gasFunc { - gasFunc := func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gasFunc := func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { var ( gas uint64 address = common.Address(stack.peek().Bytes20()) ) if evm.readOnly { - return 0, ErrWriteProtection + return GasCosts{}, ErrWriteProtection } if !evm.StateDB.AddressInAccessList(address) { // If the caller cannot afford the cost, this change will be rolled back @@ -201,12 +201,12 @@ func makeSelfdestructGasFn(refundsEnabled bool) gasFunc { // Terminate the gas measurement if the leftover gas is not sufficient, // it can effectively prevent accessing the states in the following steps - if contract.Gas < gas { - return 0, ErrOutOfGas + if contract.Gas.RegularGas < gas { + return GasCosts{}, ErrOutOfGas } } - if contract.Gas < gas { - return gas, nil + if contract.Gas.RegularGas < gas { + return GasCosts{RegularGas: gas}, nil } // if empty and transfers value @@ -216,7 +216,7 @@ func makeSelfdestructGasFn(refundsEnabled bool) gasFunc { if refundsEnabled && !evm.StateDB.HasSelfDestructed(contract.Address()) { evm.StateDB.AddRefund(params.SelfdestructRefundGas) } - return gas, nil + return GasCosts{RegularGas: gas}, nil } return gasFunc } @@ -229,9 +229,9 @@ var ( ) func makeCallVariantGasCall(oldCalculatorStateful, oldCalculatorStateless gasFunc) gasFunc { - return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { var ( - eip150BaseGas uint64 // gas used for memory expansion, transfer costs -> input to the 63/64 bounding + eip150BaseGas GasCosts // gas used for memory expansion, transfer costs -> input to the 63/64 bounding eip7702Gas uint64 eip2929Gas uint64 addr = common.Address(stack.Back(1).Bytes20()) @@ -247,20 +247,20 @@ func makeCallVariantGasCall(oldCalculatorStateful, oldCalculatorStateless gasFun coldCost := params.ColdAccountAccessCostEIP2929 - params.WarmStorageReadCostEIP2929 // Charge the remaining difference here already, to correctly calculate available // gas for call - if !contract.UseGas(coldCost, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { - return 0, ErrOutOfGas + if !contract.UseGas(GasCosts{RegularGas: coldCost}, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { + return GasCosts{}, ErrOutOfGas } eip2929Gas = coldCost } eip150BaseGas, err = oldCalculatorStateless(evm, contract, stack, mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } // ensure the portion of the call cost which doesn't depend on state lookups // is covered by the provided gas - if contract.Gas < eip150BaseGas { - return 0, ErrOutOfGas + if contract.Gas.RegularGas < eip150BaseGas.RegularGas { + return GasCosts{}, ErrOutOfGas } oldStateful, err := oldCalculatorStateful(evm, contract, stack, mem, memorySize) @@ -269,15 +269,15 @@ func makeCallVariantGasCall(oldCalculatorStateful, oldCalculatorStateless gasFun } // this should cause BAL test failures if uncommented - baseCost, overflow := math.SafeAdd(eip150BaseGas, oldStateful) + baseCost, overflow := math.SafeAdd(eip150BaseGas.RegularGas, oldStateful.RegularGas) if overflow { - return 0, ErrGasUintOverflow - } else if contract.Gas < baseCost { - return 0, ErrOutOfGas + return GasCosts{}, ErrGasUintOverflow + } else if contract.Gas.RegularGas < baseCost { + return GasCosts{}, ErrOutOfGas } - if eip150BaseGas, overflow = math.SafeAdd(eip150BaseGas, oldStateful); overflow { - return 0, ErrOutOfGas + if eip150BaseGas.RegularGas, overflow = math.SafeAdd(eip150BaseGas.RegularGas, oldStateful.RegularGas); overflow { + return GasCosts{}, ErrOutOfGas } if evm.chainRules.IsPrague { @@ -289,15 +289,30 @@ func makeCallVariantGasCall(oldCalculatorStateful, oldCalculatorStateless gasFun evm.StateDB.AddAddressToAccessList(target) eip7702Gas = params.ColdAccountAccessCostEIP2929 } - if !contract.UseGas(eip7702Gas, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { - return 0, ErrOutOfGas + if !contract.UseGas(GasCosts{RegularGas: eip7702Gas}, evm.Config.Tracer, tracing.GasChangeCallStorageColdAccess) { + return GasCosts{}, ErrOutOfGas } } } - evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, eip150BaseGas, stack.Back(0)) + // EIP-8037: Charge state gas for new account creation BEFORE the 63/64 + // child gas allocation. State gas that spills from an empty reservoir to + // regular gas must reduce the gas available for callGasTemp, otherwise + // the Underflow check in UseGas will fail when the spillover exceeds the + // tiny 1/64 remainder after child gas allocation. + var stateGasCharged uint64 + if evm.chainRules.IsAmsterdam && oldStateful.StateGas > 0 { + stateGasCharged = oldStateful.StateGas + stateGasCost := GasCosts{StateGas: stateGasCharged} + if contract.Gas.Underflow(stateGasCost) { + return GasCosts{}, ErrOutOfGas + } + contract.Gas.Sub(stateGasCost) + } + + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas.RegularGas, eip150BaseGas.RegularGas, stack.Back(0)) if err != nil { - return 0, err + return GasCosts{}, err } // TODO: it's not clear what happens if there is enough gas to cover the stateless component @@ -308,29 +323,36 @@ func makeCallVariantGasCall(oldCalculatorStateful, oldCalculatorStateless gasFun // adding it to the return, it will be charged outside of this function, as // part of the dynamic gas. This will ensure it is correctly reported to // tracers. - contract.Gas, overflow = math.SafeAdd(contract.Gas, eip2929Gas) + contract.Gas.RegularGas, overflow = math.SafeAdd(contract.Gas.RegularGas, eip2929Gas) if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - contract.Gas, overflow = math.SafeAdd(contract.Gas, eip7702Gas) + contract.Gas.RegularGas, overflow = math.SafeAdd(contract.Gas.RegularGas, eip7702Gas) if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } var totalCost uint64 totalCost, overflow = math.SafeAdd(eip2929Gas, eip7702Gas) if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } totalCost, overflow = math.SafeAdd(totalCost, evm.callGasTemp) if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - totalCost, overflow = math.SafeAdd(totalCost, eip150BaseGas) + totalCost, overflow = math.SafeAdd(totalCost, eip150BaseGas.RegularGas) if overflow { - return 0, ErrGasUintOverflow + return GasCosts{}, ErrGasUintOverflow } - return totalCost, nil + // If state gas was already charged directly (Amsterdam), don't include + // it in the returned cost — it would be double-charged by the + // interpreter's UseGas/Sub which increments TotalStateGasCharged again. + returnedStateGas := oldStateful.StateGas + if stateGasCharged > 0 { + returnedStateGas = 0 + } + return GasCosts{RegularGas: totalCost, StateGas: returnedStateGas}, nil } } diff --git a/core/vm/operations_verkle.go b/core/vm/operations_verkle.go index 30f9957775..4d09f54c1d 100644 --- a/core/vm/operations_verkle.go +++ b/core/vm/operations_verkle.go @@ -24,40 +24,40 @@ import ( "github.com/ethereum/go-ethereum/params" ) -func gasSStore4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), true, contract.Gas, true), nil +func gasSStore4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + return GasCosts{RegularGas: evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), true, contract.Gas.RegularGas, true)}, nil } -func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), false, contract.Gas, true), nil +func gasSLoad4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { + return GasCosts{RegularGas: evm.AccessEvents.SlotGas(contract.Address(), stack.peek().Bytes32(), false, contract.Gas.RegularGas, true)}, nil } -func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasBalance4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { address := stack.peek().Bytes20() - return evm.AccessEvents.BasicDataGas(address, false, contract.Gas, true), nil + return GasCosts{RegularGas: evm.AccessEvents.BasicDataGas(address, false, contract.Gas.RegularGas, true)}, nil } -func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExtCodeSize4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { address := stack.peek().Bytes20() if _, isPrecompile := evm.precompile(address); isPrecompile { - return 0, nil + return GasCosts{}, nil } - return evm.AccessEvents.BasicDataGas(address, false, contract.Gas, true), nil + return GasCosts{RegularGas: evm.AccessEvents.BasicDataGas(address, false, contract.Gas.RegularGas, true)}, nil } -func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExtCodeHash4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { address := stack.peek().Bytes20() if _, isPrecompile := evm.precompile(address); isPrecompile { - return 0, nil + return GasCosts{}, nil } - return evm.AccessEvents.CodeHashGas(address, false, contract.Gas, true), nil + return GasCosts{RegularGas: evm.AccessEvents.CodeHashGas(address, false, contract.Gas.RegularGas, true)}, nil } func makeCallVariantGasEIP4762(oldCalculator gasFunc, withTransferCosts bool) gasFunc { - return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { var ( target = common.Address(stack.Back(1).Bytes20()) - witnessGas uint64 + witnessGas GasCosts _, isPrecompile = evm.precompile(target) isSystemContract = target == params.HistoryStorageAddress ) @@ -65,38 +65,38 @@ func makeCallVariantGasEIP4762(oldCalculator gasFunc, withTransferCosts bool) ga // If value is transferred, it is charged before 1/64th // is subtracted from the available gas pool. if withTransferCosts && !stack.Back(2).IsZero() { - wantedValueTransferWitnessGas := evm.AccessEvents.ValueTransferGas(contract.Address(), target, contract.Gas) - if wantedValueTransferWitnessGas > contract.Gas { - return wantedValueTransferWitnessGas, nil + wantedValueTransferWitnessGas := evm.AccessEvents.ValueTransferGas(contract.Address(), target, contract.Gas.RegularGas) + if wantedValueTransferWitnessGas > contract.Gas.RegularGas { + return GasCosts{RegularGas: wantedValueTransferWitnessGas}, nil } - witnessGas = wantedValueTransferWitnessGas + witnessGas = GasCosts{RegularGas: wantedValueTransferWitnessGas} } else if isPrecompile || isSystemContract { - witnessGas = params.WarmStorageReadCostEIP2929 + witnessGas = GasCosts{RegularGas: params.WarmStorageReadCostEIP2929} } else { // The charging for the value transfer is done BEFORE subtracting // the 1/64th gas, as this is considered part of the CALL instruction. // (so before we get to this point) // But the message call is part of the subcall, for which only 63/64th // of the gas should be available. - wantedMessageCallWitnessGas := evm.AccessEvents.MessageCallGas(target, contract.Gas-witnessGas) + wantedMessageCallWitnessGas := evm.AccessEvents.MessageCallGas(target, contract.Gas.RegularGas-witnessGas.RegularGas) var overflow bool - if witnessGas, overflow = math.SafeAdd(witnessGas, wantedMessageCallWitnessGas); overflow { - return 0, ErrGasUintOverflow + if witnessGas.RegularGas, overflow = math.SafeAdd(witnessGas.RegularGas, wantedMessageCallWitnessGas); overflow { + return GasCosts{RegularGas: 0}, ErrGasUintOverflow } - if witnessGas > contract.Gas { + if witnessGas.RegularGas > contract.Gas.RegularGas { return witnessGas, nil } } - contract.Gas -= witnessGas + contract.Gas.Sub(witnessGas) // if the operation fails, adds witness gas to the gas before returning the error gas, err := oldCalculator(evm, contract, stack, mem, memorySize) - contract.Gas += witnessGas // restore witness gas so that it can be charged at the callsite + contract.Gas.Add(witnessGas) // restore witness gas so that it can be charged at the callsite var overflow bool - if gas, overflow = math.SafeAdd(gas, witnessGas); overflow { - return 0, ErrGasUintOverflow + if gas.RegularGas, overflow = math.SafeAdd(gas.RegularGas, witnessGas.RegularGas); overflow { + return GasCosts{}, ErrGasUintOverflow } - return gas, err + return GasCosts{RegularGas: gas.RegularGas}, err } } @@ -107,20 +107,20 @@ var ( gasDelegateCallEIP4762 = makeCallVariantGasEIP4762(gasDelegateCall, false) ) -func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { beneficiaryAddr := common.Address(stack.peek().Bytes20()) if _, isPrecompile := evm.precompile(beneficiaryAddr); isPrecompile { - return 0, nil + return GasCosts{}, nil } if contract.IsSystemCall { - return 0, nil + return GasCosts{}, nil } contractAddr := contract.Address() - wanted := evm.AccessEvents.BasicDataGas(contractAddr, false, contract.Gas, false) - if wanted > contract.Gas { - return wanted, nil + wanted := evm.AccessEvents.BasicDataGas(contractAddr, false, contract.Gas.RegularGas, false) + if wanted > contract.Gas.RegularGas { + return GasCosts{RegularGas: wanted}, nil } - statelessGas := wanted + statelessGas := GasCosts{RegularGas: wanted} balanceIsZero := evm.StateDB.GetBalance(contractAddr).Sign() == 0 _, isPrecompile := evm.precompile(beneficiaryAddr) isSystemContract := beneficiaryAddr == params.HistoryStorageAddress @@ -130,39 +130,39 @@ func gasSelfdestructEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Mem } if contractAddr != beneficiaryAddr { - wanted := evm.AccessEvents.BasicDataGas(beneficiaryAddr, false, contract.Gas-statelessGas, false) - if wanted > contract.Gas-statelessGas { - return statelessGas + wanted, nil + wanted := evm.AccessEvents.BasicDataGas(beneficiaryAddr, false, contract.Gas.RegularGas-statelessGas.RegularGas, false) + if wanted > contract.Gas.RegularGas-statelessGas.RegularGas { + return GasCosts{RegularGas: statelessGas.RegularGas + wanted}, nil } - statelessGas += wanted + statelessGas.RegularGas += wanted } // Charge write costs if it transfers value if !balanceIsZero { - wanted := evm.AccessEvents.BasicDataGas(contractAddr, true, contract.Gas-statelessGas, false) - if wanted > contract.Gas-statelessGas { - return statelessGas + wanted, nil + wanted := evm.AccessEvents.BasicDataGas(contractAddr, true, contract.Gas.RegularGas-statelessGas.RegularGas, false) + if wanted > contract.Gas.RegularGas-statelessGas.RegularGas { + return GasCosts{RegularGas: statelessGas.RegularGas + wanted}, nil } - statelessGas += wanted + statelessGas.RegularGas += wanted if contractAddr != beneficiaryAddr { if evm.StateDB.Exist(beneficiaryAddr) { - wanted = evm.AccessEvents.BasicDataGas(beneficiaryAddr, true, contract.Gas-statelessGas, false) + wanted = evm.AccessEvents.BasicDataGas(beneficiaryAddr, true, contract.Gas.RegularGas-statelessGas.RegularGas, false) } else { - wanted = evm.AccessEvents.AddAccount(beneficiaryAddr, true, contract.Gas-statelessGas) + wanted = evm.AccessEvents.AddAccount(beneficiaryAddr, true, contract.Gas.RegularGas-statelessGas.RegularGas) } - if wanted > contract.Gas-statelessGas { - return statelessGas + wanted, nil + if wanted > contract.Gas.RegularGas-statelessGas.RegularGas { + return GasCosts{RegularGas: statelessGas.RegularGas + wanted}, nil } - statelessGas += wanted + statelessGas.RegularGas += wanted } } return statelessGas, nil } -func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { gas, err := gasCodeCopy(evm, contract, stack, mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } if !contract.IsDeployment && !contract.IsSystemCall { var ( @@ -175,31 +175,31 @@ func gasCodeCopyEip4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, } _, copyOffset, nonPaddedCopyLength := getDataAndAdjustedBounds(contract.Code, uint64CodeOffset, length.Uint64()) - _, wanted := evm.AccessEvents.CodeChunksRangeGas(contract.Address(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false, contract.Gas-gas) - gas += wanted + _, wanted := evm.AccessEvents.CodeChunksRangeGas(contract.Address(), copyOffset, nonPaddedCopyLength, uint64(len(contract.Code)), false, contract.Gas.RegularGas-gas.RegularGas) + gas.RegularGas += wanted } return gas, nil } -func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExtCodeCopyEIP4762(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (GasCosts, error) { // memory expansion first (dynamic part of pre-2929 implementation) gas, err := gasExtCodeCopy(evm, contract, stack, mem, memorySize) if err != nil { - return 0, err + return GasCosts{}, err } addr := common.Address(stack.peek().Bytes20()) _, isPrecompile := evm.precompile(addr) if isPrecompile || addr == params.HistoryStorageAddress { var overflow bool - if gas, overflow = math.SafeAdd(gas, params.WarmStorageReadCostEIP2929); overflow { - return 0, ErrGasUintOverflow + if gas.RegularGas, overflow = math.SafeAdd(gas.RegularGas, params.WarmStorageReadCostEIP2929); overflow { + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas.RegularGas}, nil } - wgas := evm.AccessEvents.BasicDataGas(addr, false, contract.Gas-gas, true) + wgas := evm.AccessEvents.BasicDataGas(addr, false, contract.Gas.RegularGas-gas.RegularGas, true) var overflow bool - if gas, overflow = math.SafeAdd(gas, wgas); overflow { - return 0, ErrGasUintOverflow + if gas.RegularGas, overflow = math.SafeAdd(gas.RegularGas, wgas); overflow { + return GasCosts{}, ErrGasUintOverflow } - return gas, nil + return GasCosts{RegularGas: gas.RegularGas}, nil } diff --git a/core/vm/runtime/runtime.go b/core/vm/runtime/runtime.go index b40e99d047..49a7e809da 100644 --- a/core/vm/runtime/runtime.go +++ b/core/vm/runtime/runtime.go @@ -146,11 +146,11 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) { cfg.Origin, common.BytesToAddress([]byte("contract")), input, - cfg.GasLimit, + vm.GasCosts{RegularGas: cfg.GasLimit}, uint256.MustFromBig(cfg.Value), ) if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxEnd != nil { - cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err) + cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas.RegularGas}, err) } return ret, cfg.State, err } @@ -180,13 +180,13 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) { code, address, leftOverGas, err := vmenv.Create( cfg.Origin, input, - cfg.GasLimit, + vm.GasCosts{RegularGas: cfg.GasLimit}, uint256.MustFromBig(cfg.Value), ) if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxEnd != nil { - cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err) + cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas.RegularGas}, err) } - return code, address, leftOverGas, err + return code, address, leftOverGas.RegularGas, err } // Call executes the code given by the contract's address. It will return the @@ -215,11 +215,11 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er cfg.Origin, address, input, - cfg.GasLimit, + vm.GasCosts{RegularGas: cfg.GasLimit}, uint256.MustFromBig(cfg.Value), ) if cfg.EVMConfig.Tracer != nil && cfg.EVMConfig.Tracer.OnTxEnd != nil { - cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas}, err) + cfg.EVMConfig.Tracer.OnTxEnd(&types.Receipt{GasUsed: cfg.GasLimit - leftOverGas.RegularGas}, err) } - return ret, leftOverGas, err + return ret, leftOverGas.RegularGas, err } diff --git a/eth/tracers/js/tracer_test.go b/eth/tracers/js/tracer_test.go index b21e104abc..0a35efe71f 100644 --- a/eth/tracers/js/tracer_test.go +++ b/eth/tracers/js/tracer_test.go @@ -55,7 +55,7 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo gasLimit uint64 = 31000 startGas uint64 = 10000 value = uint256.NewInt(0) - contract = vm.NewContract(common.Address{}, common.Address{}, value, startGas, nil) + contract = vm.NewContract(common.Address{}, common.Address{}, value, vm.GasCosts{RegularGas: startGas}, nil) ) evm.SetTxContext(vmctx.txCtx) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x1, 0x0} @@ -66,9 +66,9 @@ func runTrace(tracer *tracers.Tracer, vmctx *vmContext, chaincfg *params.ChainCo tracer.OnTxStart(evm.GetVMContext(), types.NewTx(&types.LegacyTx{Gas: gasLimit, GasPrice: vmctx.txCtx.GasPrice.ToBig()}), contract.Caller()) tracer.OnEnter(0, byte(vm.CALL), contract.Caller(), contract.Address(), []byte{}, startGas, value.ToBig()) ret, err := evm.Run(contract, []byte{}, false) - tracer.OnExit(0, ret, startGas-contract.Gas, err, true) + tracer.OnExit(0, ret, startGas-contract.Gas.RegularGas, err, true) // Rest gas assumes no refund - tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas}, nil) + tracer.OnTxEnd(&types.Receipt{GasUsed: gasLimit - contract.Gas.RegularGas}, nil) if err != nil { return nil, err } @@ -183,7 +183,7 @@ func TestHaltBetweenSteps(t *testing.T) { t.Fatal(err) } scope := &vm.ScopeContext{ - Contract: vm.NewContract(common.Address{}, common.Address{}, uint256.NewInt(0), 0, nil), + Contract: vm.NewContract(common.Address{}, common.Address{}, uint256.NewInt(0), vm.GasCosts{}, nil), } evm := vm.NewEVM(vm.BlockContext{BlockNumber: big.NewInt(1)}, &dummyStatedb{}, chainConfig, vm.Config{Tracer: tracer.Hooks}) evm.SetTxContext(vm.TxContext{GasPrice: uint256.NewInt(1)}) @@ -281,7 +281,7 @@ func TestEnterExit(t *testing.T) { t.Fatal(err) } scope := &vm.ScopeContext{ - Contract: vm.NewContract(common.Address{}, common.Address{}, uint256.NewInt(0), 0, nil), + Contract: vm.NewContract(common.Address{}, common.Address{}, uint256.NewInt(0), vm.GasCosts{}, nil), } tracer.OnEnter(1, byte(vm.CALL), scope.Contract.Caller(), scope.Contract.Address(), []byte{}, 1000, new(big.Int)) tracer.OnExit(1, []byte{}, 400, nil, false) diff --git a/eth/tracers/logger/logger_test.go b/eth/tracers/logger/logger_test.go index acc3069e70..4deca8fad9 100644 --- a/eth/tracers/logger/logger_test.go +++ b/eth/tracers/logger/logger_test.go @@ -47,7 +47,7 @@ func TestStoreCapture(t *testing.T) { var ( logger = NewStructLogger(nil) evm = vm.NewEVM(vm.BlockContext{}, &dummyStatedb{}, params.TestChainConfig, vm.Config{Tracer: logger.Hooks()}) - contract = vm.NewContract(common.Address{}, common.Address{}, new(uint256.Int), 100000, nil) + contract = vm.NewContract(common.Address{}, common.Address{}, new(uint256.Int), vm.GasCosts{RegularGas: 100000}, nil) ) contract.Code = []byte{byte(vm.PUSH1), 0x1, byte(vm.PUSH1), 0x0, byte(vm.SSTORE)} var index common.Hash diff --git a/internal/ethapi/api.go b/internal/ethapi/api.go index 6c65bff69e..ca388b69e7 100644 --- a/internal/ethapi/api.go +++ b/internal/ethapi/api.go @@ -1322,6 +1322,7 @@ func AccessList(ctx context.Context, b Backend, blockNrOrHash rpc.BlockNumberOrH } // Prevent redundant operations if args contain more authorizations than EVM may handle + // TODO change with EIP-8037 maxAuthorizations := uint64(*args.Gas) / params.CallNewAccountGas if uint64(len(args.AuthorizationList)) > maxAuthorizations { return nil, 0, nil, errors.New("insufficient gas to process all authorizations") diff --git a/miner/worker.go b/miner/worker.go index 3e53353071..6e5c92dddb 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -200,8 +200,10 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay } postMut.Merge(mut) - work.accessList.AccumulateMutations(postMut, uint16(work.tcount)+1) - work.accessList.AccumulateReads(work.state.Reader().(state.StateReaderTracker).GetStateAccessList()) + if work.accessList != nil { + work.accessList.AccumulateMutations(postMut, uint16(work.tcount)+1) + work.accessList.AccumulateReads(work.state.Reader().(state.StateReaderTracker).GetStateAccessList()) + } } if requests != nil { reqHash := types.CalcRequestsHash(requests) @@ -223,6 +225,10 @@ func (miner *Miner) generateWork(genParam *generateParams, witness bool) *newPay } } + // EIP-8037: set header.GasUsed before FinalizeAndAssemble so the block + // header reflects the correct 2D gas metric max(sum_regular, sum_state). + work.header.GasUsed = work.gasPool.Used() + block, err := miner.engine.FinalizeAndAssemble(miner.chain, work.header, work.state, &body, work.receipts, onBlockFinalization) if err != nil { return &newPayloadResult{err: err} @@ -329,7 +335,9 @@ func (miner *Miner) prepareWork(genParams *generateParams, witness bool) (*envir if miner.chainConfig.IsPrague(header.Number, header.Time) { mut.Merge(core.ProcessParentBlockHash(header.ParentHash, env.evm)) } - env.accessList.AccumulateMutations(mut, 0) + if env.accessList != nil { + env.accessList.AccumulateMutations(mut, 0) + } return env, nil } @@ -430,6 +438,8 @@ func (miner *Miner) applyTransaction(env *environment, tx *types.Transaction) (* prevReader = env.state.Reader() stateCopy = env.state.WithReader(state.NewReaderWithTracker(env.state.Reader())) env.evm.StateDB = stateCopy + } else { + stateCopy = env.state } mutations, receipt, err := core.ApplyTransaction(env.evm, env.gasPool, stateCopy, env.header, tx) diff --git a/params/protocol_params.go b/params/protocol_params.go index 652574287c..f2c6b5f1c9 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -88,6 +88,7 @@ const ( LogTopicGas uint64 = 375 // Multiplied by the * of the LOG*, per LOG transaction. e.g. LOG0 incurs 0 * c_txLogTopicGas, LOG4 incurs 4 * c_txLogTopicGas. CreateGas uint64 = 32000 // Once per CREATE operation & contract-creation transaction. Create2Gas uint64 = 32000 // Once per CREATE2 operation + CreateGasAmsterdam uint64 = 9000 // Regular gas portion of CREATE in Amsterdam (EIP-8037); state gas is charged separately. CreateNGasEip4762 uint64 = 1000 // Once per CREATEn operations post-verkle SelfdestructRefundGas uint64 = 24000 // Refunded following a selfdestruct operation. MemoryGas uint64 = 3 // Times the address of the (highest referenced byte in memory + 1). NOTE: referencing happens on read, write and in instructions such as RETURN and CALL. @@ -99,6 +100,7 @@ const ( TxAccessListAddressGas uint64 = 2400 // Per address specified in EIP 2930 access list TxAccessListStorageKeyGas uint64 = 1900 // Per storage key specified in EIP 2930 access list TxAuthTupleGas uint64 = 12500 // Per auth tuple code specified in EIP-7702 + TxAuthTupleRegularGas uint64 = 7500 // Per auth tuple regular gas specified in EIP-8037 // These have been changed during the course of the chain CallGasFrontier uint64 = 40 // Once per CALL operation & message call transaction. @@ -185,6 +187,13 @@ const ( HistoryServeWindow = 8191 // Number of blocks to serve historical block hashes for, EIP-2935. MaxBlockSize = 8_388_608 // maximum size of an RLP-encoded block + + TargetStateGrowthPerYear = 100 * 1024 * 1024 * 1024 // 100GB + AccountCreationSize = 112 + StorageCreationSize = 32 + AuthorizationCreationSize = 23 + + GasBlockAccessListItem = 2000 // EIP-7928: gas cost per BAL item for gas limit check ) // Bls12381G1MultiExpDiscountTable is the gas discount table for BLS12-381 G1 multi exponentiation operation diff --git a/tests/block_test.go b/tests/block_test.go index ba2e71c499..e911c12e23 100644 --- a/tests/block_test.go +++ b/tests/block_test.go @@ -133,12 +133,15 @@ func TestBlockchain(t *testing.T) { // which run natively, so there's no reason to run them here. } -func testExecutionSpecBlocktests(t *testing.T, testDir string) { +func testExecutionSpecBlocktests(t *testing.T, testDir string, skip []string) { if !common.FileExist(testDir) { t.Skipf("directory %s does not exist", testDir) } bt := new(testMatcher) + for _, skipTest := range skip { + bt.skipLoad(skipTest) + } // These tests require us to handle scenarios where a system contract is not deployed at a fork bt.skipLoad(".*prague/eip7251_consolidations/test_system_contract_deployment.json") bt.skipLoad(".*prague/eip7002_el_triggerable_withdrawals/test_system_contract_deployment.json") @@ -150,12 +153,719 @@ func testExecutionSpecBlocktests(t *testing.T, testDir string) { // TestExecutionSpecBlocktests runs the test fixtures from execution-spec-tests. func TestExecutionSpecBlocktests(t *testing.T) { - testExecutionSpecBlocktests(t, executionSpecBlockchainTestDir) + testExecutionSpecBlocktests(t, executionSpecBlockchainTestDir, []string{}) } // TestExecutionSpecBlocktestsBAL runs the BAL release test fixtures from execution-spec-tests. func TestExecutionSpecBlocktestsBAL(t *testing.T) { - testExecutionSpecBlocktests(t, executionSpecBALBlockchainTestDir) + skips := []string{ + ".*/Cancun/stEIP1153_transientStorage/10_revertUndoesStoreAfterReturnFiller.yml", + ".*/Cancun/stEIP1153_transientStorage/14_revertAfterNestedStaticcallFiller.yml", + ".*/Cancun/stEIP1153_transientStorage/17_tstoreGasFiller.yml", + ".*/Cancun/stEIP4844_blobtransactions/createBlobhashTxFiller.yml", + ".*/Cancun/stEIP5656_MCOPY/MCOPY_copy_costFiller.yml", + ".*/Cancun/stEIP5656_MCOPY/MCOPY_memory_expansion_costFiller.yml", + ".*/Cancun/stEIP5656_MCOPY/MCOPY_memory_hashFiller.yml", + ".*/Cancun/stEIP5656_MCOPY/MCOPYFiller.yml", + ".*/Shanghai/stEIP3855_push0/push0GasFiller.yml", + ".*/Shanghai/stEIP3860_limitmeterinitcode/create2InitCodeSizeLimitFiller.yml", + ".*/Shanghai/stEIP3860_limitmeterinitcode/createInitCodeSizeLimitFiller.yml", + ".*/Shanghai/stEIP3860_limitmeterinitcode/creationTxInitCodeSizeLimitFiller.yml", + ".*/stAttackTest/ContractCreationSpamFiller.json", + ".*/stAttackTest/CrashingTransactionFiller.json", + ".*/stBadOpcode/measureGasFiller.yml", + ".*/stBadOpcode/operationDiffGasFiller.yml", + ".*/stCallCodes/callcallcall_ABCB_RECURSIVEFiller.json", + ".*/stCallCodes/callcallcallcode_ABCB_RECURSIVEFiller.json", + ".*/stCallCodes/callcallcodecall_ABCB_RECURSIVEFiller.json", + ".*/stCallCodes/callcallcodecallcode_ABCB_RECURSIVEFiller.json", + ".*/stCallCodes/callcode_checkPCFiller.json", + ".*/stCallCodes/callcodecallcall_ABCB_RECURSIVEFiller.json", + ".*/stCallCodes/callcodecallcallcode_ABCB_RECURSIVEFiller.json", + ".*/stCallCodes/callcodecallcodecall_ABCB_RECURSIVEFiller.json", + ".*/stCallCodes/callcodecallcodecallcode_ABCB_RECURSIVEFiller.json", + ".*/stCallCreateCallCodeTest/Call1024OOGFiller.json", + ".*/stCallCreateCallCodeTest/Callcode1024OOGFiller.json", + ".*/stCallCreateCallCodeTest/CallcodeLoseGasOOGFiller.json", + ".*/stCallCreateCallCodeTest/CallLoseGasOOGFiller.json", + ".*/stCallCreateCallCodeTest/callWithHighValueOOGinCallFiller.json", + ".*/stCallCreateCallCodeTest/contractCreationMakeCallThatAskMoreGasThenTransactionProvidedFiller.json", + ".*/stCallCreateCallCodeTest/createFailBalanceTooLowFiller.json", + ".*/stCallCreateCallCodeTest/createInitFailBadJumpDestination2Filler.json", + ".*/stCallCreateCallCodeTest/createInitFailBadJumpDestinationFiller.json", + ".*/stCallCreateCallCodeTest/createInitFailStackSizeLargerThan1024Filler.json", + ".*/stCallCreateCallCodeTest/createInitFailStackUnderflowFiller.json", + ".*/stCallCreateCallCodeTest/createInitFailUndefinedInstruction2Filler.json", + ".*/stCallCreateCallCodeTest/createInitFailUndefinedInstructionFiller.json", + ".*/stCallCreateCallCodeTest/createNameRegistratorPerTxsFiller.json", + ".*/stCallCreateCallCodeTest/createNameRegistratorPerTxsNotEnoughGasFiller.json", + ".*/stCallCreateCallCodeTest/createNameRegistratorPreStore1NotEnoughGasFiller.json", + ".*/stCallDelegateCodesCallCodeHomestead/callcallcallcode_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesCallCodeHomestead/callcallcodecall_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesCallCodeHomestead/callcallcodecallcode_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesCallCodeHomestead/callcodecallcall_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesCallCodeHomestead/callcodecallcallcode_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesCallCodeHomestead/callcodecallcodecall_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesCallCodeHomestead/callcodecallcodecallcode_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesHomestead/callcallcallcode_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesHomestead/callcallcodecall_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesHomestead/callcallcodecallcode_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesHomestead/callcodecallcall_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesHomestead/callcodecallcallcode_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesHomestead/callcodecallcodecall_ABCB_RECURSIVEFiller.json", + ".*/stCallDelegateCodesHomestead/callcodecallcodecallcode_ABCB_RECURSIVEFiller.json", + ".*/stChainId/chainIdFiller.json", + ".*/stChainId/chainIdGasCostFiller.json", + ".*/stCodeCopyTest/ExtCodeCopyTargetRangeLongerThanCodeTestsFiller.json", + ".*/stCodeCopyTest/ExtCodeCopyTestsParisFiller.json", + ".*/stCreate2/call_outsize_then_create2_successful_then_returndatasizeFiller.json", + ".*/stCreate2/call_then_create2_successful_then_returndatasizeFiller.json", + ".*/stCreate2/CREATE2_FirstByte_loopFiller.yml", + ".*/stCreate2/create2callPrecompilesFiller.json", + ".*/stCreate2/Create2OOGafterInitCodeReturndata2Filler.json", + ".*/stCreate2/Create2OOGFromCallRefundsFiller.yml", + ".*/stCreate2/create2SmartInitCodeFiller.json", + ".*/stCreate2/CreateMessageRevertedFiller.json", + ".*/stCreate2/CreateMessageRevertedOOGInInit2Filler.json", + ".*/stCreate2/returndatacopy_0_0_following_successful_createFiller.json", + ".*/stCreate2/returndatacopy_afterFailing_createFiller.json", + ".*/stCreate2/returndatacopy_following_revert_in_createFiller.json", + ".*/stCreate2/returndatasize_following_successful_createFiller.json", + ".*/stCreate2/RevertDepthCreate2OOGBerlinFiller.json", + ".*/stCreate2/RevertDepthCreate2OOGFiller.json", + ".*/stCreate2/RevertDepthCreateAddressCollisionBerlinFiller.json", + ".*/stCreate2/RevertDepthCreateAddressCollisionFiller.json", + ".*/stCreate2/RevertOpcodeCreateFiller.json", + ".*/stCreate2/RevertOpcodeInCreateReturnsCreate2Filler.json", + ".*/stCreateTest/CodeInConstructorFiller.yml", + ".*/stCreateTest/CREATE_EContract_ThenCALLToNonExistentAccFiller.json", + ".*/stCreateTest/CREATE_EContractCreateNEContractInInitOOG_TrFiller.json", + ".*/stCreateTest/CREATE_EmptyContractAndCallIt_0weiFiller.json", + ".*/stCreateTest/CREATE_EmptyContractAndCallIt_1weiFiller.json", + ".*/stCreateTest/CREATE_EmptyContractFiller.json", + ".*/stCreateTest/CREATE_EmptyContractWithBalanceFiller.json", + ".*/stCreateTest/CREATE_EmptyContractWithStorageAndCallIt_0weiFiller.json", + ".*/stCreateTest/CREATE_EmptyContractWithStorageAndCallIt_1weiFiller.json", + ".*/stCreateTest/CREATE_EmptyContractWithStorageFiller.json", + ".*/stCreateTest/CreateAddressWarmAfterFailFiller.yml", + ".*/stCreateTest/CreateCollisionResultsFiller.yml", + ".*/stCreateTest/CreateCollisionToEmpty2Filler.json", + ".*/stCreateTest/CreateOOGafterInitCodeReturndata2Filler.json", + ".*/stCreateTest/CreateOOGafterInitCodeRevert2Filler.json", + ".*/stCreateTest/CreateOOGFromCallRefundsFiller.yml", + ".*/stCreateTest/CreateResultsFiller.yml", + ".*/stCreateTest/TransactionCollisionToEmpty2Filler.json", + ".*/stDelegatecallTestHomestead/Call1024OOGFiller.json", + ".*/stDelegatecallTestHomestead/CallcodeLoseGasOOGFiller.json", + ".*/stDelegatecallTestHomestead/CallLoseGasOOGFiller.json", + ".*/stDelegatecallTestHomestead/Delegatecall1024OOGFiller.json", + ".*/stDelegatecallTestHomestead/delegatecallOOGinCallFiller.json", + ".*/stEIP150singleCodeGasPrices/gasCostBerlinFiller.yml", + ".*/stEIP150singleCodeGasPrices/gasCostFiller.yml", + ".*/stEIP150singleCodeGasPrices/RawCallCodeGasAskFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallCodeGasFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallCodeGasMemoryAskFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallCodeGasMemoryFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallCodeGasValueTransferAskFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallCodeGasValueTransferFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallCodeGasValueTransferMemoryAskFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallCodeGasValueTransferMemoryFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallGasAskFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallGasFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallGasValueTransferAskFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallGasValueTransferFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallGasValueTransferMemoryAskFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallGasValueTransferMemoryFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallMemoryGasAskFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCallMemoryGasFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCreateFailGasValueTransfer2Filler.json", + ".*/stEIP150singleCodeGasPrices/RawCreateFailGasValueTransferFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCreateGasFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCreateGasMemoryFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCreateGasValueTransferFiller.json", + ".*/stEIP150singleCodeGasPrices/RawCreateGasValueTransferMemoryFiller.json", + ".*/stEIP150singleCodeGasPrices/RawDelegateCallGasAskFiller.json", + ".*/stEIP150singleCodeGasPrices/RawDelegateCallGasFiller.json", + ".*/stEIP150singleCodeGasPrices/RawDelegateCallGasMemoryAskFiller.json", + ".*/stEIP150singleCodeGasPrices/RawDelegateCallGasMemoryFiller.json", + ".*/stEIP150Specific/CallAskMoreGasOnDepth2ThenTransactionHasFiller.json", + ".*/stEIP150Specific/CreateAndGasInsideCreateFiller.json", + ".*/stEIP150Specific/DelegateCallOnEIPFiller.json", + ".*/stEIP150Specific/NewGasPriceForCodesFiller.json", + ".*/stEIP150Specific/Transaction64Rule_d64e0Filler.json", + ".*/stEIP150Specific/Transaction64Rule_d64m1Filler.json", + ".*/stEIP150Specific/Transaction64Rule_d64p1Filler.json", + ".*/stEIP1559/baseFeeDiffPlacesOsakaFiller.yml", + ".*/stEIP1559/gasPriceDiffPlacesOsakaFiller.yml", + ".*/stEIP158Specific/EXP_EmptyFiller.json", + ".*/stEIP2930/addressOpcodesFiller.yml", + ".*/stEIP2930/coinbaseT01Filler.yml", + ".*/stEIP2930/coinbaseT2Filler.yml", + ".*/stEIP2930/manualCreateFiller.yml", + ".*/stEIP2930/storageCostsFiller.yml", + ".*/stEIP2930/transactionCostsFiller.yml", + ".*/stEIP2930/variedContextFiller.yml", + ".*/stEIP3607/initCollidingWithNonEmptyAccountFiller.yml", + ".*/stEIP3607/transactionCollidingWithNonEmptyAccount_init_ParisFiller.yml", + ".*/stExample/add11_ymlFiller.yml", + ".*/stExample/add11Filler.json", + ".*/stExample/basefeeExampleFiller.yml", + ".*/stExample/indexesOmitExampleFiller.yml", + ".*/stExample/labelsExampleFiller.yml", + ".*/stExample/rangesExampleFiller.yml", + ".*/stExtCodeHash/callToNonExistentFiller.json", + ".*/stExtCodeHash/callToSuicideThenExtcodehashFiller.json", + ".*/stExtCodeHash/createEmptyThenExtcodehashFiller.json", + ".*/stInitCodeTest/CallContractToCreateContractAndCallItOOGFiller.json", + ".*/stInitCodeTest/CallContractToCreateContractOOGBonusGasFiller.json", + ".*/stInitCodeTest/CallContractToCreateContractWhichWouldCreateContractIfCalledFiller.json", + ".*/stInitCodeTest/CallContractToCreateContractWhichWouldCreateContractInInitCodeFiller.json", + ".*/stInitCodeTest/CallTheContractToCreateEmptyContractFiller.json", + ".*/stInitCodeTest/OutOfGasContractCreationFiller.json", + ".*/stInitCodeTest/OutOfGasPrefundedContractCreationFiller.json", + ".*/stInitCodeTest/ReturnTest2Filler.json", + ".*/stInitCodeTest/StackUnderFlowContractCreationFiller.json", + ".*/stInitCodeTest/TransactionCreateRandomInitCodeFiller.json", + ".*/stInitCodeTest/TransactionCreateSuicideInInitcodeFiller.json", + ".*/stMemExpandingEIP150Calls/CallAskMoreGasOnDepth2ThenTransactionHasWithMemExpandingCallsFiller.json", + ".*/stMemExpandingEIP150Calls/CallGoesOOGOnSecondLevelWithMemExpandingCallsFiller.json", + ".*/stMemExpandingEIP150Calls/CreateAndGasInsideCreateWithMemExpandingCallsFiller.json", + ".*/stMemExpandingEIP150Calls/NewGasPriceForCodesWithMemExpandingCallsFiller.json", + ".*/stMemoryStressTest/RETURN_BoundsFiller.json", + ".*/stMemoryStressTest/SSTORE_BoundsFiller.json", + ".*/stMemoryTest/calldatacopy_dejavu2Filler.json", + ".*/stMemoryTest/mem0b_singleByteFiller.json", + ".*/stMemoryTest/mem31b_singleByteFiller.json", + ".*/stMemoryTest/mem32b_singleByteFiller.json", + ".*/stMemoryTest/mem32kb_singleByte-1Filler.json", + ".*/stMemoryTest/mem32kb_singleByte-31Filler.json", + ".*/stMemoryTest/mem32kb_singleByte-32Filler.json", + ".*/stMemoryTest/mem32kb_singleByte-33Filler.json", + ".*/stMemoryTest/mem32kb_singleByte+1Filler.json", + ".*/stMemoryTest/mem32kb_singleByte+31Filler.json", + ".*/stMemoryTest/mem32kb_singleByte+32Filler.json", + ".*/stMemoryTest/mem32kb_singleByte+33Filler.json", + ".*/stMemoryTest/mem32kb_singleByteFiller.json", + ".*/stMemoryTest/mem32kb-1Filler.json", + ".*/stMemoryTest/mem32kb-31Filler.json", + ".*/stMemoryTest/mem32kb-32Filler.json", + ".*/stMemoryTest/mem32kb-33Filler.json", + ".*/stMemoryTest/mem32kb+1Filler.json", + ".*/stMemoryTest/mem32kb+31Filler.json", + ".*/stMemoryTest/mem32kb+32Filler.json", + ".*/stMemoryTest/mem32kb+33Filler.json", + ".*/stMemoryTest/mem32kbFiller.json", + ".*/stMemoryTest/mem33b_singleByteFiller.json", + ".*/stMemoryTest/mem64kb_singleByte-1Filler.json", + ".*/stMemoryTest/mem64kb_singleByte-31Filler.json", + ".*/stMemoryTest/mem64kb_singleByte-32Filler.json", + ".*/stMemoryTest/mem64kb_singleByte-33Filler.json", + ".*/stMemoryTest/mem64kb_singleByte+1Filler.json", + ".*/stMemoryTest/mem64kb_singleByte+31Filler.json", + ".*/stMemoryTest/mem64kb_singleByte+32Filler.json", + ".*/stMemoryTest/mem64kb_singleByte+33Filler.json", + ".*/stMemoryTest/mem64kb_singleByteFiller.json", + ".*/stMemoryTest/mem64kb-1Filler.json", + ".*/stMemoryTest/mem64kb-31Filler.json", + ".*/stMemoryTest/mem64kb-32Filler.json", + ".*/stMemoryTest/mem64kb-33Filler.json", + ".*/stMemoryTest/mem64kb+1Filler.json", + ".*/stMemoryTest/mem64kb+31Filler.json", + ".*/stMemoryTest/mem64kb+32Filler.json", + ".*/stMemoryTest/mem64kb+33Filler.json", + ".*/stMemoryTest/mem64kbFiller.json", + ".*/stMemoryTest/oogFiller.yml", + ".*/stNonZeroCallsTest/NonZeroValue_CALL_ToEmpty_ParisFiller.json", + ".*/stNonZeroCallsTest/NonZeroValue_CALL_ToOneStorageKey_ParisFiller.json", + ".*/stNonZeroCallsTest/NonZeroValue_CALLCODE_ToEmpty_ParisFiller.json", + ".*/stNonZeroCallsTest/NonZeroValue_CALLCODE_ToOneStorageKey_ParisFiller.json", + ".*/stNonZeroCallsTest/NonZeroValue_CALLCODEFiller.json", + ".*/stNonZeroCallsTest/NonZeroValue_CALLFiller.json", + ".*/stNonZeroCallsTest/NonZeroValue_DELEGATECALL_ToEmpty_ParisFiller.json", + ".*/stNonZeroCallsTest/NonZeroValue_DELEGATECALL_ToNonNonZeroBalanceFiller.json", + ".*/stNonZeroCallsTest/NonZeroValue_DELEGATECALL_ToOneStorageKey_ParisFiller.json", + ".*/stNonZeroCallsTest/NonZeroValue_DELEGATECALLFiller.json", + ".*/stPreCompiledContracts/precompsEIP2929CancunFiller.yml", + ".*/stPreCompiledContracts2/CallEcrecover_OverflowFiller.yml", + ".*/stPreCompiledContracts2/ecrecoverShortBuffFiller.yml", + ".*/stPreCompiledContracts2/modexp_0_0_0_22000Filler.json", + ".*/stPreCompiledContracts2/modexp_0_0_0_25000Filler.json", + ".*/stPreCompiledContracts2/modexp_0_0_0_35000Filler.json", + ".*/stQuadraticComplexityTest/Call20KbytesContract50_1Filler.json", + ".*/stQuadraticComplexityTest/Return50000_2Filler.json", + ".*/stQuadraticComplexityTest/Return50000Filler.json", + ".*/stRandom/randomStatetest100Filler.json", + ".*/stRandom/randomStatetest102Filler.json", + ".*/stRandom/randomStatetest104Filler.json", + ".*/stRandom/randomStatetest105Filler.json", + ".*/stRandom/randomStatetest106Filler.json", + ".*/stRandom/randomStatetest107Filler.json", + ".*/stRandom/randomStatetest110Filler.json", + ".*/stRandom/randomStatetest112Filler.json", + ".*/stRandom/randomStatetest114Filler.json", + ".*/stRandom/randomStatetest115Filler.json", + ".*/stRandom/randomStatetest116Filler.json", + ".*/stRandom/randomStatetest117Filler.json", + ".*/stRandom/randomStatetest118Filler.json", + ".*/stRandom/randomStatetest119Filler.json", + ".*/stRandom/randomStatetest11Filler.json", + ".*/stRandom/randomStatetest120Filler.json", + ".*/stRandom/randomStatetest121Filler.json", + ".*/stRandom/randomStatetest122Filler.json", + ".*/stRandom/randomStatetest124Filler.json", + ".*/stRandom/randomStatetest129Filler.json", + ".*/stRandom/randomStatetest12Filler.json", + ".*/stRandom/randomStatetest130Filler.json", + ".*/stRandom/randomStatetest131Filler.json", + ".*/stRandom/randomStatetest137Filler.json", + ".*/stRandom/randomStatetest138Filler.json", + ".*/stRandom/randomStatetest139Filler.json", + ".*/stRandom/randomStatetest142Filler.json", + ".*/stRandom/randomStatetest143Filler.json", + ".*/stRandom/randomStatetest145Filler.json", + ".*/stRandom/randomStatetest147Filler.json", + ".*/stRandom/randomStatetest148Filler.json", + ".*/stRandom/randomStatetest14Filler.json", + ".*/stRandom/randomStatetest153Filler.json", + ".*/stRandom/randomStatetest155Filler.json", + ".*/stRandom/randomStatetest156Filler.json", + ".*/stRandom/randomStatetest158Filler.json", + ".*/stRandom/randomStatetest15Filler.json", + ".*/stRandom/randomStatetest161Filler.json", + ".*/stRandom/randomStatetest162Filler.json", + ".*/stRandom/randomStatetest164Filler.json", + ".*/stRandom/randomStatetest166Filler.json", + ".*/stRandom/randomStatetest167Filler.json", + ".*/stRandom/randomStatetest169Filler.json", + ".*/stRandom/randomStatetest173Filler.json", + ".*/stRandom/randomStatetest174Filler.json", + ".*/stRandom/randomStatetest175Filler.json", + ".*/stRandom/randomStatetest179Filler.json", + ".*/stRandom/randomStatetest17Filler.json", + ".*/stRandom/randomStatetest180Filler.json", + ".*/stRandom/randomStatetest183Filler.json", + ".*/stRandom/randomStatetest184Filler.json", + ".*/stRandom/randomStatetest187Filler.json", + ".*/stRandom/randomStatetest188Filler.json", + ".*/stRandom/randomStatetest191Filler.json", + ".*/stRandom/randomStatetest192Filler.json", + ".*/stRandom/randomStatetest194Filler.json", + ".*/stRandom/randomStatetest195Filler.json", + ".*/stRandom/randomStatetest196Filler.json", + ".*/stRandom/randomStatetest198Filler.json", + ".*/stRandom/randomStatetest199Filler.json", + ".*/stRandom/randomStatetest19Filler.json", + ".*/stRandom/randomStatetest200Filler.json", + ".*/stRandom/randomStatetest201Filler.json", + ".*/stRandom/randomStatetest202Filler.json", + ".*/stRandom/randomStatetest204Filler.json", + ".*/stRandom/randomStatetest206Filler.json", + ".*/stRandom/randomStatetest207Filler.json", + ".*/stRandom/randomStatetest208Filler.json", + ".*/stRandom/randomStatetest210Filler.json", + ".*/stRandom/randomStatetest212Filler.json", + ".*/stRandom/randomStatetest214Filler.json", + ".*/stRandom/randomStatetest215Filler.json", + ".*/stRandom/randomStatetest216Filler.json", + ".*/stRandom/randomStatetest217Filler.json", + ".*/stRandom/randomStatetest219Filler.json", + ".*/stRandom/randomStatetest220Filler.json", + ".*/stRandom/randomStatetest221Filler.json", + ".*/stRandom/randomStatetest222Filler.json", + ".*/stRandom/randomStatetest225Filler.json", + ".*/stRandom/randomStatetest227Filler.json", + ".*/stRandom/randomStatetest228Filler.json", + ".*/stRandom/randomStatetest22Filler.json", + ".*/stRandom/randomStatetest231Filler.json", + ".*/stRandom/randomStatetest232Filler.json", + ".*/stRandom/randomStatetest236Filler.json", + ".*/stRandom/randomStatetest237Filler.json", + ".*/stRandom/randomStatetest238Filler.json", + ".*/stRandom/randomStatetest23Filler.json", + ".*/stRandom/randomStatetest242Filler.json", + ".*/stRandom/randomStatetest243Filler.json", + ".*/stRandom/randomStatetest244Filler.json", + ".*/stRandom/randomStatetest245Filler.json", + ".*/stRandom/randomStatetest246Filler.json", + ".*/stRandom/randomStatetest247Filler.json", + ".*/stRandom/randomStatetest248Filler.json", + ".*/stRandom/randomStatetest249Filler.json", + ".*/stRandom/randomStatetest254Filler.json", + ".*/stRandom/randomStatetest259Filler.json", + ".*/stRandom/randomStatetest264Filler.json", + ".*/stRandom/randomStatetest267Filler.json", + ".*/stRandom/randomStatetest268Filler.json", + ".*/stRandom/randomStatetest269Filler.json", + ".*/stRandom/randomStatetest26Filler.json", + ".*/stRandom/randomStatetest270Filler.json", + ".*/stRandom/randomStatetest273Filler.json", + ".*/stRandom/randomStatetest276Filler.json", + ".*/stRandom/randomStatetest278Filler.json", + ".*/stRandom/randomStatetest279Filler.json", + ".*/stRandom/randomStatetest27Filler.json", + ".*/stRandom/randomStatetest280Filler.json", + ".*/stRandom/randomStatetest281Filler.json", + ".*/stRandom/randomStatetest283Filler.json", + ".*/stRandom/randomStatetest28Filler.json", + ".*/stRandom/randomStatetest290Filler.json", + ".*/stRandom/randomStatetest291Filler.json", + ".*/stRandom/randomStatetest293Filler.json", + ".*/stRandom/randomStatetest297Filler.json", + ".*/stRandom/randomStatetest298Filler.json", + ".*/stRandom/randomStatetest299Filler.json", + ".*/stRandom/randomStatetest29Filler.json", + ".*/stRandom/randomStatetest2Filler.json", + ".*/stRandom/randomStatetest301Filler.json", + ".*/stRandom/randomStatetest305Filler.json", + ".*/stRandom/randomStatetest30Filler.json", + ".*/stRandom/randomStatetest310Filler.json", + ".*/stRandom/randomStatetest311Filler.json", + ".*/stRandom/randomStatetest315Filler.json", + ".*/stRandom/randomStatetest316Filler.json", + ".*/stRandom/randomStatetest318Filler.json", + ".*/stRandom/randomStatetest31Filler.json", + ".*/stRandom/randomStatetest322Filler.json", + ".*/stRandom/randomStatetest325Filler.json", + ".*/stRandom/randomStatetest329Filler.json", + ".*/stRandom/randomStatetest332Filler.json", + ".*/stRandom/randomStatetest333Filler.json", + ".*/stRandom/randomStatetest334Filler.json", + ".*/stRandom/randomStatetest337Filler.json", + ".*/stRandom/randomStatetest338Filler.json", + ".*/stRandom/randomStatetest339Filler.json", + ".*/stRandom/randomStatetest342Filler.json", + ".*/stRandom/randomStatetest343Filler.json", + ".*/stRandom/randomStatetest348Filler.json", + ".*/stRandom/randomStatetest349Filler.json", + ".*/stRandom/randomStatetest351Filler.json", + ".*/stRandom/randomStatetest354Filler.json", + ".*/stRandom/randomStatetest356Filler.json", + ".*/stRandom/randomStatetest358Filler.json", + ".*/stRandom/randomStatetest360Filler.json", + ".*/stRandom/randomStatetest361Filler.json", + ".*/stRandom/randomStatetest362Filler.json", + ".*/stRandom/randomStatetest363Filler.json", + ".*/stRandom/randomStatetest364Filler.json", + ".*/stRandom/randomStatetest365Filler.json", + ".*/stRandom/randomStatetest366Filler.json", + ".*/stRandom/randomStatetest367Filler.json", + ".*/stRandom/randomStatetest368Filler.json", + ".*/stRandom/randomStatetest369Filler.json", + ".*/stRandom/randomStatetest371Filler.json", + ".*/stRandom/randomStatetest372Filler.json", + ".*/stRandom/randomStatetest376Filler.json", + ".*/stRandom/randomStatetest379Filler.json", + ".*/stRandom/randomStatetest37Filler.json", + ".*/stRandom/randomStatetest380Filler.json", + ".*/stRandom/randomStatetest381Filler.json", + ".*/stRandom/randomStatetest382Filler.json", + ".*/stRandom/randomStatetest383Filler.json", + ".*/stRandom/randomStatetest39Filler.json", + ".*/stRandom/randomStatetest3Filler.json", + ".*/stRandom/randomStatetest41Filler.json", + ".*/stRandom/randomStatetest43Filler.json", + ".*/stRandom/randomStatetest47Filler.json", + ".*/stRandom/randomStatetest49Filler.json", + ".*/stRandom/randomStatetest52Filler.json", + ".*/stRandom/randomStatetest58Filler.json", + ".*/stRandom/randomStatetest59Filler.json", + ".*/stRandom/randomStatetest60Filler.json", + ".*/stRandom/randomStatetest62Filler.json", + ".*/stRandom/randomStatetest63Filler.json", + ".*/stRandom/randomStatetest64Filler.json", + ".*/stRandom/randomStatetest66Filler.json", + ".*/stRandom/randomStatetest67Filler.json", + ".*/stRandom/randomStatetest69Filler.json", + ".*/stRandom/randomStatetest6Filler.json", + ".*/stRandom/randomStatetest73Filler.json", + ".*/stRandom/randomStatetest74Filler.json", + ".*/stRandom/randomStatetest75Filler.json", + ".*/stRandom/randomStatetest77Filler.json", + ".*/stRandom/randomStatetest80Filler.json", + ".*/stRandom/randomStatetest81Filler.json", + ".*/stRandom/randomStatetest83Filler.json", + ".*/stRandom/randomStatetest85Filler.json", + ".*/stRandom/randomStatetest87Filler.json", + ".*/stRandom/randomStatetest88Filler.json", + ".*/stRandom/randomStatetest89Filler.json", + ".*/stRandom/randomStatetest90Filler.json", + ".*/stRandom/randomStatetest92Filler.json", + ".*/stRandom/randomStatetest95Filler.json", + ".*/stRandom/randomStatetest96Filler.json", + ".*/stRandom/randomStatetest98Filler.json", + ".*/stRandom/randomStatetest9Filler.json", + ".*/stRandom2/randomStatetest384Filler.json", + ".*/stRandom2/randomStatetest385Filler.json", + ".*/stRandom2/randomStatetest386Filler.json", + ".*/stRandom2/randomStatetest388Filler.json", + ".*/stRandom2/randomStatetest389Filler.json", + ".*/stRandom2/randomStatetest395Filler.json", + ".*/stRandom2/randomStatetest398Filler.json", + ".*/stRandom2/randomStatetest399Filler.json", + ".*/stRandom2/randomStatetest402Filler.json", + ".*/stRandom2/randomStatetest405Filler.json", + ".*/stRandom2/randomStatetest406Filler.json", + ".*/stRandom2/randomStatetest407Filler.json", + ".*/stRandom2/randomStatetest408Filler.json", + ".*/stRandom2/randomStatetest409Filler.json", + ".*/stRandom2/randomStatetest411Filler.json", + ".*/stRandom2/randomStatetest412Filler.json", + ".*/stRandom2/randomStatetest413Filler.json", + ".*/stRandom2/randomStatetest416Filler.json", + ".*/stRandom2/randomStatetest419Filler.json", + ".*/stRandom2/randomStatetest421Filler.json", + ".*/stRandom2/randomStatetest424Filler.json", + ".*/stRandom2/randomStatetest425Filler.json", + ".*/stRandom2/randomStatetest426Filler.json", + ".*/stRandom2/randomStatetest429Filler.json", + ".*/stRandom2/randomStatetest430Filler.json", + ".*/stRandom2/randomStatetest435Filler.json", + ".*/stRandom2/randomStatetest436Filler.json", + ".*/stRandom2/randomStatetest437Filler.json", + ".*/stRandom2/randomStatetest438Filler.json", + ".*/stRandom2/randomStatetest439Filler.json", + ".*/stRandom2/randomStatetest440Filler.json", + ".*/stRandom2/randomStatetest442Filler.json", + ".*/stRandom2/randomStatetest446Filler.json", + ".*/stRandom2/randomStatetest447Filler.json", + ".*/stRandom2/randomStatetest450Filler.json", + ".*/stRandom2/randomStatetest451Filler.json", + ".*/stRandom2/randomStatetest452Filler.json", + ".*/stRandom2/randomStatetest455Filler.json", + ".*/stRandom2/randomStatetest457Filler.json", + ".*/stRandom2/randomStatetest460Filler.json", + ".*/stRandom2/randomStatetest461Filler.json", + ".*/stRandom2/randomStatetest462Filler.json", + ".*/stRandom2/randomStatetest464Filler.json", + ".*/stRandom2/randomStatetest465Filler.json", + ".*/stRandom2/randomStatetest466Filler.json", + ".*/stRandom2/randomStatetest470Filler.json", + ".*/stRandom2/randomStatetest471Filler.json", + ".*/stRandom2/randomStatetest473Filler.json", + ".*/stRandom2/randomStatetest474Filler.json", + ".*/stRandom2/randomStatetest475Filler.json", + ".*/stRandom2/randomStatetest477Filler.json", + ".*/stRandom2/randomStatetest480Filler.json", + ".*/stRandom2/randomStatetest482Filler.json", + ".*/stRandom2/randomStatetest483Filler.json", + ".*/stRandom2/randomStatetest487Filler.json", + ".*/stRandom2/randomStatetest488Filler.json", + ".*/stRandom2/randomStatetest489Filler.json", + ".*/stRandom2/randomStatetest491Filler.json", + ".*/stRandom2/randomStatetest493Filler.json", + ".*/stRandom2/randomStatetest495Filler.json", + ".*/stRandom2/randomStatetest497Filler.json", + ".*/stRandom2/randomStatetest500Filler.json", + ".*/stRandom2/randomStatetest501Filler.json", + ".*/stRandom2/randomStatetest502Filler.json", + ".*/stRandom2/randomStatetest503Filler.json", + ".*/stRandom2/randomStatetest505Filler.json", + ".*/stRandom2/randomStatetest506Filler.json", + ".*/stRandom2/randomStatetest511Filler.json", + ".*/stRandom2/randomStatetest512Filler.json", + ".*/stRandom2/randomStatetest514Filler.json", + ".*/stRandom2/randomStatetest516Filler.json", + ".*/stRandom2/randomStatetest517Filler.json", + ".*/stRandom2/randomStatetest518Filler.json", + ".*/stRandom2/randomStatetest519Filler.json", + ".*/stRandom2/randomStatetest520Filler.json", + ".*/stRandom2/randomStatetest521Filler.json", + ".*/stRandom2/randomStatetest526Filler.json", + ".*/stRandom2/randomStatetest532Filler.json", + ".*/stRandom2/randomStatetest533Filler.json", + ".*/stRandom2/randomStatetest534Filler.json", + ".*/stRandom2/randomStatetest535Filler.json", + ".*/stRandom2/randomStatetest537Filler.json", + ".*/stRandom2/randomStatetest539Filler.json", + ".*/stRandom2/randomStatetest541Filler.json", + ".*/stRandom2/randomStatetest542Filler.json", + ".*/stRandom2/randomStatetest544Filler.json", + ".*/stRandom2/randomStatetest545Filler.json", + ".*/stRandom2/randomStatetest546Filler.json", + ".*/stRandom2/randomStatetest548Filler.json", + ".*/stRandom2/randomStatetest550Filler.json", + ".*/stRandom2/randomStatetest552Filler.json", + ".*/stRandom2/randomStatetest553Filler.json", + ".*/stRandom2/randomStatetest555Filler.json", + ".*/stRandom2/randomStatetest556Filler.json", + ".*/stRandom2/randomStatetest559Filler.json", + ".*/stRandom2/randomStatetest564Filler.json", + ".*/stRandom2/randomStatetest565Filler.json", + ".*/stRandom2/randomStatetest571Filler.json", + ".*/stRandom2/randomStatetest574Filler.json", + ".*/stRandom2/randomStatetest577Filler.json", + ".*/stRandom2/randomStatetest578Filler.json", + ".*/stRandom2/randomStatetest580Filler.json", + ".*/stRandom2/randomStatetest581Filler.json", + ".*/stRandom2/randomStatetest584Filler.json", + ".*/stRandom2/randomStatetest585Filler.json", + ".*/stRandom2/randomStatetest586Filler.json", + ".*/stRandom2/randomStatetest587Filler.json", + ".*/stRandom2/randomStatetest588Filler.json", + ".*/stRandom2/randomStatetest592Filler.json", + ".*/stRandom2/randomStatetest596Filler.json", + ".*/stRandom2/randomStatetest599Filler.json", + ".*/stRandom2/randomStatetest600Filler.json", + ".*/stRandom2/randomStatetest602Filler.json", + ".*/stRandom2/randomStatetest603Filler.json", + ".*/stRandom2/randomStatetest605Filler.json", + ".*/stRandom2/randomStatetest607Filler.json", + ".*/stRandom2/randomStatetest608Filler.json", + ".*/stRandom2/randomStatetest610Filler.json", + ".*/stRandom2/randomStatetest612Filler.json", + ".*/stRandom2/randomStatetest615Filler.json", + ".*/stRandom2/randomStatetest616Filler.json", + ".*/stRandom2/randomStatetest620Filler.json", + ".*/stRandom2/randomStatetest621Filler.json", + ".*/stRandom2/randomStatetest627Filler.json", + ".*/stRandom2/randomStatetest628Filler.json", + ".*/stRandom2/randomStatetest629Filler.json", + ".*/stRandom2/randomStatetest630Filler.json", + ".*/stRandom2/randomStatetest633Filler.json", + ".*/stRandom2/randomStatetest635Filler.json", + ".*/stRandom2/randomStatetest637Filler.json", + ".*/stRandom2/randomStatetest638Filler.json", + ".*/stRandom2/randomStatetest641Filler.json", + ".*/stRandom2/randomStatetest643Filler.json", + ".*/stRandom2/randomStatetestFiller.json", + ".*/stRefundTest/refund_CallAFiller.json", + ".*/stRefundTest/refund_TxToSuicideFiller.json", + ".*/stRefundTest/refund50_2Filler.json", + ".*/stRefundTest/refund50percentCapFiller.json", + ".*/stRefundTest/refund600Filler.json", + ".*/stRefundTest/refundSuicide50procentCapFiller.json", + ".*/stReturnDataTest/call_outsize_then_create_successful_then_returndatasizeFiller.json", + ".*/stReturnDataTest/call_then_create_successful_then_returndatasizeFiller.json", + ".*/stReturnDataTest/create_callprecompile_returndatasizeFiller.json", + ".*/stReturnDataTest/modexp_modsize0_returndatasizeFiller.json", + ".*/stReturnDataTest/returndatacopy_0_0_following_successful_createFiller.json", + ".*/stReturnDataTest/returndatacopy_afterFailing_createFiller.json", + ".*/stReturnDataTest/returndatacopy_following_revert_in_createFiller.json", + ".*/stReturnDataTest/returndatasize_after_successful_callcodeFiller.json", + ".*/stReturnDataTest/returndatasize_following_successful_createFiller.json", + ".*/stReturnDataTest/tooLongReturnDataCopyFiller.yml", + ".*/stRevertTest/RevertDepth2Filler.json", + ".*/stRevertTest/RevertDepthCreateAddressCollisionFiller.json", + ".*/stRevertTest/RevertDepthCreateOOGFiller.json", + ".*/stRevertTest/RevertInCreateInInit_ParisFiller.json", + ".*/stRevertTest/RevertOpcodeCallsFiller.json", + ".*/stRevertTest/RevertOpcodeCreateFiller.json", + ".*/stRevertTest/RevertOpcodeDirectCallFiller.json", + ".*/stRevertTest/RevertOpcodeInCreateReturnsFiller.json", + ".*/stRevertTest/RevertOpcodeMultipleSubCallsFiller.json", + ".*/stRevertTest/RevertSubCallStorageOOG2Filler.json", + ".*/stRevertTest/RevertSubCallStorageOOGFiller.json", + ".*/stSelfBalance/selfBalanceCallTypesFiller.json", + ".*/stSelfBalance/selfBalanceEqualsBalanceFiller.json", + ".*/stSelfBalance/selfBalanceFiller.json", + ".*/stSelfBalance/selfBalanceGasCostFiller.json", + ".*/stSelfBalance/selfBalanceUpdateFiller.json", + ".*/stSLoadTest/sloadGasCostFiller.json", + ".*/stSolidityTest/CallLowLevelCreatesSolidityFiller.json", + ".*/stSolidityTest/RecursiveCreateContractsCreate4ContractsFiller.json", + ".*/stSolidityTest/TestOverflowFiller.json", + ".*/stSolidityTest/TestStructuresAndVariablessFiller.json", + ".*/stSpecialTest/deploymentErrorFiller.json", + ".*/stSpecialTest/FailedCreateRevertsDeletionParisFiller.json", + ".*/stSpecialTest/makeMoneyFiller.json", + ".*/stSpecialTest/selfdestructEIP2929Filler.json", + ".*/stSStoreTest/sstore_0to0Filler.json", + ".*/stSStoreTest/sstore_0to0to0Filler.json", + ".*/stSStoreTest/sstore_0to0toXFiller.json", + ".*/stSStoreTest/sstore_0toXFiller.json", + ".*/stSStoreTest/sstore_0toXto0Filler.json", + ".*/stSStoreTest/sstore_0toXto0toXFiller.json", + ".*/stSStoreTest/sstore_0toXtoXFiller.json", + ".*/stSStoreTest/sstore_0toXtoYFiller.json", + ".*/stSStoreTest/sstore_Xto0Filler.json", + ".*/stSStoreTest/sstore_Xto0to0Filler.json", + ".*/stSStoreTest/sstore_Xto0toXFiller.json", + ".*/stSStoreTest/sstore_Xto0toXto0Filler.json", + ".*/stSStoreTest/sstore_Xto0toYFiller.json", + ".*/stSStoreTest/sstore_XtoXFiller.json", + ".*/stSStoreTest/sstore_XtoXto0Filler.json", + ".*/stSStoreTest/sstore_XtoXtoXFiller.json", + ".*/stSStoreTest/sstore_XtoXtoYFiller.json", + ".*/stSStoreTest/sstore_XtoYFiller.json", + ".*/stSStoreTest/sstore_XtoYto0Filler.json", + ".*/stSStoreTest/sstore_XtoYtoXFiller.json", + ".*/stSStoreTest/sstore_XtoYtoYFiller.json", + ".*/stSStoreTest/sstore_XtoYtoZFiller.json", + ".*/stSStoreTest/sstoreGasFiller.yml", + ".*/stStackTests/shallowStackFiller.json", + ".*/stStackTests/stackOverflowDUPFiller.json", + ".*/stStackTests/stackOverflowFiller.json", + ".*/stStackTests/stackOverflowM1DUPFiller.json", + ".*/stStackTests/stackOverflowM1Filler.json", + ".*/stStackTests/stackOverflowM1PUSHFiller.json", + ".*/stStackTests/stackOverflowPUSHFiller.json", + ".*/stStackTests/stackOverflowSWAPFiller.json", + ".*/stStackTests/stacksanitySWAPFiller.json", + ".*/stStaticCall/static_ABAcalls3Filler.json", + ".*/stStaticCall/static_Call1024OOGFiller.json", + ".*/stStaticCall/static_Call10Filler.json", + ".*/stStaticCall/static_callcallcodecall_ABCB_RECURSIVE2Filler.json", + ".*/stStaticCall/static_callcallcodecall_ABCB_RECURSIVEFiller.json", + ".*/stStaticCall/static_callcallcodecallcode_ABCB_RECURSIVE2Filler.json", + ".*/stStaticCall/static_callcallcodecallcode_ABCB_RECURSIVEFiller.json", + ".*/stStaticCall/static_callcode_checkPCFiller.json", + ".*/stStaticCall/static_callcodecallcall_ABCB_RECURSIVE2Filler.json", + ".*/stStaticCall/static_callcodecallcall_ABCB_RECURSIVEFiller.json", + ".*/stStaticCall/static_callcodecallcallcode_ABCB_RECURSIVE2Filler.json", + ".*/stStaticCall/static_callcodecallcallcode_ABCB_RECURSIVEFiller.json", + ".*/stStaticCall/static_callcodecallcodecall_110_SuicideEnd2Filler.json", + ".*/stStaticCall/static_callcodecallcodecall_110_SuicideEndFiller.json", + ".*/stStaticCall/static_callcodecallcodecall_ABCB_RECURSIVE2Filler.json", + ".*/stStaticCall/static_callcodecallcodecall_ABCB_RECURSIVEFiller.json", + ".*/stStaticCall/static_CallContractToCreateContractOOGFiller.json", + ".*/stStaticCall/static_CallContractToCreateContractWhichWouldCreateContractIfCalledFiller.json", + ".*/stStaticCall/static_CallLoseGasOOGFiller.json", + ".*/stStaticCall/static_CheckOpcodes5Filler.json", + ".*/stStaticCall/static_contractCreationMakeCallThatAskMoreGasThenTransactionProvidedFiller.json", + ".*/stStaticCall/static_CREATE_EmptyContractAndCallIt_0weiFiller.json", + ".*/stStaticCall/static_CREATE_EmptyContractWithStorageAndCallIt_0weiFiller.json", + ".*/stStaticCall/static_RETURN_BoundsFiller.json", + ".*/stStaticCall/static_RETURN_BoundsOOGFiller.json", + ".*/stStaticCall/static_ReturnTest2Filler.json", + ".*/stSystemOperationsTest/ABAcalls3Filler.json", + ".*/stSystemOperationsTest/Call10Filler.json", + ".*/stSystemOperationsTest/callcodeToNameRegistratorZeroMemExpanionFiller.json", + ".*/stSystemOperationsTest/CallRecursiveBomb3Filler.json", + ".*/stSystemOperationsTest/CallToNameRegistratorZeorSizeMemExpansionFiller.json", + ".*/stSystemOperationsTest/doubleSelfdestructTestFiller.yml", + ".*/stSystemOperationsTest/extcodecopyFiller.json", + ".*/stSystemOperationsTest/multiSelfdestructFiller.yml", + ".*/stTransactionTest/CreateMessageSuccessFiller.json", + ".*/stTransactionTest/CreateTransactionSuccessFiller.json", + ".*/stTransactionTest/InternalCallHittingGasLimit2Filler.json", + ".*/stTransactionTest/StoreGasOnCreateFiller.json", + ".*/stTransactionTest/SuicidesAndInternalCallSuicidesOOGFiller.json", + ".*/stTransitionTest/createNameRegistratorPerTxsAfterFiller.json", + ".*/stTransitionTest/createNameRegistratorPerTxsAtFiller.json", + ".*/stTransitionTest/createNameRegistratorPerTxsBeforeFiller.json", + ".*/stZeroCallsRevert/ZeroValue_CALL_OOGRevertFiller.json", + ".*/stZeroCallsRevert/ZeroValue_CALL_ToEmpty_OOGRevert_ParisFiller.json", + ".*/stZeroCallsRevert/ZeroValue_CALL_ToNonZeroBalance_OOGRevertFiller.json", + ".*/stZeroCallsRevert/ZeroValue_CALL_ToOneStorageKey_OOGRevert_ParisFiller.json", + ".*/stZeroCallsRevert/ZeroValue_CALLCODE_OOGRevertFiller.json", + ".*/stZeroCallsRevert/ZeroValue_CALLCODE_ToEmpty_OOGRevert_ParisFiller.json", + ".*/stZeroCallsRevert/ZeroValue_CALLCODE_ToNonZeroBalance_OOGRevertFiller.json", + ".*/stZeroCallsRevert/ZeroValue_CALLCODE_ToOneStorageKey_OOGRevert_ParisFiller.json", + ".*/stZeroCallsRevert/ZeroValue_DELEGATECALL_OOGRevertFiller.json", + ".*/stZeroCallsRevert/ZeroValue_DELEGATECALL_ToEmpty_OOGRevert_ParisFiller.json", + ".*/stZeroCallsRevert/ZeroValue_DELEGATECALL_ToNonZeroBalance_OOGRevertFiller.json", + ".*/stZeroCallsRevert/ZeroValue_DELEGATECALL_ToOneStorageKey_OOGRevert_ParisFiller.json", + ".*/stZeroCallsRevert/ZeroValue_SUICIDE_OOGRevertFiller.json", + ".*/stZeroCallsRevert/ZeroValue_SUICIDE_ToEmpty_OOGRevert_ParisFiller.json", + ".*/stZeroCallsRevert/ZeroValue_SUICIDE_ToNonZeroBalance_OOGRevertFiller.json", + ".*/stZeroCallsRevert/ZeroValue_SUICIDE_ToOneStorageKey_OOGRevert_ParisFiller.json", + ".*/stZeroKnowledge/pointAddFiller.json", + ".*/stZeroKnowledge/pointAddTruncFiller.json", + ".*/stZeroKnowledge/pointMulAdd2Filler.json", + ".*/stZeroKnowledge/pointMulAddFiller.json", + ".*/VMTests/vmArithmeticTest/twoOpsFiller.yml", + } + testExecutionSpecBlocktests(t, executionSpecBALBlockchainTestDir, skips) } var failures = 0 diff --git a/tests/init.go b/tests/init.go index 117410b7a8..b8fa1c8b99 100644 --- a/tests/init.go +++ b/tests/init.go @@ -490,7 +490,7 @@ var Forks = map[string]*params.ChainConfig{ Cancun: params.DefaultCancunBlobConfig, Prague: params.DefaultPragueBlobConfig, Osaka: params.DefaultOsakaBlobConfig, - BPO1: bpo1BlobConfig, + BPO1: params.DefaultBPO1BlobConfig, }, }, "Amsterdam": { @@ -518,11 +518,12 @@ var Forks = map[string]*params.ChainConfig{ AmsterdamTime: u64(0), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, BlobScheduleConfig: ¶ms.BlobScheduleConfig{ - Cancun: params.DefaultCancunBlobConfig, - Prague: params.DefaultPragueBlobConfig, - Osaka: params.DefaultOsakaBlobConfig, - BPO1: bpo1BlobConfig, - BPO2: bpo2BlobConfig, + Cancun: params.DefaultCancunBlobConfig, + Prague: params.DefaultPragueBlobConfig, + Osaka: params.DefaultOsakaBlobConfig, + BPO1: params.DefaultBPO1BlobConfig, + BPO2: params.DefaultBPO2BlobConfig, + Amsterdam: params.DefaultBPO2BlobConfig, }, }, "BPO2ToAmsterdamAtTime15k": { @@ -550,11 +551,12 @@ var Forks = map[string]*params.ChainConfig{ AmsterdamTime: u64(15_000), DepositContractAddress: params.MainnetChainConfig.DepositContractAddress, BlobScheduleConfig: ¶ms.BlobScheduleConfig{ - Cancun: params.DefaultCancunBlobConfig, - Prague: params.DefaultPragueBlobConfig, - Osaka: params.DefaultOsakaBlobConfig, - BPO1: bpo1BlobConfig, - BPO2: bpo2BlobConfig, + Cancun: params.DefaultCancunBlobConfig, + Prague: params.DefaultPragueBlobConfig, + Osaka: params.DefaultOsakaBlobConfig, + BPO1: params.DefaultBPO1BlobConfig, + BPO2: params.DefaultBPO2BlobConfig, + Amsterdam: params.DefaultBPO2BlobConfig, }, }, "OsakaToBPO1AtTime15k": { @@ -583,7 +585,7 @@ var Forks = map[string]*params.ChainConfig{ Cancun: params.DefaultCancunBlobConfig, Prague: params.DefaultPragueBlobConfig, Osaka: params.DefaultOsakaBlobConfig, - BPO1: bpo1BlobConfig, + BPO1: params.DefaultBPO1BlobConfig, }, }, "BPO2": { @@ -613,8 +615,8 @@ var Forks = map[string]*params.ChainConfig{ Cancun: params.DefaultCancunBlobConfig, Prague: params.DefaultPragueBlobConfig, Osaka: params.DefaultOsakaBlobConfig, - BPO1: bpo1BlobConfig, - BPO2: bpo2BlobConfig, + BPO1: params.DefaultBPO1BlobConfig, + BPO2: params.DefaultBPO2BlobConfig, }, }, "BPO1ToBPO2AtTime15k": { @@ -644,8 +646,8 @@ var Forks = map[string]*params.ChainConfig{ Cancun: params.DefaultCancunBlobConfig, Prague: params.DefaultPragueBlobConfig, Osaka: params.DefaultOsakaBlobConfig, - BPO1: bpo1BlobConfig, - BPO2: bpo2BlobConfig, + BPO1: params.DefaultBPO1BlobConfig, + BPO2: params.DefaultBPO2BlobConfig, }, }, "BPO3": { @@ -676,8 +678,8 @@ var Forks = map[string]*params.ChainConfig{ Cancun: params.DefaultCancunBlobConfig, Prague: params.DefaultPragueBlobConfig, Osaka: params.DefaultOsakaBlobConfig, - BPO1: bpo1BlobConfig, - BPO2: bpo2BlobConfig, + BPO1: params.DefaultBPO1BlobConfig, + BPO2: params.DefaultBPO2BlobConfig, BPO3: params.DefaultBPO3BlobConfig, }, }, @@ -709,8 +711,8 @@ var Forks = map[string]*params.ChainConfig{ Cancun: params.DefaultCancunBlobConfig, Prague: params.DefaultPragueBlobConfig, Osaka: params.DefaultOsakaBlobConfig, - BPO1: bpo1BlobConfig, - BPO2: bpo2BlobConfig, + BPO1: params.DefaultBPO1BlobConfig, + BPO2: params.DefaultBPO2BlobConfig, BPO3: params.DefaultBPO3BlobConfig, }, }, @@ -743,8 +745,8 @@ var Forks = map[string]*params.ChainConfig{ Cancun: params.DefaultCancunBlobConfig, Prague: params.DefaultPragueBlobConfig, Osaka: params.DefaultOsakaBlobConfig, - BPO1: bpo1BlobConfig, - BPO2: bpo2BlobConfig, + BPO1: params.DefaultBPO1BlobConfig, + BPO2: params.DefaultBPO2BlobConfig, BPO3: params.DefaultBPO3BlobConfig, BPO4: params.DefaultBPO4BlobConfig, }, @@ -778,8 +780,8 @@ var Forks = map[string]*params.ChainConfig{ Cancun: params.DefaultCancunBlobConfig, Prague: params.DefaultPragueBlobConfig, Osaka: params.DefaultOsakaBlobConfig, - BPO1: bpo1BlobConfig, - BPO2: bpo2BlobConfig, + BPO1: params.DefaultBPO1BlobConfig, + BPO2: params.DefaultBPO2BlobConfig, BPO3: params.DefaultBPO3BlobConfig, BPO4: params.DefaultBPO4BlobConfig, }, @@ -805,18 +807,6 @@ var Forks = map[string]*params.ChainConfig{ }, } -var bpo1BlobConfig = ¶ms.BlobConfig{ - Target: 9, - Max: 14, - UpdateFraction: 8832827, -} - -var bpo2BlobConfig = ¶ms.BlobConfig{ - Target: 14, - Max: 21, - UpdateFraction: 13739630, -} - // AvailableForks returns the set of defined fork names func AvailableForks() []string { var availableForks []string diff --git a/tests/state_test.go b/tests/state_test.go index f80bda4372..a1b71e95da 100644 --- a/tests/state_test.go +++ b/tests/state_test.go @@ -301,7 +301,7 @@ func runBenchmark(b *testing.B, t *StateTest) { evm.SetTxContext(txContext) // Create "contract" for sender to cache code analysis. - sender := vm.NewContract(msg.From, msg.From, nil, 0, nil) + sender := vm.NewContract(msg.From, msg.From, nil, vm.GasCosts{}, nil) var ( gasUsed uint64 @@ -316,7 +316,7 @@ func runBenchmark(b *testing.B, t *StateTest) { start := time.Now() // Execute the message. - _, leftOverGas, err := evm.Call(sender.Address(), *msg.To, msg.Data, msg.GasLimit, uint256.MustFromBig(msg.Value)) + _, leftOverGas, err := evm.Call(sender.Address(), *msg.To, msg.Data, vm.GasCosts{RegularGas: msg.GasLimit}, uint256.MustFromBig(msg.Value)) if err != nil { b.Error(err) return @@ -325,7 +325,7 @@ func runBenchmark(b *testing.B, t *StateTest) { b.StopTimer() elapsed += uint64(time.Since(start)) refund += state.StateDB.GetRefund() - gasUsed += msg.GasLimit - leftOverGas + gasUsed += msg.GasLimit - leftOverGas.RegularGas state.StateDB.RevertToSnapshot(snapshot) } diff --git a/tests/transaction_test_util.go b/tests/transaction_test_util.go index a90c2d522f..9848964e7a 100644 --- a/tests/transaction_test_util.go +++ b/tests/transaction_test_util.go @@ -81,10 +81,12 @@ func (tt *TransactionTest) Run() error { return } // Intrinsic gas - requiredGas, err = core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, rules.IsHomestead, rules.IsIstanbul, rules.IsShanghai) + // TODO (MariusVanDerWijden): correctly set this for post-amsterdam tests. + gas, err := core.IntrinsicGas(tx.Data(), tx.AccessList(), tx.SetCodeAuthorizations(), tx.To() == nil, *rules, 0) if err != nil { return } + requiredGas = gas.RegularGas if requiredGas > tx.Gas() { return sender, hash, 0, fmt.Errorf("insufficient gas ( %d < %d )", tx.Gas(), requiredGas) }