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 }