github.com/neatlab/neatio@v1.7.3-0.20220425043230-d903e92fcc75/chain/core/vm/gas_table.go (about)

     1  package vm
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/neatlab/neatio/params"
     7  	"github.com/neatlab/neatio/utilities/common"
     8  	"github.com/neatlab/neatio/utilities/common/math"
     9  )
    10  
    11  func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) {
    12  	if newMemSize == 0 {
    13  		return 0, nil
    14  	}
    15  
    16  	if newMemSize > 0x1FFFFFFFE0 {
    17  		return 0, errGasUintOverflow
    18  	}
    19  	newMemSizeWords := toWordSize(newMemSize)
    20  	newMemSize = newMemSizeWords * 32
    21  
    22  	if newMemSize > uint64(mem.Len()) {
    23  		square := newMemSizeWords * newMemSizeWords
    24  		linCoef := newMemSizeWords * params.MemoryGas
    25  		quadCoef := square / params.QuadCoeffDiv
    26  		newTotalFee := linCoef + quadCoef
    27  
    28  		fee := newTotalFee - mem.lastGasCost
    29  		mem.lastGasCost = newTotalFee
    30  
    31  		return fee, nil
    32  	}
    33  	return 0, nil
    34  }
    35  
    36  func memoryCopierGas(stackpos int) gasFunc {
    37  	return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
    38  
    39  		gas, err := memoryGasCost(mem, memorySize)
    40  		if err != nil {
    41  			return 0, err
    42  		}
    43  
    44  		words, overflow := bigUint64(stack.Back(stackpos))
    45  		if overflow {
    46  			return 0, errGasUintOverflow
    47  		}
    48  
    49  		if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow {
    50  			return 0, errGasUintOverflow
    51  		}
    52  
    53  		if gas, overflow = math.SafeAdd(gas, words); overflow {
    54  			return 0, errGasUintOverflow
    55  		}
    56  		return gas, nil
    57  	}
    58  }
    59  
    60  var (
    61  	gasCallDataCopy   = memoryCopierGas(2)
    62  	gasCodeCopy       = memoryCopierGas(2)
    63  	gasExtCodeCopy    = memoryCopierGas(3)
    64  	gasReturnDataCopy = memoryCopierGas(2)
    65  )
    66  
    67  func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
    68  	var (
    69  		y, x    = stack.Back(1), stack.Back(0)
    70  		current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
    71  	)
    72  
    73  	if evm.chainRules.IsPetersburg || !evm.chainRules.IsConstantinople {
    74  
    75  		switch {
    76  		case current == (common.Hash{}) && y.Sign() != 0:
    77  			return params.SstoreSetGas, nil
    78  		case current != (common.Hash{}) && y.Sign() == 0:
    79  			evm.StateDB.AddRefund(params.SstoreRefundGas)
    80  			return params.SstoreClearGas, nil
    81  		default:
    82  			return params.SstoreResetGas, nil
    83  		}
    84  	}
    85  
    86  	value := common.BigToHash(y)
    87  	if current == value {
    88  		return params.NetSstoreNoopGas, nil
    89  	}
    90  	original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
    91  	if original == current {
    92  		if original == (common.Hash{}) {
    93  			return params.NetSstoreInitGas, nil
    94  		}
    95  		if value == (common.Hash{}) {
    96  			evm.StateDB.AddRefund(params.NetSstoreClearRefund)
    97  		}
    98  		return params.NetSstoreCleanGas, nil
    99  	}
   100  	if original != (common.Hash{}) {
   101  		if current == (common.Hash{}) {
   102  			evm.StateDB.SubRefund(params.NetSstoreClearRefund)
   103  		} else if value == (common.Hash{}) {
   104  			evm.StateDB.AddRefund(params.NetSstoreClearRefund)
   105  		}
   106  	}
   107  	if original == value {
   108  		if original == (common.Hash{}) {
   109  			evm.StateDB.AddRefund(params.NetSstoreResetClearRefund)
   110  		} else {
   111  			evm.StateDB.AddRefund(params.NetSstoreResetRefund)
   112  		}
   113  	}
   114  	return params.NetSstoreDirtyGas, nil
   115  }
   116  
   117  func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   118  
   119  	if contract.Gas <= params.SstoreSentryGasEIP2200 {
   120  		return 0, errors.New("not enough gas for reentrancy sentry")
   121  	}
   122  
   123  	var (
   124  		y, x    = stack.Back(1), stack.Back(0)
   125  		current = evm.StateDB.GetState(contract.Address(), common.BigToHash(x))
   126  	)
   127  	value := common.BigToHash(y)
   128  
   129  	if current == value {
   130  		return params.SstoreNoopGasEIP2200, nil
   131  	}
   132  	original := evm.StateDB.GetCommittedState(contract.Address(), common.BigToHash(x))
   133  	if original == current {
   134  		if original == (common.Hash{}) {
   135  			return params.SstoreInitGasEIP2200, nil
   136  		}
   137  		if value == (common.Hash{}) {
   138  			evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200)
   139  		}
   140  		return params.SstoreCleanGasEIP2200, nil
   141  	}
   142  	if original != (common.Hash{}) {
   143  		if current == (common.Hash{}) {
   144  			evm.StateDB.SubRefund(params.SstoreClearRefundEIP2200)
   145  		} else if value == (common.Hash{}) {
   146  			evm.StateDB.AddRefund(params.SstoreClearRefundEIP2200)
   147  		}
   148  	}
   149  	if original == value {
   150  		if original == (common.Hash{}) {
   151  			evm.StateDB.AddRefund(params.SstoreInitRefundEIP2200)
   152  		} else {
   153  			evm.StateDB.AddRefund(params.SstoreCleanRefundEIP2200)
   154  		}
   155  	}
   156  	return params.SstoreDirtyGasEIP2200, nil
   157  }
   158  
   159  func makeGasLog(n uint64) gasFunc {
   160  	return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   161  		requestedSize, overflow := bigUint64(stack.Back(1))
   162  		if overflow {
   163  			return 0, errGasUintOverflow
   164  		}
   165  
   166  		gas, err := memoryGasCost(mem, memorySize)
   167  		if err != nil {
   168  			return 0, err
   169  		}
   170  
   171  		if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow {
   172  			return 0, errGasUintOverflow
   173  		}
   174  		if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow {
   175  			return 0, errGasUintOverflow
   176  		}
   177  
   178  		var memorySizeGas uint64
   179  		if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow {
   180  			return 0, errGasUintOverflow
   181  		}
   182  		if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow {
   183  			return 0, errGasUintOverflow
   184  		}
   185  		return gas, nil
   186  	}
   187  }
   188  
   189  func gasSha3(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  	wordGas, overflow := bigUint64(stack.Back(1))
   195  	if overflow {
   196  		return 0, errGasUintOverflow
   197  	}
   198  	if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
   199  		return 0, errGasUintOverflow
   200  	}
   201  	if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
   202  		return 0, errGasUintOverflow
   203  	}
   204  	return gas, nil
   205  }
   206  
   207  func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   208  	return memoryGasCost(mem, memorySize)
   209  }
   210  
   211  var (
   212  	gasReturn  = pureMemoryGascost
   213  	gasRevert  = pureMemoryGascost
   214  	gasMLoad   = pureMemoryGascost
   215  	gasMStore8 = pureMemoryGascost
   216  	gasMStore  = pureMemoryGascost
   217  	gasCreate  = pureMemoryGascost
   218  )
   219  
   220  func gasCreate2(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  	wordGas, overflow := bigUint64(stack.Back(2))
   226  	if overflow {
   227  		return 0, errGasUintOverflow
   228  	}
   229  	if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow {
   230  		return 0, errGasUintOverflow
   231  	}
   232  	if gas, overflow = math.SafeAdd(gas, wordGas); overflow {
   233  		return 0, errGasUintOverflow
   234  	}
   235  	return gas, nil
   236  }
   237  
   238  func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   239  	expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
   240  
   241  	var (
   242  		gas      = expByteLen * params.ExpByteFrontier
   243  		overflow bool
   244  	)
   245  	if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow {
   246  		return 0, errGasUintOverflow
   247  	}
   248  	return gas, nil
   249  }
   250  
   251  func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   252  	expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8)
   253  
   254  	var (
   255  		gas      = expByteLen * params.ExpByteEIP158
   256  		overflow bool
   257  	)
   258  	if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow {
   259  		return 0, errGasUintOverflow
   260  	}
   261  	return gas, nil
   262  }
   263  
   264  func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   265  	var (
   266  		gas            uint64
   267  		transfersValue = stack.Back(2).Sign() != 0
   268  		address        = common.BigToAddress(stack.Back(1))
   269  	)
   270  	if evm.chainRules.IsEIP158 {
   271  		if transfersValue && evm.StateDB.Empty(address) {
   272  			gas += params.CallNewAccountGas
   273  		}
   274  	} else if !evm.StateDB.Exist(address) {
   275  		gas += params.CallNewAccountGas
   276  	}
   277  	if transfersValue {
   278  		gas += params.CallValueTransferGas
   279  	}
   280  	memoryGas, err := memoryGasCost(mem, memorySize)
   281  	if err != nil {
   282  		return 0, err
   283  	}
   284  	var overflow bool
   285  	if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
   286  		return 0, errGasUintOverflow
   287  	}
   288  
   289  	evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
   290  	if err != nil {
   291  		return 0, err
   292  	}
   293  	if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
   294  		return 0, errGasUintOverflow
   295  	}
   296  	return gas, nil
   297  }
   298  
   299  func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   300  	memoryGas, err := memoryGasCost(mem, memorySize)
   301  	if err != nil {
   302  		return 0, err
   303  	}
   304  	var (
   305  		gas      uint64
   306  		overflow bool
   307  	)
   308  	if stack.Back(2).Sign() != 0 {
   309  		gas += params.CallValueTransferGas
   310  	}
   311  	if gas, overflow = math.SafeAdd(gas, memoryGas); overflow {
   312  		return 0, errGasUintOverflow
   313  	}
   314  	evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
   315  	if err != nil {
   316  		return 0, err
   317  	}
   318  	if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
   319  		return 0, errGasUintOverflow
   320  	}
   321  	return gas, nil
   322  }
   323  
   324  func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   325  	gas, err := memoryGasCost(mem, memorySize)
   326  	if err != nil {
   327  		return 0, err
   328  	}
   329  	evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
   330  	if err != nil {
   331  		return 0, err
   332  	}
   333  	var overflow bool
   334  	if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
   335  		return 0, errGasUintOverflow
   336  	}
   337  	return gas, nil
   338  }
   339  
   340  func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   341  	gas, err := memoryGasCost(mem, memorySize)
   342  	if err != nil {
   343  		return 0, err
   344  	}
   345  	evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0))
   346  	if err != nil {
   347  		return 0, err
   348  	}
   349  	var overflow bool
   350  	if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow {
   351  		return 0, errGasUintOverflow
   352  	}
   353  	return gas, nil
   354  }
   355  
   356  func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
   357  	var gas uint64
   358  
   359  	if evm.chainRules.IsEIP150 {
   360  		gas = params.SelfdestructGasEIP150
   361  		var address = common.BigToAddress(stack.Back(0))
   362  
   363  		if evm.chainRules.IsEIP158 {
   364  
   365  			if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 {
   366  				gas += params.CreateBySelfdestructGas
   367  			}
   368  		} else if !evm.StateDB.Exist(address) {
   369  			gas += params.CreateBySelfdestructGas
   370  		}
   371  	}
   372  
   373  	if !evm.StateDB.HasSuicided(contract.Address()) {
   374  		evm.StateDB.AddRefund(params.SelfdestructRefundGas)
   375  	}
   376  	return gas, nil
   377  }