github.com/humaniq/go-ethereum@v1.6.8-0.20171225131628-061223a13848/core/vm/gas_table.go (about)

     1  // Copyright 2017 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package vm
    18  
    19  import (
    20  	"math/big"
    21  
    22  	"github.com/ethereum/go-ethereum/common"
    23  	"github.com/ethereum/go-ethereum/common/math"
    24  	"github.com/ethereum/go-ethereum/params"
    25  )
    26  
    27  // memoryGasCosts calculates the quadratic gas for memory expansion. It does so
    28  // only for the memory region that is expanded, not the total memory.
    29  func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
    30  
    31  	if newMemSize == 0 {
    32  		return 0, nil
    33  	}
    34  	// The maximum that will fit in a uint64 is max_word_count - 1
    35  	// anything above that will result in an overflow.
    36  	// Additionally, a newMemSize which results in a
    37  	// newMemSizeWords larger than 0x7ffffffff will cause the square operation
    38  	// to overflow.
    39  	// The constant 0xffffffffe0 is the highest number that can be used without
    40  	// overflowing the gas calculation
    41  	if newMemSize > 0xffffffffe0 {
    42  		return 0, errGasUintOverflow
    43  	}
    44  
    45  	newMemSizeWords := toWordSize(newMemSize)
    46  	newMemSize = newMemSizeWords * 32
    47  
    48  	if newMemSize > uint64(mem.Len()) {
    49  		square := newMemSizeWords * newMemSizeWords
    50  		linCoef := newMemSizeWords * params.MemoryGas
    51  		quadCoef := square / params.QuadCoeffDiv
    52  		newTotalFee := linCoef + quadCoef
    53  
    54  		fee := newTotalFee - mem.lastGasCost
    55  		mem.lastGasCost = newTotalFee
    56  
    57  		return fee, nil
    58  	}
    59  	return 0, nil
    60  }
    61  
    62  func constGasFunc(gas uint64) gasFunc {
    63  	return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
    64  		return gas, nil
    65  	}
    66  }
    67  
    68  func gasCallDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
    69  	gas, err := memoryGasCost(mem, memorySize)
    70  	if err != nil {
    71  		return 0, err
    72  	}
    73  
    74  	var overflow bool
    75  	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
    76  		return 0, errGasUintOverflow
    77  	}
    78  
    79  	words, overflow := bigUint64(stack.Back(2))
    80  	if overflow {
    81  		return 0, errGasUintOverflow
    82  	}
    83  
    84  	if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
    85  		return 0, errGasUintOverflow
    86  	}
    87  
    88  	if gas, overflow = math.SafeAdd(gas, words); overflow {
    89  		return 0, errGasUintOverflow
    90  	}
    91  	return gas, nil
    92  }
    93  
    94  func gasReturnDataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
    95  	gas, err := memoryGasCost(mem, memorySize)
    96  	if err != nil {
    97  		return 0, err
    98  	}
    99  
   100  	var overflow bool
   101  	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
   102  		return 0, errGasUintOverflow
   103  	}
   104  
   105  	words, overflow := bigUint64(stack.Back(2))
   106  	if overflow {
   107  		return 0, errGasUintOverflow
   108  	}
   109  
   110  	if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
   111  		return 0, errGasUintOverflow
   112  	}
   113  
   114  	if gas, overflow = math.SafeAdd(gas, words); overflow {
   115  		return 0, errGasUintOverflow
   116  	}
   117  	return gas, nil
   118  }
   119  
   120  func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   121  	var (
   122  		y, x = stack.Back(1), stack.Back(0)
   123  		val  = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
   124  	)
   125  	// This checks for 3 scenario's and calculates gas accordingly
   126  	// 1. From a zero-value address to a non-zero value         (NEW VALUE)
   127  	// 2. From a non-zero value address to a zero-value address (DELETE)
   128  	// 3. From a non-zero to a non-zero                         (CHANGE)
   129  	if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
   130  		// 0 => non 0
   131  		return params.SstoreSetGas, nil
   132  	} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
   133  		evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SstoreRefundGas))
   134  
   135  		return params.SstoreClearGas, nil
   136  	} else {
   137  		// non 0 => non 0 (or 0 => 0)
   138  		return params.SstoreResetGas, nil
   139  	}
   140  }
   141  
   142  func makeGasLog(n uint64) gasFunc {
   143  	return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   144  		requestedSize, overflow := bigUint64(stack.Back(1))
   145  		if overflow {
   146  			return 0, errGasUintOverflow
   147  		}
   148  
   149  		gas, err := memoryGasCost(mem, memorySize)
   150  		if err != nil {
   151  			return 0, err
   152  		}
   153  
   154  		if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow {
   155  			return 0, errGasUintOverflow
   156  		}
   157  		if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow {
   158  			return 0, errGasUintOverflow
   159  		}
   160  
   161  		var memorySizeGas uint64
   162  		if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow {
   163  			return 0, errGasUintOverflow
   164  		}
   165  		if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow {
   166  			return 0, errGasUintOverflow
   167  		}
   168  		return gas, nil
   169  	}
   170  }
   171  
   172  func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   173  	var overflow bool
   174  	gas, err := memoryGasCost(mem, memorySize)
   175  	if err != nil {
   176  		return 0, err
   177  	}
   178  
   179  	if gas, overflow = math.SafeAdd(gas, params.Sha3Gas); overflow {
   180  		return 0, errGasUintOverflow
   181  	}
   182  
   183  	wordGas, overflow := bigUint64(stack.Back(1))
   184  	if overflow {
   185  		return 0, errGasUintOverflow
   186  	}
   187  	if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
   188  		return 0, errGasUintOverflow
   189  	}
   190  	if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
   191  		return 0, errGasUintOverflow
   192  	}
   193  	return gas, nil
   194  }
   195  
   196  func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   197  	gas, err := memoryGasCost(mem, memorySize)
   198  	if err != nil {
   199  		return 0, err
   200  	}
   201  
   202  	var overflow bool
   203  	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
   204  		return 0, errGasUintOverflow
   205  	}
   206  
   207  	wordGas, overflow := bigUint64(stack.Back(2))
   208  	if overflow {
   209  		return 0, errGasUintOverflow
   210  	}
   211  	if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
   212  		return 0, errGasUintOverflow
   213  	}
   214  	if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
   215  		return 0, errGasUintOverflow
   216  	}
   217  	return gas, nil
   218  }
   219  
   220  func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   221  	gas, err := memoryGasCost(mem, memorySize)
   222  	if err != nil {
   223  		return 0, err
   224  	}
   225  
   226  	var overflow bool
   227  	if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow {
   228  		return 0, errGasUintOverflow
   229  	}
   230  
   231  	wordGas, overflow := bigUint64(stack.Back(3))
   232  	if overflow {
   233  		return 0, errGasUintOverflow
   234  	}
   235  
   236  	if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
   237  		return 0, errGasUintOverflow
   238  	}
   239  
   240  	if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
   241  		return 0, errGasUintOverflow
   242  	}
   243  	return gas, nil
   244  }
   245  
   246  func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   247  	var overflow bool
   248  	gas, err := memoryGasCost(mem, memorySize)
   249  	if err != nil {
   250  		return 0, errGasUintOverflow
   251  	}
   252  	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
   253  		return 0, errGasUintOverflow
   254  	}
   255  	return gas, nil
   256  }
   257  
   258  func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   259  	var overflow bool
   260  	gas, err := memoryGasCost(mem, memorySize)
   261  	if err != nil {
   262  		return 0, errGasUintOverflow
   263  	}
   264  	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
   265  		return 0, errGasUintOverflow
   266  	}
   267  	return gas, nil
   268  }
   269  
   270  func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   271  	var overflow bool
   272  	gas, err := memoryGasCost(mem, memorySize)
   273  	if err != nil {
   274  		return 0, errGasUintOverflow
   275  	}
   276  	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
   277  		return 0, errGasUintOverflow
   278  	}
   279  	return gas, nil
   280  }
   281  
   282  func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   283  	var overflow bool
   284  	gas, err := memoryGasCost(mem, memorySize)
   285  	if err != nil {
   286  		return 0, err
   287  	}
   288  	if gas, overflow = math.SafeAdd(gas, params.CreateGas); overflow {
   289  		return 0, errGasUintOverflow
   290  	}
   291  	return gas, nil
   292  }
   293  
   294  func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   295  	return gt.Balance, nil
   296  }
   297  
   298  func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   299  	return gt.ExtcodeSize, nil
   300  }
   301  
   302  func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   303  	return gt.SLoad, nil
   304  }
   305  
   306  func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   307  	expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
   308  
   309  	var (
   310  		gas      = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas
   311  		overflow bool
   312  	)
   313  	if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow {
   314  		return 0, errGasUintOverflow
   315  	}
   316  	return gas, nil
   317  }
   318  
   319  func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   320  	var (
   321  		gas            = gt.Calls
   322  		transfersValue = stack.Back(2).Sign() != 0
   323  		address        = common.BigToAddress(stack.Back(1))
   324  		eip158         = evm.ChainConfig().IsEIP158(evm.BlockNumber)
   325  	)
   326  	if eip158 {
   327  		if transfersValue && evm.StateDB.Empty(address) {
   328  			gas += params.CallNewAccountGas
   329  		}
   330  	} else if !evm.StateDB.Exist(address) {
   331  		gas += params.CallNewAccountGas
   332  	}
   333  	if transfersValue {
   334  		gas += params.CallValueTransferGas
   335  	}
   336  	memoryGas, err := memoryGasCost(mem, memorySize)
   337  	if err != nil {
   338  		return 0, err
   339  	}
   340  	var overflow bool
   341  	if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
   342  		return 0, errGasUintOverflow
   343  	}
   344  
   345  	evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
   346  	if err != nil {
   347  		return 0, err
   348  	}
   349  	if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
   350  		return 0, errGasUintOverflow
   351  	}
   352  	return gas, nil
   353  }
   354  
   355  func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   356  	gas := gt.Calls
   357  	if stack.Back(2).Sign() != 0 {
   358  		gas += params.CallValueTransferGas
   359  	}
   360  	memoryGas, err := memoryGasCost(mem, memorySize)
   361  	if err != nil {
   362  		return 0, err
   363  	}
   364  	var overflow bool
   365  	if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
   366  		return 0, errGasUintOverflow
   367  	}
   368  
   369  	evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
   370  	if err != nil {
   371  		return 0, err
   372  	}
   373  	if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
   374  		return 0, errGasUintOverflow
   375  	}
   376  	return gas, nil
   377  }
   378  
   379  func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   380  	return memoryGasCost(mem, memorySize)
   381  }
   382  
   383  func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   384  	return memoryGasCost(mem, memorySize)
   385  }
   386  
   387  func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   388  	var gas uint64
   389  	// EIP150 homestead gas reprice fork:
   390  	if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
   391  		gas = gt.Suicide
   392  		var (
   393  			address = common.BigToAddress(stack.Back(0))
   394  			eip158  = evm.ChainConfig().IsEIP158(evm.BlockNumber)
   395  		)
   396  
   397  		if eip158 {
   398  			// if empty and transfers value
   399  			if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
   400  				gas += gt.CreateBySuicide
   401  			}
   402  		} else if !evm.StateDB.Exist(address) {
   403  			gas += gt.CreateBySuicide
   404  		}
   405  	}
   406  
   407  	if !evm.StateDB.HasSuicided(contract.Address()) {
   408  		evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas))
   409  	}
   410  	return gas, nil
   411  }
   412  
   413  func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   414  	gas, err := memoryGasCost(mem, memorySize)
   415  	if err != nil {
   416  		return 0, err
   417  	}
   418  	var overflow bool
   419  	if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
   420  		return 0, errGasUintOverflow
   421  	}
   422  
   423  	evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
   424  	if err != nil {
   425  		return 0, err
   426  	}
   427  	if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
   428  		return 0, errGasUintOverflow
   429  	}
   430  	return gas, nil
   431  }
   432  
   433  func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   434  	gas, err := memoryGasCost(mem, memorySize)
   435  	if err != nil {
   436  		return 0, err
   437  	}
   438  	var overflow bool
   439  	if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
   440  		return 0, errGasUintOverflow
   441  	}
   442  
   443  	evm.callGasTemp, err = callGas(gt, contract.Gas, gas, stack.Back(0))
   444  	if err != nil {
   445  		return 0, err
   446  	}
   447  	if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
   448  		return 0, errGasUintOverflow
   449  	}
   450  	return gas, nil
   451  }
   452  
   453  func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   454  	return GasFastestStep, nil
   455  }
   456  
   457  func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   458  	return GasFastestStep, nil
   459  }
   460  
   461  func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   462  	return GasFastestStep, nil
   463  }