core: uodate 8037 and fix rebasing issues

This commit is contained in:
MariusVanDerWijden 2026-01-13 22:00:25 +01:00
parent 9fdd74be00
commit c14f3e4c2f
39 changed files with 1761 additions and 538 deletions

View file

@ -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/

View file

@ -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
}

View file

@ -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,
})

View file

@ -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)
}

View file

@ -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.

View file

@ -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

View file

@ -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++
})

View file

@ -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.

View file

@ -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{

View file

@ -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 {

View file

@ -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(),
}
}

View file

@ -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)

View file

@ -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.

View file

@ -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())

View file

@ -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")
}
}

View file

@ -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 {

View file

@ -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

View file

@ -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
}

View file

@ -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)
}
}

View file

@ -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)
}

View file

@ -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))
}

60
core/vm/gascosts.go Normal file
View file

@ -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)
}

View file

@ -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

View file

@ -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 {

View file

@ -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)
}
}

View file

@ -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))

View file

@ -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)
}

View file

@ -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
}
}

View file

@ -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
}

View file

@ -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
}

View file

@ -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)

View file

@ -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

View file

@ -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")

View file

@ -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)

View file

@ -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

View file

@ -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

View file

@ -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: &params.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: &params.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 = &params.BlobConfig{
Target: 9,
Max: 14,
UpdateFraction: 8832827,
}
var bpo2BlobConfig = &params.BlobConfig{
Target: 14,
Max: 21,
UpdateFraction: 13739630,
}
// AvailableForks returns the set of defined fork names
func AvailableForks() []string {
var availableForks []string

View file

@ -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)
}

View file

@ -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)
}