github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/core/vm/gas_table.go (about)

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