github.com/devfans/go-ethereum@v1.5.10-0.20170326212234-7419d0c38291/core/vm/gas_table.go (about)

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