gitlab.com/flarenetwork/coreth@v0.1.1/core/vm/gas_table.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2017 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package vm 28 29 import ( 30 "errors" 31 32 "github.com/ethereum/go-ethereum/common" 33 "github.com/ethereum/go-ethereum/common/math" 34 "gitlab.com/flarenetwork/coreth/params" 35 ) 36 37 // memoryGasCost calculates the quadratic gas for memory expansion. It does so 38 // only for the memory region that is expanded, not the total memory. 39 func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { 40 if newMemSize == 0 { 41 return 0, nil 42 } 43 // The maximum that will fit in a uint64 is max_word_count - 1. Anything above 44 // that will result in an overflow. Additionally, a newMemSize which results in 45 // a newMemSizeWords larger than 0xFFFFFFFF will cause the square operation to 46 // overflow. The constant 0x1FFFFFFFE0 is the highest number that can be used 47 // without overflowing the gas calculation. 48 if newMemSize > 0x1FFFFFFFE0 { 49 return 0, ErrGasUintOverflow 50 } 51 newMemSizeWords := toWordSize(newMemSize) 52 newMemSize = newMemSizeWords * 32 53 54 if newMemSize > uint64(mem.Len()) { 55 square := newMemSizeWords * newMemSizeWords 56 linCoef := newMemSizeWords * params.MemoryGas 57 quadCoef := square / params.QuadCoeffDiv 58 newTotalFee := linCoef + quadCoef 59 60 fee := newTotalFee - mem.lastGasCost 61 mem.lastGasCost = newTotalFee 62 63 return fee, nil 64 } 65 return 0, nil 66 } 67 68 // memoryCopierGas creates the gas functions for the following opcodes, and takes 69 // the stack position of the operand which determines the size of the data to copy 70 // as argument: 71 // CALLDATACOPY (stack position 2) 72 // CODECOPY (stack position 2) 73 // EXTCODECOPY (stack poition 3) 74 // RETURNDATACOPY (stack position 2) 75 func memoryCopierGas(stackpos int) gasFunc { 76 return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 77 // Gas for expanding the memory 78 gas, err := memoryGasCost(mem, memorySize) 79 if err != nil { 80 return 0, err 81 } 82 // And gas for copying data, charged per word at param.CopyGas 83 words, overflow := stack.Back(stackpos).Uint64WithOverflow() 84 if overflow { 85 return 0, ErrGasUintOverflow 86 } 87 88 if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { 89 return 0, ErrGasUintOverflow 90 } 91 92 if gas, overflow = math.SafeAdd(gas, words); overflow { 93 return 0, ErrGasUintOverflow 94 } 95 return gas, nil 96 } 97 } 98 99 var ( 100 gasCallDataCopy = memoryCopierGas(2) 101 gasCodeCopy = memoryCopierGas(2) 102 gasExtCodeCopy = memoryCopierGas(3) 103 gasReturnDataCopy = memoryCopierGas(2) 104 ) 105 106 func gasSStore(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 107 var ( 108 y, x = stack.Back(1), stack.Back(0) 109 current = evm.StateDB.GetState(contract.Address(), x.Bytes32()) 110 ) 111 // The legacy gas metering only takes into consideration the current state 112 // Legacy rules should be applied if we are in Petersburg (removal of EIP-1283) 113 // OR Constantinople is not active 114 if evm.chainRules.IsPetersburg || !evm.chainRules.IsConstantinople { 115 // This checks for 3 scenario's and calculates gas accordingly: 116 // 117 // 1. From a zero-value address to a non-zero value (NEW VALUE) 118 // 2. From a non-zero value address to a zero-value address (DELETE) 119 // 3. From a non-zero to a non-zero (CHANGE) 120 switch { 121 case current == (common.Hash{}) && y.Sign() != 0: // 0 => non 0 122 return params.SstoreSetGas, nil 123 case current != (common.Hash{}) && y.Sign() == 0: // non 0 => 0 124 evm.StateDB.AddRefund(params.SstoreRefundGas) 125 return params.SstoreClearGas, nil 126 default: // non 0 => non 0 (or 0 => 0) 127 return params.SstoreResetGas, nil 128 } 129 } 130 // The new gas metering is based on net gas costs (EIP-1283): 131 // 132 // 1. If current value equals new value (this is a no-op), 200 gas is deducted. 133 // 2. If current value does not equal new value 134 // 2.1. If original value equals current value (this storage slot has not been changed by the current execution context) 135 // 2.1.1. If original value is 0, 20000 gas is deducted. 136 // 2.1.2. Otherwise, 5000 gas is deducted. If new value is 0, add 15000 gas to refund counter. 137 // 2.2. If original value does not equal current value (this storage slot is dirty), 200 gas is deducted. Apply both of the following clauses. 138 // 2.2.1. If original value is not 0 139 // 2.2.1.1. If current value is 0 (also means that new value is not 0), remove 15000 gas from refund counter. We can prove that refund counter will never go below 0. 140 // 2.2.1.2. If new value is 0 (also means that current value is not 0), add 15000 gas to refund counter. 141 // 2.2.2. If original value equals new value (this storage slot is reset) 142 // 2.2.2.1. If original value is 0, add 19800 gas to refund counter. 143 // 2.2.2.2. Otherwise, add 4800 gas to refund counter. 144 value := common.Hash(y.Bytes32()) 145 if current == value { // noop (1) 146 return params.NetSstoreNoopGas, nil 147 } 148 original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32()) 149 if original == current { 150 if original == (common.Hash{}) { // create slot (2.1.1) 151 return params.NetSstoreInitGas, nil 152 } 153 if value == (common.Hash{}) { // delete slot (2.1.2b) 154 evm.StateDB.AddRefund(params.NetSstoreClearRefund) 155 } 156 return params.NetSstoreCleanGas, nil // write existing slot (2.1.2) 157 } 158 if original != (common.Hash{}) { 159 if current == (common.Hash{}) { // recreate slot (2.2.1.1) 160 evm.StateDB.SubRefund(params.NetSstoreClearRefund) 161 } else if value == (common.Hash{}) { // delete slot (2.2.1.2) 162 evm.StateDB.AddRefund(params.NetSstoreClearRefund) 163 } 164 } 165 if original == value { 166 if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) 167 evm.StateDB.AddRefund(params.NetSstoreResetClearRefund) 168 } else { // reset to original existing slot (2.2.2.2) 169 evm.StateDB.AddRefund(params.NetSstoreResetRefund) 170 } 171 } 172 return params.NetSstoreDirtyGas, nil 173 } 174 175 // 0. If *gasleft* is less than or equal to 2300, fail the current call. 176 // 1. If current value equals new value (this is a no-op), SLOAD_GAS is deducted. 177 // 2. If current value does not equal new value: 178 // 2.1. If original value equals current value (this storage slot has not been changed by the current execution context): 179 // 2.1.1. If original value is 0, SSTORE_SET_GAS (20K) gas is deducted. 180 // 2.1.2. Otherwise, SSTORE_RESET_GAS gas is deducted. If new value is 0, add SSTORE_CLEARS_SCHEDULE to refund counter. 181 // 2.2. If original value does not equal current value (this storage slot is dirty), SLOAD_GAS gas is deducted. Apply both of the following clauses: 182 // 2.2.1. If original value is not 0: 183 // 2.2.1.1. If current value is 0 (also means that new value is not 0), subtract SSTORE_CLEARS_SCHEDULE gas from refund counter. 184 // 2.2.1.2. If new value is 0 (also means that current value is not 0), add SSTORE_CLEARS_SCHEDULE gas to refund counter. 185 // 2.2.2. If original value equals new value (this storage slot is reset): 186 // 2.2.2.1. If original value is 0, add SSTORE_SET_GAS - SLOAD_GAS to refund counter. 187 // 2.2.2.2. Otherwise, add SSTORE_RESET_GAS - SLOAD_GAS gas to refund counter. 188 func gasSStoreEIP2200(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 189 // If we fail the minimum gas availability invariant, fail (0) 190 if contract.Gas <= params.SstoreSentryGasEIP2200 { 191 return 0, errors.New("not enough gas for reentrancy sentry") 192 } 193 // Gas sentry honoured, do the actual gas calculation based on the stored value 194 var ( 195 y, x = stack.Back(1), stack.Back(0) 196 current = evm.StateDB.GetState(contract.Address(), x.Bytes32()) 197 ) 198 value := common.Hash(y.Bytes32()) 199 200 if current == value { // noop (1) 201 return params.SloadGasEIP2200, nil 202 } 203 original := evm.StateDB.GetCommittedState(contract.Address(), x.Bytes32()) 204 if original == current { 205 if original == (common.Hash{}) { // create slot (2.1.1) 206 return params.SstoreSetGasEIP2200, nil 207 } 208 if value == (common.Hash{}) { // delete slot (2.1.2b) 209 evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200) 210 } 211 return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2) 212 } 213 if original != (common.Hash{}) { 214 if current == (common.Hash{}) { // recreate slot (2.2.1.1) 215 evm.StateDB.SubRefund(params.SstoreClearsScheduleRefundEIP2200) 216 } else if value == (common.Hash{}) { // delete slot (2.2.1.2) 217 evm.StateDB.AddRefund(params.SstoreClearsScheduleRefundEIP2200) 218 } 219 } 220 if original == value { 221 if original == (common.Hash{}) { // reset to original inexistent slot (2.2.2.1) 222 evm.StateDB.AddRefund(params.SstoreSetGasEIP2200 - params.SloadGasEIP2200) 223 } else { // reset to original existing slot (2.2.2.2) 224 evm.StateDB.AddRefund(params.SstoreResetGasEIP2200 - params.SloadGasEIP2200) 225 } 226 } 227 return params.SloadGasEIP2200, nil // dirty update (2.2) 228 } 229 230 // gasSStoreAP1 simplifies the dynamic gas cost of SSTORE by removing all refund logic 231 // 232 // 0. If *gasleft* is less than or equal to 2300, fail the current call. 233 // 1. If current value equals new value (this is a no-op), SLOAD_GAS is deducted. 234 // 2. If current value does not equal new value: 235 // 2.1. If original value equals current value (this storage slot has not been changed by the current execution context): 236 // 2.1.1. If original value is 0, SSTORE_SET_GAS (20K) gas is deducted. 237 // 2.1.2. Otherwise, SSTORE_RESET_GAS gas is deducted. If new value is 0, add SSTORE_CLEARS_SCHEDULE to refund counter. 238 // 2.2. If original value does not equal current value (this storage slot is dirty), SLOAD_GAS gas is deducted. Apply both of the following clauses: 239 func gasSStoreAP1(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 240 // If we fail the minimum gas availability invariant, fail (0) 241 if contract.Gas <= params.SstoreSentryGasEIP2200 { 242 return 0, errors.New("not enough gas for reentrancy sentry") 243 } 244 // Gas sentry honoured, do the actual gas calculation based on the stored value 245 var ( 246 y, x = stack.Back(1), stack.Back(0) 247 current = evm.StateDB.GetState(contract.Address(), x.Bytes32()) 248 ) 249 value := common.Hash(y.Bytes32()) 250 251 if current == value { // noop (1) 252 return params.SloadGasEIP2200, nil 253 } 254 original := evm.StateDB.GetCommittedStateAP1(contract.Address(), x.Bytes32()) 255 if original == current { 256 if original == (common.Hash{}) { // create slot (2.1.1) 257 return params.SstoreSetGasEIP2200, nil 258 } 259 return params.SstoreResetGasEIP2200, nil // write existing slot (2.1.2) 260 } 261 262 return params.SloadGasEIP2200, nil // dirty update (2.2) 263 } 264 265 func makeGasLog(n uint64) gasFunc { 266 return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 267 requestedSize, overflow := stack.Back(1).Uint64WithOverflow() 268 if overflow { 269 return 0, ErrGasUintOverflow 270 } 271 272 gas, err := memoryGasCost(mem, memorySize) 273 if err != nil { 274 return 0, err 275 } 276 277 if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow { 278 return 0, ErrGasUintOverflow 279 } 280 if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow { 281 return 0, ErrGasUintOverflow 282 } 283 284 var memorySizeGas uint64 285 if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow { 286 return 0, ErrGasUintOverflow 287 } 288 if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow { 289 return 0, ErrGasUintOverflow 290 } 291 return gas, nil 292 } 293 } 294 295 func gasSha3(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 296 gas, err := memoryGasCost(mem, memorySize) 297 if err != nil { 298 return 0, err 299 } 300 wordGas, overflow := stack.Back(1).Uint64WithOverflow() 301 if overflow { 302 return 0, ErrGasUintOverflow 303 } 304 if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { 305 return 0, ErrGasUintOverflow 306 } 307 if gas, overflow = math.SafeAdd(gas, wordGas); overflow { 308 return 0, ErrGasUintOverflow 309 } 310 return gas, nil 311 } 312 313 // pureMemoryGascost is used by several operations, which aside from their 314 // static cost have a dynamic cost which is solely based on the memory 315 // expansion 316 func pureMemoryGascost(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 317 return memoryGasCost(mem, memorySize) 318 } 319 320 var ( 321 gasReturn = pureMemoryGascost 322 gasRevert = pureMemoryGascost 323 gasMLoad = pureMemoryGascost 324 gasMStore8 = pureMemoryGascost 325 gasMStore = pureMemoryGascost 326 gasCreate = pureMemoryGascost 327 ) 328 329 func gasCreate2(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 330 gas, err := memoryGasCost(mem, memorySize) 331 if err != nil { 332 return 0, err 333 } 334 wordGas, overflow := stack.Back(2).Uint64WithOverflow() 335 if overflow { 336 return 0, ErrGasUintOverflow 337 } 338 if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { 339 return 0, ErrGasUintOverflow 340 } 341 if gas, overflow = math.SafeAdd(gas, wordGas); overflow { 342 return 0, ErrGasUintOverflow 343 } 344 return gas, nil 345 } 346 347 func gasExpFrontier(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 348 expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) 349 350 var ( 351 gas = expByteLen * params.ExpByteFrontier // no overflow check required. Max is 256 * ExpByte gas 352 overflow bool 353 ) 354 if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow { 355 return 0, ErrGasUintOverflow 356 } 357 return gas, nil 358 } 359 360 func gasExpEIP158(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 361 expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) 362 363 var ( 364 gas = expByteLen * params.ExpByteEIP158 // no overflow check required. Max is 256 * ExpByte gas 365 overflow bool 366 ) 367 if gas, overflow = math.SafeAdd(gas, params.ExpGas); overflow { 368 return 0, ErrGasUintOverflow 369 } 370 return gas, nil 371 } 372 373 func gasCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 374 var ( 375 gas uint64 376 transfersValue = !stack.Back(2).IsZero() 377 address = common.Address(stack.Back(1).Bytes20()) 378 ) 379 if evm.chainRules.IsEIP158 { 380 if transfersValue && evm.StateDB.Empty(address) { 381 gas += params.CallNewAccountGas 382 } 383 } else if !evm.StateDB.Exist(address) { 384 gas += params.CallNewAccountGas 385 } 386 if transfersValue { 387 gas += params.CallValueTransferGas 388 } 389 memoryGas, err := memoryGasCost(mem, memorySize) 390 if err != nil { 391 return 0, err 392 } 393 var overflow bool 394 if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { 395 return 0, ErrGasUintOverflow 396 } 397 398 evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) 399 if err != nil { 400 return 0, err 401 } 402 if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { 403 return 0, ErrGasUintOverflow 404 } 405 return gas, nil 406 } 407 408 func gasCallExpertAP1(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 409 var ( 410 gas uint64 411 transfersValue = !stack.Back(2).IsZero() 412 multiCoinTransfersValue = !stack.Back(4).IsZero() 413 address = common.Address(stack.Back(1).Bytes20()) 414 ) 415 if evm.chainRules.IsEIP158 { 416 if (transfersValue || multiCoinTransfersValue) && evm.StateDB.Empty(address) { 417 gas += params.CallNewAccountGas 418 } 419 } else if !evm.StateDB.Exist(address) { 420 gas += params.CallNewAccountGas 421 } 422 if transfersValue { 423 gas += params.CallValueTransferGas 424 } 425 if multiCoinTransfersValue { 426 gas += params.CallValueTransferGas 427 } 428 memoryGas, err := memoryGasCost(mem, memorySize) 429 if err != nil { 430 return 0, err 431 } 432 var overflow bool 433 if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { 434 return 0, ErrGasUintOverflow 435 } 436 437 evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) 438 if err != nil { 439 return 0, err 440 } 441 if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { 442 return 0, ErrGasUintOverflow 443 } 444 return gas, nil 445 } 446 447 func gasCallCode(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 448 memoryGas, err := memoryGasCost(mem, memorySize) 449 if err != nil { 450 return 0, err 451 } 452 var ( 453 gas uint64 454 overflow bool 455 ) 456 if stack.Back(2).Sign() != 0 { 457 gas += params.CallValueTransferGas 458 } 459 if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { 460 return 0, ErrGasUintOverflow 461 } 462 evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) 463 if err != nil { 464 return 0, err 465 } 466 if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { 467 return 0, ErrGasUintOverflow 468 } 469 return gas, nil 470 } 471 472 func gasDelegateCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 473 gas, err := memoryGasCost(mem, memorySize) 474 if err != nil { 475 return 0, err 476 } 477 evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) 478 if err != nil { 479 return 0, err 480 } 481 var overflow bool 482 if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { 483 return 0, ErrGasUintOverflow 484 } 485 return gas, nil 486 } 487 488 func gasStaticCall(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 489 gas, err := memoryGasCost(mem, memorySize) 490 if err != nil { 491 return 0, err 492 } 493 evm.callGasTemp, err = callGas(evm.chainRules.IsEIP150, contract.Gas, gas, stack.Back(0)) 494 if err != nil { 495 return 0, err 496 } 497 var overflow bool 498 if gas, overflow = math.SafeAdd(gas, evm.callGasTemp); overflow { 499 return 0, ErrGasUintOverflow 500 } 501 return gas, nil 502 } 503 504 func gasSelfdestruct(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 505 var gas uint64 506 // EIP150 homestead gas reprice fork: 507 if evm.chainRules.IsEIP150 { 508 gas = params.SelfdestructGasEIP150 509 var address = common.Address(stack.Back(0).Bytes20()) 510 511 if evm.chainRules.IsEIP158 { 512 // if empty and transfers value 513 if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { 514 gas += params.CreateBySelfdestructGas 515 } 516 } else if !evm.StateDB.Exist(address) { 517 gas += params.CreateBySelfdestructGas 518 } 519 } 520 521 if !evm.StateDB.HasSuicided(contract.Address()) { 522 evm.StateDB.AddRefund(params.SelfdestructRefundGas) 523 } 524 return gas, nil 525 } 526 527 func gasSelfdestructAP1(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 528 var gas uint64 529 // EIP150 homestead gas reprice fork: 530 if evm.chainRules.IsEIP150 { 531 gas = params.SelfdestructGasEIP150 532 var address = common.Address(stack.Back(0).Bytes20()) 533 534 if evm.chainRules.IsEIP158 { 535 // if empty and transfers value 536 if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { 537 gas += params.CreateBySelfdestructGas 538 } 539 } else if !evm.StateDB.Exist(address) { 540 gas += params.CreateBySelfdestructGas 541 } 542 } 543 544 return gas, nil 545 }