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 }