2017-04-14 08:29:00 +00:00
// 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/>.
2017-01-05 10:52:10 +00:00
package vm
import (
2019-08-19 11:39:38 +00:00
"errors"
2020-05-25 11:12:25 +00:00
"github.com/holiman/uint256"
2019-05-27 13:51:49 +00:00
"github.com/ledgerwatch/turbo-geth/common"
"github.com/ledgerwatch/turbo-geth/common/math"
2020-06-05 14:45:56 +00:00
"github.com/ledgerwatch/turbo-geth/core/vm/stack"
2019-05-27 13:51:49 +00:00
"github.com/ledgerwatch/turbo-geth/params"
2017-01-05 10:52:10 +00:00
)
2019-01-24 11:14:02 +00:00
// memoryGasCost calculates the quadratic gas for memory expansion. It does so
2017-01-04 19:17:24 +00:00
// 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
2017-02-02 14:25:42 +00:00
}
2019-04-01 11:56:43 +00:00
// 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 0xFFFFFFFF will cause the square operation to
// overflow. The constant 0x1FFFFFFFE0 is the highest number that can be used
// without overflowing the gas calculation.
2019-03-28 21:04:31 +00:00
if newMemSize > 0x1FFFFFFFE0 {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-06-28 07:51:31 +00:00
}
2017-01-04 19:17:24 +00:00
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
2017-01-05 10:52:10 +00:00
}
2019-08-05 08:01:02 +00:00
// 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 {
2020-06-05 14:45:56 +00:00
return func ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2019-08-05 08:01:02 +00:00
// 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
2020-05-18 07:10:59 +00:00
words , overflow := stack . Back ( stackpos ) . Uint64WithOverflow ( )
2019-08-05 08:01:02 +00:00
if overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2019-08-05 08:01:02 +00:00
}
2017-08-16 10:07:33 +00:00
2019-08-05 08:01:02 +00:00
if words , overflow = math . SafeMul ( toWordSize ( words ) , params . CopyGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2019-08-05 08:01:02 +00:00
}
2017-08-16 10:07:33 +00:00
2019-08-05 08:01:02 +00:00
if gas , overflow = math . SafeAdd ( gas , words ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2019-08-05 08:01:02 +00:00
}
return gas , nil
2017-08-16 10:07:33 +00:00
}
}
2019-08-05 08:01:02 +00:00
var (
gasCallDataCopy = memoryCopierGas ( 2 )
gasCodeCopy = memoryCopierGas ( 2 )
gasExtCodeCopy = memoryCopierGas ( 3 )
gasReturnDataCopy = memoryCopierGas ( 2 )
)
2017-01-05 10:52:10 +00:00
2020-06-05 14:45:56 +00:00
func gasSStore ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2020-05-25 11:12:25 +00:00
value , x := stack . Back ( 1 ) , stack . Back ( 0 )
2020-05-24 16:43:54 +00:00
key := common . Hash ( x . Bytes32 ( ) )
2020-05-25 11:12:25 +00:00
var current uint256 . Int
2020-05-24 16:43:54 +00:00
evm . IntraBlockState . GetState ( contract . Address ( ) , & key , & current )
2019-05-27 13:51:49 +00:00
2018-09-18 13:24:35 +00:00
// The legacy gas metering only takes into consideration the current state
2019-01-24 10:36:30 +00:00
// 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 {
2018-09-18 13:24:35 +00:00
// 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 {
2020-05-25 11:12:25 +00:00
case current . IsZero ( ) && ! value . IsZero ( ) : // 0 => non 0
2018-09-18 13:24:35 +00:00
return params . SstoreSetGas , nil
2020-05-25 11:12:25 +00:00
case ! current . IsZero ( ) && value . IsZero ( ) : // non 0 => 0
2019-05-27 13:51:49 +00:00
evm . IntraBlockState . AddRefund ( params . SstoreRefundGas )
2018-09-18 13:24:35 +00:00
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.
2020-05-25 11:12:25 +00:00
if current . Eq ( value ) { // noop (1)
2018-09-18 13:24:35 +00:00
return params . NetSstoreNoopGas , nil
}
2020-05-25 11:12:25 +00:00
var original uint256 . Int
2020-05-24 16:43:54 +00:00
evm . IntraBlockState . GetCommittedState ( contract . Address ( ) , & key , & original )
2018-09-18 13:24:35 +00:00
if original == current {
2020-05-25 11:12:25 +00:00
if original . IsZero ( ) { // create slot (2.1.1)
2018-09-18 13:24:35 +00:00
return params . NetSstoreInitGas , nil
2018-08-11 21:03:54 +00:00
}
2020-05-25 11:12:25 +00:00
if value . IsZero ( ) { // delete slot (2.1.2b)
2019-05-27 13:51:49 +00:00
evm . IntraBlockState . AddRefund ( params . NetSstoreClearRefund )
2018-08-11 21:03:54 +00:00
}
2018-09-18 13:24:35 +00:00
return params . NetSstoreCleanGas , nil // write existing slot (2.1.2)
}
2020-05-25 11:12:25 +00:00
if ! original . IsZero ( ) {
if current . IsZero ( ) { // recreate slot (2.2.1.1)
2019-05-27 13:51:49 +00:00
evm . IntraBlockState . SubRefund ( params . NetSstoreClearRefund )
2020-05-25 11:12:25 +00:00
} else if value . IsZero ( ) { // delete slot (2.2.1.2)
2019-05-27 13:51:49 +00:00
evm . IntraBlockState . AddRefund ( params . NetSstoreClearRefund )
2018-08-11 21:03:54 +00:00
}
}
2020-05-25 11:12:25 +00:00
if original . Eq ( value ) {
if original . IsZero ( ) { // reset to original inexistent slot (2.2.2.1)
2019-05-27 13:51:49 +00:00
evm . IntraBlockState . AddRefund ( params . NetSstoreResetClearRefund )
2018-09-18 13:24:35 +00:00
} else { // reset to original existing slot (2.2.2.2)
2019-05-27 13:51:49 +00:00
evm . IntraBlockState . AddRefund ( params . NetSstoreResetRefund )
2018-08-11 21:03:54 +00:00
}
}
2019-05-27 13:51:49 +00:00
2018-09-18 13:24:35 +00:00
return params . NetSstoreDirtyGas , nil
2018-08-11 21:03:54 +00:00
}
2019-08-19 11:39:38 +00:00
// 0. If *gasleft* is less than or equal to 2300, fail the current call.
// 1. If current value equals new value (this is a no-op), SSTORE_NOOP_GAS 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, SSTORE_INIT_GAS gas is deducted.
// 2.1.2. Otherwise, SSTORE_CLEAN_GAS gas is deducted. If new value is 0, add SSTORE_CLEAR_REFUND to refund counter.
// 2.2. If original value does not equal current value (this storage slot is dirty), SSTORE_DIRTY_GAS 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), subtract SSTORE_CLEAR_REFUND 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 SSTORE_CLEAR_REFUND 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 SSTORE_INIT_REFUND to refund counter.
// 2.2.2.2. Otherwise, add SSTORE_CLEAN_REFUND gas to refund counter.
2020-06-05 14:45:56 +00:00
func gasSStoreEIP2200 ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2019-08-19 11:39:38 +00:00
// 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" )
}
// Gas sentry honoured, do the actual gas calculation based on the stored value
2020-05-25 11:12:25 +00:00
value , x := stack . Back ( 1 ) , stack . Back ( 0 )
2020-05-24 16:43:54 +00:00
key := common . Hash ( x . Bytes32 ( ) )
2020-05-25 11:12:25 +00:00
var current uint256 . Int
2020-05-24 16:43:54 +00:00
evm . IntraBlockState . GetState ( contract . Address ( ) , & key , & current )
2019-08-19 11:39:38 +00:00
2020-05-25 11:12:25 +00:00
if current . Eq ( value ) { // noop (1)
2019-08-19 11:39:38 +00:00
return params . SstoreNoopGasEIP2200 , nil
}
2020-06-04 18:30:28 +00:00
2020-05-25 11:12:25 +00:00
var original uint256 . Int
2020-05-24 16:43:54 +00:00
evm . IntraBlockState . GetCommittedState ( contract . Address ( ) , & key , & original )
2019-08-19 11:39:38 +00:00
if original == current {
2020-05-25 11:12:25 +00:00
if original . IsZero ( ) { // create slot (2.1.1)
2019-08-19 11:39:38 +00:00
return params . SstoreInitGasEIP2200 , nil
}
2020-05-25 11:12:25 +00:00
if value . IsZero ( ) { // delete slot (2.1.2b)
2019-05-27 13:51:49 +00:00
evm . IntraBlockState . AddRefund ( params . SstoreClearRefundEIP2200 )
2019-08-19 11:39:38 +00:00
}
return params . SstoreCleanGasEIP2200 , nil // write existing slot (2.1.2)
}
2020-05-25 11:12:25 +00:00
if ! original . IsZero ( ) {
if current . IsZero ( ) { // recreate slot (2.2.1.1)
2019-05-27 13:51:49 +00:00
evm . IntraBlockState . SubRefund ( params . SstoreClearRefundEIP2200 )
2020-05-25 11:12:25 +00:00
} else if value . IsZero ( ) { // delete slot (2.2.1.2)
2019-05-27 13:51:49 +00:00
evm . IntraBlockState . AddRefund ( params . SstoreClearRefundEIP2200 )
2019-08-19 11:39:38 +00:00
}
}
2020-05-25 11:12:25 +00:00
if original . Eq ( value ) {
if original . IsZero ( ) { // reset to original inexistent slot (2.2.2.1)
2019-05-27 13:51:49 +00:00
evm . IntraBlockState . AddRefund ( params . SstoreInitRefundEIP2200 )
2019-08-19 11:39:38 +00:00
} else { // reset to original existing slot (2.2.2.2)
2019-05-27 13:51:49 +00:00
evm . IntraBlockState . AddRefund ( params . SstoreCleanRefundEIP2200 )
2019-08-19 11:39:38 +00:00
}
}
return params . SstoreDirtyGasEIP2200 , nil // dirty update (2.2)
}
2017-01-04 19:17:24 +00:00
func makeGasLog ( n uint64 ) gasFunc {
2020-06-05 14:45:56 +00:00
return func ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2020-05-18 07:10:59 +00:00
requestedSize , overflow := stack . Back ( 1 ) . Uint64WithOverflow ( )
2017-01-04 19:17:24 +00:00
if overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
2017-01-05 10:52:10 +00:00
2017-01-04 19:17:24 +00:00
gas , err := memoryGasCost ( mem , memorySize )
if err != nil {
return 0 , err
}
if gas , overflow = math . SafeAdd ( gas , params . LogGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
if gas , overflow = math . SafeAdd ( gas , n * params . LogTopicGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
var memorySizeGas uint64
if memorySizeGas , overflow = math . SafeMul ( requestedSize , params . LogDataGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
if gas , overflow = math . SafeAdd ( gas , memorySizeGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
return gas , nil
2017-01-05 10:52:10 +00:00
}
}
2020-06-05 14:45:56 +00:00
func gasSha3 ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2017-01-04 19:17:24 +00:00
gas , err := memoryGasCost ( mem , memorySize )
if err != nil {
return 0 , err
}
2020-05-18 07:10:59 +00:00
wordGas , overflow := stack . Back ( 1 ) . Uint64WithOverflow ( )
2017-01-04 19:17:24 +00:00
if overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
if wordGas , overflow = math . SafeMul ( toWordSize ( wordGas ) , params . Sha3WordGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
if gas , overflow = math . SafeAdd ( gas , wordGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
return gas , nil
2017-01-05 10:52:10 +00:00
}
2019-08-05 08:01:02 +00:00
// pureMemoryGascost is used by several operations, which aside from their
// static cost have a dynamic cost which is solely based on the memory
// expansion
2020-06-05 14:45:56 +00:00
func pureMemoryGascost ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2019-08-05 08:01:02 +00:00
return memoryGasCost ( mem , memorySize )
2017-01-05 10:52:10 +00:00
}
2019-08-05 08:01:02 +00:00
var (
gasReturn = pureMemoryGascost
gasRevert = pureMemoryGascost
gasMLoad = pureMemoryGascost
gasMStore8 = pureMemoryGascost
gasMStore = pureMemoryGascost
gasCreate = pureMemoryGascost
)
2017-01-05 10:52:10 +00:00
2020-06-05 14:45:56 +00:00
func gasCreate2 ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2018-07-24 14:22:03 +00:00
gas , err := memoryGasCost ( mem , memorySize )
if err != nil {
return 0 , err
}
2020-05-18 07:10:59 +00:00
wordGas , overflow := stack . Back ( 2 ) . Uint64WithOverflow ( )
2018-10-05 07:32:35 +00:00
if overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2018-10-05 07:32:35 +00:00
}
if wordGas , overflow = math . SafeMul ( toWordSize ( wordGas ) , params . Sha3WordGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2018-10-05 07:32:35 +00:00
}
if gas , overflow = math . SafeAdd ( gas , wordGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2018-10-05 07:32:35 +00:00
}
2018-07-24 14:22:03 +00:00
return gas , nil
}
2020-06-05 14:45:56 +00:00
func gasExpFrontier ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
expByteLen := uint64 ( ( stack . Data [ stack . Len ( ) - 2 ] . BitLen ( ) + 7 ) / 8 )
2017-01-05 10:52:10 +00:00
2019-08-05 08:01:02 +00:00
var (
gas = expByteLen * params . ExpByteFrontier // no overflow check required. Max is 256 * ExpByte gas
overflow bool
)
if gas , overflow = math . SafeAdd ( gas , params . ExpGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2019-08-05 08:01:02 +00:00
}
return gas , nil
2017-02-02 14:25:42 +00:00
}
2020-06-05 14:45:56 +00:00
func gasExpEIP158 ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
expByteLen := uint64 ( ( stack . Data [ stack . Len ( ) - 2 ] . BitLen ( ) + 7 ) / 8 )
2017-02-08 12:39:26 +00:00
2017-02-02 14:25:42 +00:00
var (
2019-08-05 08:01:02 +00:00
gas = expByteLen * params . ExpByteEIP158 // no overflow check required. Max is 256 * ExpByte gas
2017-01-04 19:17:24 +00:00
overflow bool
)
2019-01-24 11:14:02 +00:00
if gas , overflow = math . SafeAdd ( gas , params . ExpGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
return gas , nil
}
2020-06-05 14:45:56 +00:00
func gasCall ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2017-01-04 19:17:24 +00:00
var (
2019-08-05 08:01:02 +00:00
gas uint64
2020-05-18 07:10:59 +00:00
transfersValue = ! stack . Back ( 2 ) . IsZero ( )
address = common . Address ( stack . Back ( 1 ) . Bytes20 ( ) )
2017-01-05 10:52:10 +00:00
)
2019-08-05 08:01:02 +00:00
if evm . chainRules . IsEIP158 {
2019-05-27 13:51:49 +00:00
if transfersValue && evm . IntraBlockState . Empty ( address ) {
2017-01-04 19:17:24 +00:00
gas += params . CallNewAccountGas
2017-01-05 10:52:10 +00:00
}
2019-05-27 13:51:49 +00:00
} else if ! evm . IntraBlockState . Exist ( address ) {
2017-01-04 19:17:24 +00:00
gas += params . CallNewAccountGas
2017-01-05 10:52:10 +00:00
}
if transfersValue {
2017-01-04 19:17:24 +00:00
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 {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-05 10:52:10 +00:00
}
2019-08-05 08:01:02 +00:00
evm . callGasTemp , err = callGas ( evm . chainRules . IsEIP150 , contract . Gas , gas , stack . Back ( 0 ) )
2017-01-04 19:17:24 +00:00
if err != nil {
return 0 , err
}
2017-11-28 19:05:49 +00:00
if gas , overflow = math . SafeAdd ( gas , evm . callGasTemp ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
return gas , nil
2017-01-05 10:52:10 +00:00
}
2020-06-05 14:45:56 +00:00
func gasCallCode ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2017-01-04 19:17:24 +00:00
memoryGas , err := memoryGasCost ( mem , memorySize )
if err != nil {
return 0 , err
}
2019-08-05 08:01:02 +00:00
var (
gas uint64
overflow bool
)
if stack . Back ( 2 ) . Sign ( ) != 0 {
gas += params . CallValueTransferGas
}
2017-01-04 19:17:24 +00:00
if gas , overflow = math . SafeAdd ( gas , memoryGas ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-05 10:52:10 +00:00
}
2019-08-05 08:01:02 +00:00
evm . callGasTemp , err = callGas ( evm . chainRules . IsEIP150 , contract . Gas , gas , stack . Back ( 0 ) )
2017-01-04 19:17:24 +00:00
if err != nil {
return 0 , err
}
2017-11-28 19:05:49 +00:00
if gas , overflow = math . SafeAdd ( gas , evm . callGasTemp ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
return gas , nil
2017-01-05 10:52:10 +00:00
}
2020-06-05 14:45:56 +00:00
func gasDelegateCall ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2017-01-04 19:17:24 +00:00
gas , err := memoryGasCost ( mem , memorySize )
if err != nil {
return 0 , err
}
2019-08-05 08:01:02 +00:00
evm . callGasTemp , err = callGas ( evm . chainRules . IsEIP150 , contract . Gas , gas , stack . Back ( 0 ) )
2017-08-15 08:23:23 +00:00
if err != nil {
return 0 , err
}
2019-08-05 08:01:02 +00:00
var overflow bool
2017-11-28 19:05:49 +00:00
if gas , overflow = math . SafeAdd ( gas , evm . callGasTemp ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-08-15 08:23:23 +00:00
}
return gas , nil
}
2020-06-05 14:45:56 +00:00
func gasStaticCall ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2017-08-15 08:23:23 +00:00
gas , err := memoryGasCost ( mem , memorySize )
if err != nil {
return 0 , err
}
2019-08-05 08:01:02 +00:00
evm . callGasTemp , err = callGas ( evm . chainRules . IsEIP150 , contract . Gas , gas , stack . Back ( 0 ) )
2017-01-04 19:17:24 +00:00
if err != nil {
return 0 , err
}
2019-08-05 08:01:02 +00:00
var overflow bool
2017-11-28 19:05:49 +00:00
if gas , overflow = math . SafeAdd ( gas , evm . callGasTemp ) ; overflow {
2020-04-22 08:25:36 +00:00
return 0 , ErrGasUintOverflow
2017-01-04 19:17:24 +00:00
}
return gas , nil
2017-01-05 10:52:10 +00:00
}
2019-08-05 08:01:02 +00:00
2020-06-05 14:45:56 +00:00
func gasSelfdestruct ( evm * EVM , contract * Contract , stack * stack . Stack , mem * Memory , memorySize uint64 ) ( uint64 , error ) {
2019-08-05 08:01:02 +00:00
var gas uint64
// EIP150 homestead gas reprice fork:
if evm . chainRules . IsEIP150 {
gas = params . SelfdestructGasEIP150
2020-05-18 07:10:59 +00:00
var address = common . Address ( stack . Back ( 0 ) . Bytes20 ( ) )
2019-08-05 08:01:02 +00:00
if evm . chainRules . IsEIP158 {
// if empty and transfers value
2019-05-27 13:51:49 +00:00
if evm . IntraBlockState . Empty ( address ) && evm . IntraBlockState . GetBalance ( contract . Address ( ) ) . Sign ( ) != 0 {
2019-08-05 08:01:02 +00:00
gas += params . CreateBySelfdestructGas
}
2019-05-27 13:51:49 +00:00
} else if ! evm . IntraBlockState . Exist ( address ) {
2019-08-05 08:01:02 +00:00
gas += params . CreateBySelfdestructGas
}
}
2019-05-27 13:51:49 +00:00
if ! evm . IntraBlockState . HasSuicided ( contract . Address ( ) ) {
evm . IntraBlockState . AddRefund ( params . SelfdestructRefundGas )
2019-08-05 08:01:02 +00:00
}
return gas , nil
}