diff --git a/core/vm/gas_table.go b/core/vm/gas_table.go index d8abba0ca1..e8a0a57f90 100644 --- a/core/vm/gas_table.go +++ b/core/vm/gas_table.go @@ -53,49 +53,45 @@ func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { return 0, 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 - } +// memoryCopierGas creates the gas functions for the following opcodes, and takes +// the stack position of the operand which determines the size of the data to copy +// as argument: +// CALLDATACOPY (stack position 2) +// CODECOPY (stack position 2) +// EXTCODECOPY (stack poition 3) +// RETURNDATACOPY (stack position 2) +func memoryCopierGas(stackpos int) gasFunc { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + // Gas for expanding the memory + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + // And gas for copying data, charged per word at param.CopyGas + words, overflow := bigUint64(stack.Back(stackpos)) + if 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 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 } - - 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 ( + gasCallDataCopy = memoryCopierGas(2) + gasCodeCopy = memoryCopierGas(2) + gasExtCodeCopy = memoryCopierGas(3) + gasReturnDataCopy = memoryCopierGas(2) +) - 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) { +func gasSStore(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)) @@ -165,7 +161,7 @@ func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, m } func makeGasLog(n uint64) gasFunc { - return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { requestedSize, overflow := bigUint64(stack.Back(1)) if overflow { return 0, errGasUintOverflow @@ -194,13 +190,11 @@ func makeGasLog(n uint64) gasFunc { } } -func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - var overflow bool +func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err } - wordGas, overflow := bigUint64(stack.Back(1)) if overflow { return 0, errGasUintOverflow @@ -214,66 +208,23 @@ func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem 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 - 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 - - 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 gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +// 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 gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return memoryGasCost(mem, memorySize) -} +var ( + gasReturn = pureMemoryGascost + gasRevert = pureMemoryGascost + gasMLoad = pureMemoryGascost + gasMStore8 = pureMemoryGascost + gasMStore = pureMemoryGascost + gasCreate = pureMemoryGascost +) -func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return memoryGasCost(mem, memorySize) -} - -func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return memoryGasCost(mem, memorySize) -} - -func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { gas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err @@ -288,11 +239,10 @@ func gasCreate2(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, if gas, overflow = math.SafeAdd(gas, wordGas); overflow { return 0, errGasUintOverflow } - return gas, nil } -func gasExpFrontier(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) var ( @@ -305,7 +255,7 @@ func gasExpFrontier(gt params.GasTable, evm *EVM, contract *Contract, stack *Sta return gas, nil } -func gasExpEip158(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasExpEip158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) var ( @@ -318,9 +268,9 @@ func gasExpEip158(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack return gas, nil } -func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var ( - gas = gt.Calls + gas uint64 transfersValue = stack.Back(2).Sign() != 0 address = common.BigToAddress(stack.Back(1)) eip158 = evm.chainRules.IsEIP158 @@ -355,20 +305,21 @@ func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem 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 - } +func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { memoryGas, err := memoryGasCost(mem, memorySize) if err != nil { return 0, err } - var overflow bool + var ( + gas uint64 + overflow bool + ) + if stack.Back(2).Sign() != 0 { + gas += params.CallValueTransferGas + } if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { return 0, errGasUintOverflow } - evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) if err != nil { return 0, err @@ -379,15 +330,39 @@ func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, 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 gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + if err != nil { + return 0, err + } + var overflow bool + if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + return 0, errGasUintOverflow + } + return gas, nil } -func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { - return memoryGasCost(mem, memorySize) +func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { + gas, err := memoryGasCost(mem, memorySize) + if err != nil { + return 0, err + } + evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) + if err != nil { + return 0, err + } + var overflow bool + if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { + return 0, errGasUintOverflow + } + return gas, nil } -func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { +func gasSuicide(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { var gas uint64 // EIP150 homestead gas reprice fork: if evm.chainRules.IsEIP150 { @@ -409,43 +384,3 @@ func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, } 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(evm.chainRules.IsEIP150, 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(evm.chainRules.IsEIP150, 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 -} diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index bb67de176e..612c4e2a21 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -23,7 +23,6 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/math" - "github.com/ethereum/go-ethereum/params" ) // Config are the configuration options for the Interpreter @@ -71,9 +70,8 @@ type keccakState interface { // EVMInterpreter represents an EVM interpreter type EVMInterpreter struct { - evm *EVM - cfg Config - gasTable params.GasTable + evm *EVM + cfg Config intPool *intPool @@ -107,9 +105,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { } return &EVMInterpreter{ - evm: evm, - cfg: cfg, - gasTable: evm.ChainConfig().GasTable(evm.BlockNumber), + evm: evm, + cfg: cfg, } } @@ -238,7 +235,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) ( // 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 if operation.dynamicGas != nil { - cost, err = operation.dynamicGas(in.gasTable, in.evm, contract, stack, mem, memorySize) + cost, err = operation.dynamicGas(in.evm, contract, stack, mem, memorySize) if err != nil || !contract.UseGas(cost) { return nil, ErrOutOfGas } diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 793bc74af7..fbfb0a821d 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -24,7 +24,7 @@ import ( type ( executionFunc func(pc *uint64, interpreter *EVMInterpreter, contract *Contract, memory *Memory, stack *Stack) ([]byte, error) - gasFunc func(params.GasTable, *EVM, *Contract, *Stack, *Memory, uint64) (uint64, error) // last parameter is the requested memory size as a uint64 + gasFunc func(*EVM, *Contract, *Stack, *Memory, uint64) (uint64, 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) ) @@ -115,13 +115,14 @@ func newByzantiumInstructionSet() [256]operation { // instructions that can be executed during the homestead phase. instructionSet := newSpuriousDragonInstructionSet() instructionSet[STATICCALL] = operation{ - execute: opStaticCall, - dynamicGas: gasStaticCall, - minStack: minStack(6, 1), - maxStack: maxStack(6, 1), - memorySize: memoryStaticCall, - valid: true, - returns: true, + execute: opStaticCall, + constantGas: params.CallGasEip150, + dynamicGas: gasStaticCall, + minStack: minStack(6, 1), + maxStack: maxStack(6, 1), + memorySize: memoryStaticCall, + valid: true, + returns: true, } instructionSet[RETURNDATASIZE] = operation{ execute: opReturnDataSize, @@ -152,6 +153,7 @@ func newByzantiumInstructionSet() [256]operation { return instructionSet } +// EIP 158 a.k.a Spurious Dragon func newSpuriousDragonInstructionSet() [256]operation { instructionSet := newTangerineWhistleInstructionSet() instructionSet[EXP].dynamicGas = gasExpEip158 @@ -159,12 +161,16 @@ func newSpuriousDragonInstructionSet() [256]operation { } +// EIP 150 a.k.a Tangerine Whistle func newTangerineWhistleInstructionSet() [256]operation { instructionSet := newHomesteadInstructionSet() instructionSet[BALANCE].constantGas = params.BalanceGasEip150 instructionSet[EXTCODESIZE].constantGas = params.ExtcodeSizeGasEip150 instructionSet[SLOAD].constantGas = params.SloadGasEip150 instructionSet[EXTCODECOPY].constantGas = params.ExtcodeCopyBaseEip150 + instructionSet[CALL].constantGas = params.CallGasEip150 + instructionSet[CALLCODE].constantGas = params.CallGasEip150 + instructionSet[DELEGATECALL].constantGas = params.CallGasEip150 return instructionSet } @@ -173,13 +179,14 @@ func newTangerineWhistleInstructionSet() [256]operation { func newHomesteadInstructionSet() [256]operation { instructionSet := newFrontierInstructionSet() instructionSet[DELEGATECALL] = operation{ - execute: opDelegateCall, - dynamicGas: gasDelegateCall, - minStack: minStack(6, 1), - maxStack: maxStack(6, 1), - memorySize: memoryDelegateCall, - valid: true, - returns: true, + execute: opDelegateCall, + dynamicGas: gasDelegateCall, + constantGas: params.CallGasFrontier, + minStack: minStack(6, 1), + maxStack: maxStack(6, 1), + memorySize: memoryDelegateCall, + valid: true, + returns: true, } return instructionSet } @@ -1097,22 +1104,24 @@ func newFrontierInstructionSet() [256]operation { returns: true, }, CALL: { - execute: opCall, - dynamicGas: gasCall, - minStack: minStack(7, 1), - maxStack: maxStack(7, 1), - memorySize: memoryCall, - valid: true, - returns: true, + execute: opCall, + constantGas: params.CallGasFrontier, + dynamicGas: gasCall, + minStack: minStack(7, 1), + maxStack: maxStack(7, 1), + memorySize: memoryCall, + valid: true, + returns: true, }, CALLCODE: { - execute: opCallCode, - dynamicGas: gasCallCode, - minStack: minStack(7, 1), - maxStack: maxStack(7, 1), - memorySize: memoryCall, - valid: true, - returns: true, + execute: opCallCode, + constantGas: params.CallGasFrontier, + dynamicGas: gasCallCode, + minStack: minStack(7, 1), + maxStack: maxStack(7, 1), + memorySize: memoryCall, + valid: true, + returns: true, }, RETURN: { execute: opReturn, diff --git a/params/config.go b/params/config.go index 6f75562d6b..bd695fb113 100644 --- a/params/config.go +++ b/params/config.go @@ -298,23 +298,6 @@ func (c *ChainConfig) IsEWASM(num *big.Int) bool { return isForked(c.EWASMBlock, num) } -// GasTable returns the gas table corresponding to the current phase (homestead or homestead reprice). -// -// The returned GasTable's fields shouldn't, under any circumstances, be changed. -func (c *ChainConfig) GasTable(num *big.Int) GasTable { - if num == nil { - return GasTableHomestead - } - switch { - case c.IsEIP158(num): - return GasTableEIP158 - case c.IsEIP150(num): - return GasTableEIP150 - default: - return GasTableHomestead - } -} - // CheckCompatible checks whether scheduled fork transitions have been imported // with a mismatching chain configuration. func (c *ChainConfig) CheckCompatible(newcfg *ChainConfig, height uint64) *ConfigCompatError { diff --git a/params/gas_table.go b/params/gas_table.go deleted file mode 100644 index 41b5e8e821..0000000000 --- a/params/gas_table.go +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright 2016 The go-ethereum Authors -// This file is part of the go-ethereum library. -// -// The go-ethereum library is free software: you can redistribute it and/or modify -// it under the terms of the GNU Lesser General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// The go-ethereum library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public License -// along with the go-ethereum library. If not, see . - -package params - -// GasTable organizes gas prices for different ethereum phases. -type GasTable struct { - Calls uint64 -} - -// Variables containing gas prices for different ethereum phases. -var ( - // GasTableHomestead contain the gas prices for - // the homestead phase. - GasTableHomestead = GasTable{ - Calls: 40, - } - - // GasTableEIP150 contain the gas re-prices for - // the EIP150 phase (a.k.a TangerineWhistle). - GasTableEIP150 = GasTable{ - Calls: 700, - } - // GasTableEIP158 contain the gas re-prices for - // the EIP155/EIP158 phase (a.k.a Spurious Dragon). - GasTableEIP158 = GasTable{ - Calls: 700, - } -) diff --git a/params/protocol_params.go b/params/protocol_params.go index 42b8c19a97..4a79c126b1 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -52,9 +52,9 @@ const ( NetSstoreResetRefund uint64 = 4800 // Once per SSTORE operation for resetting to the original non-zero value NetSstoreResetClearRefund uint64 = 19800 // Once per SSTORE operation for resetting to the original zero value - JumpdestGas uint64 = 1 // Once per JUMPDEST operation. - EpochDuration uint64 = 30000 // Duration between proof-of-work epochs. - CallGas uint64 = 40 // Once per CALL operation & message call transaction. + JumpdestGas uint64 = 1 // Once per JUMPDEST operation. + EpochDuration uint64 = 30000 // Duration between proof-of-work epochs. + CreateDataGas uint64 = 200 // CallCreateDepth uint64 = 1024 // Maximum depth of call/create stack. ExpGas uint64 = 10 // Once per EXP instruction @@ -70,6 +70,8 @@ const ( TxDataNonZeroGas uint64 = 68 // Per byte of data attached to a transaction that is not equal to zero. NOTE: Not payable on data of calls between transactions. // These have been changed during the course of the chain + CallGasFrontier uint64 = 40 // Once per CALL operation & message call transaction. + CallGasEip150 uint64 = 700 // Static portion of gas for CALL-derivates after EIP 150 (T.W) BalanceGasFrontier uint64 = 20 // The cost of a BALANCE operation BalanceGasEip150 uint64 = 400 // The cost of a BALANCE operation after Tangerine Whistle ExtcodeSizeGasFrontier uint64 = 20 // Cost of EXTCODESIZE before EIP 150 (T.W)