github.com/bamzi/go-ethereum@v1.6.7-0.20170704111104-138f26c93af1/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 gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
    95  	var (
    96  		y, x = stack.Back(1), stack.Back(0)
    97  		val  = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
    98  	)
    99  	// This checks for 3 scenario's and calculates gas accordingly
   100  	// 1. From a zero-value address to a non-zero value         (NEW VALUE)
   101  	// 2. From a non-zero value address to a zero-value address (DELETE)
   102  	// 3. From a non-zero to a non-zero                         (CHANGE)
   103  	if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) {
   104  		// 0 => non 0
   105  		return params.SstoreSetGas, nil
   106  	} else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) {
   107  		evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SstoreRefundGas))
   108  
   109  		return params.SstoreClearGas, nil
   110  	} else {
   111  		// non 0 => non 0 (or 0 => 0)
   112  		return params.SstoreResetGas, nil
   113  	}
   114  }
   115  
   116  func makeGasLog(n uint64) gasFunc {
   117  	return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   118  		requestedSize, overflow := bigUint64(stack.Back(1))
   119  		if overflow {
   120  			return 0, errGasUintOverflow
   121  		}
   122  
   123  		gas, err := memoryGasCost(mem, memorySize)
   124  		if err != nil {
   125  			return 0, err
   126  		}
   127  
   128  		if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow {
   129  			return 0, errGasUintOverflow
   130  		}
   131  		if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow {
   132  			return 0, errGasUintOverflow
   133  		}
   134  
   135  		var memorySizeGas uint64
   136  		if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow {
   137  			return 0, errGasUintOverflow
   138  		}
   139  		if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow {
   140  			return 0, errGasUintOverflow
   141  		}
   142  		return gas, nil
   143  	}
   144  }
   145  
   146  func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   147  	var overflow bool
   148  	gas, err := memoryGasCost(mem, memorySize)
   149  	if err != nil {
   150  		return 0, err
   151  	}
   152  
   153  	if gas, overflow = math.SafeAdd(gas, params.Sha3Gas); overflow {
   154  		return 0, errGasUintOverflow
   155  	}
   156  
   157  	wordGas, overflow := bigUint64(stack.Back(1))
   158  	if overflow {
   159  		return 0, errGasUintOverflow
   160  	}
   161  	if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
   162  		return 0, errGasUintOverflow
   163  	}
   164  	if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
   165  		return 0, errGasUintOverflow
   166  	}
   167  	return gas, nil
   168  }
   169  
   170  func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   171  	gas, err := memoryGasCost(mem, memorySize)
   172  	if err != nil {
   173  		return 0, err
   174  	}
   175  
   176  	var overflow bool
   177  	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
   178  		return 0, errGasUintOverflow
   179  	}
   180  
   181  	wordGas, overflow := bigUint64(stack.Back(2))
   182  	if overflow {
   183  		return 0, errGasUintOverflow
   184  	}
   185  	if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
   186  		return 0, errGasUintOverflow
   187  	}
   188  	if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
   189  		return 0, errGasUintOverflow
   190  	}
   191  	return gas, nil
   192  }
   193  
   194  func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   195  	gas, err := memoryGasCost(mem, memorySize)
   196  	if err != nil {
   197  		return 0, err
   198  	}
   199  
   200  	var overflow bool
   201  	if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow {
   202  		return 0, errGasUintOverflow
   203  	}
   204  
   205  	wordGas, overflow := bigUint64(stack.Back(3))
   206  	if overflow {
   207  		return 0, errGasUintOverflow
   208  	}
   209  
   210  	if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow {
   211  		return 0, errGasUintOverflow
   212  	}
   213  
   214  	if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
   215  		return 0, errGasUintOverflow
   216  	}
   217  	return gas, nil
   218  }
   219  
   220  func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   221  	var overflow bool
   222  	gas, err := memoryGasCost(mem, memorySize)
   223  	if err != nil {
   224  		return 0, errGasUintOverflow
   225  	}
   226  	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
   227  		return 0, errGasUintOverflow
   228  	}
   229  	return gas, nil
   230  }
   231  
   232  func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   233  	var overflow bool
   234  	gas, err := memoryGasCost(mem, memorySize)
   235  	if err != nil {
   236  		return 0, errGasUintOverflow
   237  	}
   238  	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
   239  		return 0, errGasUintOverflow
   240  	}
   241  	return gas, nil
   242  }
   243  
   244  func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   245  	var overflow bool
   246  	gas, err := memoryGasCost(mem, memorySize)
   247  	if err != nil {
   248  		return 0, errGasUintOverflow
   249  	}
   250  	if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow {
   251  		return 0, errGasUintOverflow
   252  	}
   253  	return gas, nil
   254  }
   255  
   256  func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   257  	var overflow bool
   258  	gas, err := memoryGasCost(mem, memorySize)
   259  	if err != nil {
   260  		return 0, err
   261  	}
   262  	if gas, overflow = math.SafeAdd(gas, params.CreateGas); overflow {
   263  		return 0, errGasUintOverflow
   264  	}
   265  	return gas, nil
   266  }
   267  
   268  func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   269  	return gt.Balance, nil
   270  }
   271  
   272  func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   273  	return gt.ExtcodeSize, nil
   274  }
   275  
   276  func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   277  	return gt.SLoad, nil
   278  }
   279  
   280  func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   281  	expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
   282  
   283  	var (
   284  		gas      = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas
   285  		overflow bool
   286  	)
   287  	if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow {
   288  		return 0, errGasUintOverflow
   289  	}
   290  	return gas, nil
   291  }
   292  
   293  func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   294  	var (
   295  		gas            = gt.Calls
   296  		transfersValue = stack.Back(2).Sign() != 0
   297  		address        = common.BigToAddress(stack.Back(1))
   298  		eip158         = evm.ChainConfig().IsEIP158(evm.BlockNumber)
   299  	)
   300  	if eip158 {
   301  		if evm.StateDB.Empty(address) && transfersValue {
   302  			gas += params.CallNewAccountGas
   303  		}
   304  	} else if !evm.StateDB.Exist(address) {
   305  		gas += params.CallNewAccountGas
   306  	}
   307  	if transfersValue {
   308  		gas += params.CallValueTransferGas
   309  	}
   310  	memoryGas, err := memoryGasCost(mem, memorySize)
   311  	if err != nil {
   312  		return 0, err
   313  	}
   314  	var overflow bool
   315  	if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
   316  		return 0, errGasUintOverflow
   317  	}
   318  
   319  	cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
   320  	if err != nil {
   321  		return 0, err
   322  	}
   323  	// Replace the stack item with the new gas calculation. This means that
   324  	// either the original item is left on the stack or the item is replaced by:
   325  	// (availableGas - gas) * 63 / 64
   326  	// We replace the stack item so that it's available when the opCall instruction is
   327  	// called. This information is otherwise lost due to the dependency on *current*
   328  	// available gas.
   329  	stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
   330  
   331  	if gas, overflow = math.SafeAdd(gas, cg); overflow {
   332  		return 0, errGasUintOverflow
   333  	}
   334  	return gas, nil
   335  }
   336  
   337  func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   338  	gas := gt.Calls
   339  	if stack.Back(2).Sign() != 0 {
   340  		gas += params.CallValueTransferGas
   341  	}
   342  	memoryGas, err := memoryGasCost(mem, memorySize)
   343  	if err != nil {
   344  		return 0, err
   345  	}
   346  	var overflow bool
   347  	if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
   348  		return 0, errGasUintOverflow
   349  	}
   350  
   351  	cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
   352  	if err != nil {
   353  		return 0, err
   354  	}
   355  	// Replace the stack item with the new gas calculation. This means that
   356  	// either the original item is left on the stack or the item is replaced by:
   357  	// (availableGas - gas) * 63 / 64
   358  	// We replace the stack item so that it's available when the opCall instruction is
   359  	// called. This information is otherwise lost due to the dependency on *current*
   360  	// available gas.
   361  	stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
   362  
   363  	if gas, overflow = math.SafeAdd(gas, cg); overflow {
   364  		return 0, errGasUintOverflow
   365  	}
   366  	return gas, nil
   367  }
   368  
   369  func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   370  	return memoryGasCost(mem, memorySize)
   371  }
   372  
   373  func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   374  	var gas uint64
   375  	// EIP150 homestead gas reprice fork:
   376  	if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
   377  		gas = gt.Suicide
   378  		var (
   379  			address = common.BigToAddress(stack.Back(0))
   380  			eip158  = evm.ChainConfig().IsEIP158(evm.BlockNumber)
   381  		)
   382  
   383  		if eip158 {
   384  			// if empty and transfers value
   385  			if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
   386  				gas += gt.CreateBySuicide
   387  			}
   388  		} else if !evm.StateDB.Exist(address) {
   389  			gas += gt.CreateBySuicide
   390  		}
   391  	}
   392  
   393  	if !evm.StateDB.HasSuicided(contract.Address()) {
   394  		evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas))
   395  	}
   396  	return gas, nil
   397  }
   398  
   399  func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   400  	gas, err := memoryGasCost(mem, memorySize)
   401  	if err != nil {
   402  		return 0, err
   403  	}
   404  	var overflow bool
   405  	if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
   406  		return 0, errGasUintOverflow
   407  	}
   408  
   409  	cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
   410  	if err != nil {
   411  		return 0, err
   412  	}
   413  	// Replace the stack item with the new gas calculation. This means that
   414  	// either the original item is left on the stack or the item is replaced by:
   415  	// (availableGas - gas) * 63 / 64
   416  	// We replace the stack item so that it's available when the opCall instruction is
   417  	// called.
   418  	stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
   419  
   420  	if gas, overflow = math.SafeAdd(gas, cg); overflow {
   421  		return 0, errGasUintOverflow
   422  	}
   423  	return gas, nil
   424  }
   425  
   426  func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   427  	return GasFastestStep, nil
   428  }
   429  
   430  func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   431  	return GasFastestStep, nil
   432  }
   433  
   434  func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   435  	return GasFastestStep, nil
   436  }