github.com/etherite/go-etherite@v0.0.0-20171015192807-5f4dd87b2f6e/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/etherite/go-etherite/common"
    23  	"github.com/etherite/go-etherite/common/math"
    24  	"github.com/etherite/go-etherite/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  	cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
   346  	if err != nil {
   347  		return 0, err
   348  	}
   349  	// Replace the stack item with the new gas calculation. This means that
   350  	// either the original item is left on the stack or the item is replaced by:
   351  	// (availableGas - gas) * 63 / 64
   352  	// We replace the stack item so that it's available when the opCall instruction is
   353  	// called. This information is otherwise lost due to the dependency on *current*
   354  	// available gas.
   355  	stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
   356  
   357  	if gas, overflow = math.SafeAdd(gas, cg); overflow {
   358  		return 0, errGasUintOverflow
   359  	}
   360  	return gas, nil
   361  }
   362  
   363  func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   364  	gas := gt.Calls
   365  	if stack.Back(2).Sign() != 0 {
   366  		gas += params.CallValueTransferGas
   367  	}
   368  	memoryGas, err := memoryGasCost(mem, memorySize)
   369  	if err != nil {
   370  		return 0, err
   371  	}
   372  	var overflow bool
   373  	if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
   374  		return 0, errGasUintOverflow
   375  	}
   376  
   377  	cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
   378  	if err != nil {
   379  		return 0, err
   380  	}
   381  	// Replace the stack item with the new gas calculation. This means that
   382  	// either the original item is left on the stack or the item is replaced by:
   383  	// (availableGas - gas) * 63 / 64
   384  	// We replace the stack item so that it's available when the opCall instruction is
   385  	// called. This information is otherwise lost due to the dependency on *current*
   386  	// available gas.
   387  	stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
   388  
   389  	if gas, overflow = math.SafeAdd(gas, cg); overflow {
   390  		return 0, errGasUintOverflow
   391  	}
   392  	return gas, nil
   393  }
   394  
   395  func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   396  	return memoryGasCost(mem, memorySize)
   397  }
   398  
   399  func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   400  	return memoryGasCost(mem, memorySize)
   401  }
   402  
   403  func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   404  	var gas uint64
   405  	// EIP150 homestead gas reprice fork:
   406  	if evm.ChainConfig().IsEIP150(evm.BlockNumber) {
   407  		gas = gt.Suicide
   408  		var (
   409  			address = common.BigToAddress(stack.Back(0))
   410  			eip158  = evm.ChainConfig().IsEIP158(evm.BlockNumber)
   411  		)
   412  
   413  		if eip158 {
   414  			// if empty and transfers value
   415  			if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
   416  				gas += gt.CreateBySuicide
   417  			}
   418  		} else if !evm.StateDB.Exist(address) {
   419  			gas += gt.CreateBySuicide
   420  		}
   421  	}
   422  
   423  	if !evm.StateDB.HasSuicided(contract.Address()) {
   424  		evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas))
   425  	}
   426  	return gas, nil
   427  }
   428  
   429  func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   430  	gas, err := memoryGasCost(mem, memorySize)
   431  	if err != nil {
   432  		return 0, err
   433  	}
   434  	var overflow bool
   435  	if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
   436  		return 0, errGasUintOverflow
   437  	}
   438  
   439  	cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
   440  	if err != nil {
   441  		return 0, err
   442  	}
   443  	// Replace the stack item with the new gas calculation. This means that
   444  	// either the original item is left on the stack or the item is replaced by:
   445  	// (availableGas - gas) * 63 / 64
   446  	// We replace the stack item so that it's available when the opCall instruction is
   447  	// called.
   448  	stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
   449  
   450  	if gas, overflow = math.SafeAdd(gas, cg); overflow {
   451  		return 0, errGasUintOverflow
   452  	}
   453  	return gas, nil
   454  }
   455  
   456  func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   457  	gas, err := memoryGasCost(mem, memorySize)
   458  	if err != nil {
   459  		return 0, err
   460  	}
   461  	var overflow bool
   462  	if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow {
   463  		return 0, errGasUintOverflow
   464  	}
   465  
   466  	cg, err := callGas(gt, contract.Gas, gas, stack.Back(0))
   467  	if err != nil {
   468  		return 0, err
   469  	}
   470  	// Replace the stack item with the new gas calculation. This means that
   471  	// either the original item is left on the stack or the item is replaced by:
   472  	// (availableGas - gas) * 63 / 64
   473  	// We replace the stack item so that it's available when the opCall instruction is
   474  	// called.
   475  	stack.data[stack.len()-1] = new(big.Int).SetUint64(cg)
   476  
   477  	if gas, overflow = math.SafeAdd(gas, cg); overflow {
   478  		return 0, errGasUintOverflow
   479  	}
   480  	return gas, nil
   481  }
   482  
   483  func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   484  	return GasFastestStep, nil
   485  }
   486  
   487  func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   488  	return GasFastestStep, nil
   489  }
   490  
   491  func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   492  	return GasFastestStep, nil
   493  }