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