ecb781297b
This PR adds a new fork which disables EIP-1283. Internally it's called Petersburg, but the genesis/config field is ConstantinopleFix. The block numbers are: 7280000 for Constantinople on Mainnet 7280000 for ConstantinopleFix on Mainnet 4939394 for ConstantinopleFix on Ropsten 9999999 for ConstantinopleFix on Rinkeby (real number decided later) This PR also defaults to using the same ConstantinopleFix number as whatever Constantinople is set to. That is, it will default to mainnet behaviour if ConstantinopleFix is not set.This means that for private networks which have already transitioned to Constantinople, this PR will break the network unless ConstantinopleFix is explicitly set!
536 lines
17 KiB
Go
536 lines
17 KiB
Go
// Copyright 2017 The go-ethereum Authors
|
|
// This file is part of the go-ethereum library.
|
|
//
|
|
// The go-ethereum library is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU Lesser General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// The go-ethereum library is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU Lesser General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU Lesser General Public License
|
|
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
package vm
|
|
|
|
import (
|
|
"github.com/ethereum/go-ethereum/common"
|
|
"github.com/ethereum/go-ethereum/common/math"
|
|
"github.com/ethereum/go-ethereum/params"
|
|
)
|
|
|
|
// memoryGasCosts calculates the quadratic gas for memory expansion. It does so
|
|
// only for the memory region that is expanded, not the total memory.
|
|
func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
|
|
|
|
if newMemSize == 0 {
|
|
return 0, nil
|
|
}
|
|
// The maximum that will fit in a uint64 is max_word_count - 1
|
|
// anything above that will result in an overflow.
|
|
// Additionally, a newMemSize which results in a
|
|
// newMemSizeWords larger than 0x7ffffffff will cause the square operation
|
|
// to overflow.
|
|
// The constant 0xffffffffe0 is the highest number that can be used without
|
|
// overflowing the gas calculation
|
|
if newMemSize > 0xffffffffe0 {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
newMemSizeWords := toWordSize(newMemSize)
|
|
newMemSize = newMemSizeWords * 32
|
|
|
|
if newMemSize > uint64(mem.Len()) {
|
|
square := newMemSizeWords * newMemSizeWords
|
|
linCoef := newMemSizeWords * params.MemoryGas
|
|
quadCoef := square / params.QuadCoeffDiv
|
|
newTotalFee := linCoef + quadCoef
|
|
|
|
fee := newTotalFee - mem.lastGasCost
|
|
mem.lastGasCost = newTotalFee
|
|
|
|
return fee, nil
|
|
}
|
|
return 0, nil
|
|
}
|
|
|
|
func constGasFunc(gas uint64) gasFunc {
|
|
return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
return gas, nil
|
|
}
|
|
}
|
|
|
|
func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
var overflow bool
|
|
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
words, overflow := bigUint64(stack.Back(2))
|
|
if overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
if gas, overflow = math.SafeAdd(gas, words); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
var overflow bool
|
|
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
words, overflow := bigUint64(stack.Back(2))
|
|
if overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
if gas, overflow = math.SafeAdd(gas, words); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
var (
|
|
y, x = stack.Back(1), stack.Back(0)
|
|
current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
|
|
)
|
|
// The legacy gas metering only takes into consideration the current state
|
|
// Legacy rules should be applied if we are in Petersburg (removal of EIP-1283)
|
|
// OR Constantinople is not active
|
|
if evm.chainRules.IsPetersburg || !evm.chainRules.IsConstantinople {
|
|
// This checks for 3 scenario's and calculates gas accordingly:
|
|
//
|
|
// 1. From a zero-value address to a non-zero value (NEW VALUE)
|
|
// 2. From a non-zero value address to a zero-value address (DELETE)
|
|
// 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
|
|
case current != (common.Hash{}) && y.Sign() == 0: // non 0 => 0
|
|
evm.StateDB.AddRefund(params.SstoreRefundGas)
|
|
return params.SstoreClearGas, nil
|
|
default: // non 0 => non 0 (or 0 => 0)
|
|
return params.SstoreResetGas, nil
|
|
}
|
|
}
|
|
// The new gas metering is based on net gas costs (EIP-1283):
|
|
//
|
|
// 1. If current value equals new value (this is a no-op), 200 gas is deducted.
|
|
// 2. If current value does not equal new value
|
|
// 2.1. If original value equals current value (this storage slot has not been changed by the current execution context)
|
|
// 2.1.1. If original value is 0, 20000 gas is deducted.
|
|
// 2.1.2. Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter.
|
|
// 2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses.
|
|
// 2.2.1. If original value is not 0
|
|
// 2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0.
|
|
// 2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter.
|
|
// 2.2.2. If original value equals new value (this storage slot is reset)
|
|
// 2.2.2.1. If original value is 0, add 19800 gas to refund counter.
|
|
// 2.2.2.2. Otherwise, add 4800 gas to refund counter.
|
|
value := common.BigToHash(y)
|
|
if current == value { // noop (1)
|
|
return params.NetSstoreNoopGas, nil
|
|
}
|
|
original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
|
|
if original == current {
|
|
if original == (common.Hash{}) { // create slot (2.1.1)
|
|
return 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)
|
|
}
|
|
if original != (common.Hash{}) {
|
|
if current == (common.Hash{}) { // recreate slot (2.2.1.1)
|
|
evm.StateDB.SubRefund(params.NetSstoreClearRefund)
|
|
} else if value == (common.Hash{}) { // delete slot (2.2.1.2)
|
|
evm.StateDB.AddRefund(params.NetSstoreClearRefund)
|
|
}
|
|
}
|
|
if original == value {
|
|
if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1)
|
|
evm.StateDB.AddRefund(params.NetSstoreResetClearRefund)
|
|
} else { // reset to original existing slot (2.2.2.2)
|
|
evm.StateDB.AddRefund(params.NetSstoreResetRefund)
|
|
}
|
|
}
|
|
return params.NetSstoreDirtyGas, nil
|
|
}
|
|
|
|
func makeGasLog(n uint64) gasFunc {
|
|
return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
requestedSize, overflow := bigUint64(stack.Back(1))
|
|
if overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
var memorySizeGas uint64
|
|
if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
}
|
|
|
|
func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
var overflow bool
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
if gas, overflow = math.SafeAdd(gas, params.Sha3Gas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
wordGas, overflow := bigUint64(stack.Back(1))
|
|
if overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
var overflow bool
|
|
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
wordGas, overflow := bigUint64(stack.Back(2))
|
|
if overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
var overflow bool
|
|
if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
wordGas, overflow := bigUint64(stack.Back(3))
|
|
if overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasExtCodeHash(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
return gt.ExtcodeHash, nil
|
|
}
|
|
|
|
func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
var overflow bool
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
var overflow bool
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
var overflow bool
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
var overflow bool
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, params.CreateGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
var overflow bool
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, params.Create2Gas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
wordGas, overflow := bigUint64(stack.Back(2))
|
|
if overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
return gas, nil
|
|
}
|
|
|
|
func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
return gt.Balance, nil
|
|
}
|
|
|
|
func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
return gt.ExtcodeSize, nil
|
|
}
|
|
|
|
func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
return gt.SLoad, nil
|
|
}
|
|
|
|
func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
|
|
|
|
var (
|
|
gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas
|
|
overflow bool
|
|
)
|
|
if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
var (
|
|
gas = gt.Calls
|
|
transfersValue = stack.Back(2).Sign() != 0
|
|
address = common.BigToAddress(stack.Back(1))
|
|
eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber)
|
|
)
|
|
if eip158 {
|
|
if transfersValue && evm.StateDB.Empty(address) {
|
|
gas += params.CallNewAccountGas
|
|
}
|
|
} else if !evm.StateDB.Exist(address) {
|
|
gas += params.CallNewAccountGas
|
|
}
|
|
if transfersValue {
|
|
gas += params.CallValueTransferGas
|
|
}
|
|
memoryGas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var overflow bool
|
|
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
gas := gt.Calls
|
|
if stack.Back(2).Sign() != 0 {
|
|
gas += params.CallValueTransferGas
|
|
}
|
|
memoryGas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var overflow bool
|
|
if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
return memoryGasCost(mem, memorySize)
|
|
}
|
|
|
|
func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
return memoryGasCost(mem, memorySize)
|
|
}
|
|
|
|
func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
var gas uint64
|
|
// EIP150 homestead gas reprice fork:
|
|
if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
|
|
gas = gt.Suicide
|
|
var (
|
|
address = common.BigToAddress(stack.Back(0))
|
|
eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber)
|
|
)
|
|
|
|
if eip158 {
|
|
// if empty and transfers value
|
|
if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
|
|
gas += gt.CreateBySuicide
|
|
}
|
|
} else if !evm.StateDB.Exist(address) {
|
|
gas += gt.CreateBySuicide
|
|
}
|
|
}
|
|
|
|
if !evm.StateDB.HasSuicided(contract.Address()) {
|
|
evm.StateDB.AddRefund(params.SuicideRefundGas)
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var overflow bool
|
|
if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
gas, err := memoryGasCost(mem, memorySize)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
var overflow bool
|
|
if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
|
|
evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
|
|
return 0, errGasUintOverflow
|
|
}
|
|
return gas, nil
|
|
}
|
|
|
|
func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
return GasFastestStep, nil
|
|
}
|
|
|
|
func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
return GasFastestStep, nil
|
|
}
|
|
|
|
func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
|
|
return GasFastestStep, nil
|
|
}
|