github.com/halybang/go-ethereum@v1.0.5-0.20180325041310-3b262bc1367c/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/wanchain/go-wanchain/common" 23 "github.com/wanchain/go-wanchain/common/math" 24 "github.com/wanchain/go-wanchain/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 y, x = stack.Back(1), stack.Back(0) 123 val = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) 124 ) 125 // This checks for 3 scenario's and calculates gas accordingly 126 // 1. From a zero-value address to a non-zero value (NEW VALUE) 127 // 2. From a non-zero value address to a zero-value address (DELETE) 128 // 3. From a non-zero to a non-zero (CHANGE) 129 if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { 130 // 0 => non 0 131 return params.SstoreSetGas, nil 132 } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { 133 evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SstoreRefundGas)) 134 135 return params.SstoreClearGas, nil 136 } else { 137 // non 0 => non 0 (or 0 => 0) 138 return params.SstoreResetGas, nil 139 } 140 } 141 142 func makeGasLog(n uint64) gasFunc { 143 return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 144 requestedSize, overflow := bigUint64(stack.Back(1)) 145 if overflow { 146 return 0, errGasUintOverflow 147 } 148 149 gas, err := memoryGasCost(mem, memorySize) 150 if err != nil { 151 return 0, err 152 } 153 154 if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow { 155 return 0, errGasUintOverflow 156 } 157 if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow { 158 return 0, errGasUintOverflow 159 } 160 161 var memorySizeGas uint64 162 if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow { 163 return 0, errGasUintOverflow 164 } 165 if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow { 166 return 0, errGasUintOverflow 167 } 168 return gas, nil 169 } 170 } 171 172 func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 173 var overflow bool 174 gas, err := memoryGasCost(mem, memorySize) 175 if err != nil { 176 return 0, err 177 } 178 179 if gas, overflow = math.SafeAdd(gas, params.Sha3Gas); overflow { 180 return 0, errGasUintOverflow 181 } 182 183 wordGas, overflow := bigUint64(stack.Back(1)) 184 if overflow { 185 return 0, errGasUintOverflow 186 } 187 if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { 188 return 0, errGasUintOverflow 189 } 190 if gas, overflow = math.SafeAdd(gas, wordGas); overflow { 191 return 0, errGasUintOverflow 192 } 193 return gas, nil 194 } 195 196 func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 197 gas, err := memoryGasCost(mem, memorySize) 198 if err != nil { 199 return 0, err 200 } 201 202 var overflow bool 203 if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { 204 return 0, errGasUintOverflow 205 } 206 207 wordGas, overflow := bigUint64(stack.Back(2)) 208 if overflow { 209 return 0, errGasUintOverflow 210 } 211 if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow { 212 return 0, errGasUintOverflow 213 } 214 if gas, overflow = math.SafeAdd(gas, wordGas); overflow { 215 return 0, errGasUintOverflow 216 } 217 return gas, nil 218 } 219 220 func gasExtCodeCopy(gt params.GasTable, 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 226 var overflow bool 227 if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow { 228 return 0, errGasUintOverflow 229 } 230 231 wordGas, overflow := bigUint64(stack.Back(3)) 232 if overflow { 233 return 0, errGasUintOverflow 234 } 235 236 if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow { 237 return 0, errGasUintOverflow 238 } 239 240 if gas, overflow = math.SafeAdd(gas, wordGas); overflow { 241 return 0, errGasUintOverflow 242 } 243 return gas, nil 244 } 245 246 func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 247 var overflow bool 248 gas, err := memoryGasCost(mem, memorySize) 249 if err != nil { 250 return 0, errGasUintOverflow 251 } 252 if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { 253 return 0, errGasUintOverflow 254 } 255 return gas, nil 256 } 257 258 func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 259 var overflow bool 260 gas, err := memoryGasCost(mem, memorySize) 261 if err != nil { 262 return 0, errGasUintOverflow 263 } 264 if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { 265 return 0, errGasUintOverflow 266 } 267 return gas, nil 268 } 269 270 func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 271 var overflow bool 272 gas, err := memoryGasCost(mem, memorySize) 273 if err != nil { 274 return 0, errGasUintOverflow 275 } 276 if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { 277 return 0, errGasUintOverflow 278 } 279 return gas, nil 280 } 281 282 func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 283 var overflow bool 284 gas, err := memoryGasCost(mem, memorySize) 285 if err != nil { 286 return 0, err 287 } 288 if gas, overflow = math.SafeAdd(gas, params.CreateGas); overflow { 289 return 0, errGasUintOverflow 290 } 291 return gas, nil 292 } 293 294 func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 295 return gt.Balance, nil 296 } 297 298 func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 299 return gt.ExtcodeSize, nil 300 } 301 302 func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 303 return gt.SLoad, nil 304 } 305 306 func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 307 expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) 308 309 var ( 310 gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas 311 overflow bool 312 ) 313 if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow { 314 return 0, errGasUintOverflow 315 } 316 return gas, nil 317 } 318 319 func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 320 var ( 321 gas = gt.Calls 322 transfersValue = stack.Back(2).Sign() != 0 323 address = common.BigToAddress(stack.Back(1)) 324 325 eip158 = true//evm.ChainConfig().IsEIP158(evm.BlockNumber) 326 ) 327 328 if eip158 { 329 if transfersValue && evm.StateDB.Empty(address) { 330 gas += params.CallNewAccountGas 331 } 332 } else if !evm.StateDB.Exist(address) { 333 gas += params.CallNewAccountGas 334 } 335 if transfersValue { 336 gas += params.CallValueTransferGas 337 } 338 memoryGas, err := memoryGasCost(mem, memorySize) 339 if err != nil { 340 return 0, err 341 } 342 var overflow bool 343 if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { 344 return 0, errGasUintOverflow 345 } 346 347 cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) 348 if err != nil { 349 return 0, err 350 } 351 // Replace the stack item with the new gas calculation. This means that 352 // either the original item is left on the stack or the item is replaced by: 353 // (availableGas - gas) * 63 / 64 354 // We replace the stack item so that it's available when the opCall instruction is 355 // called. This information is otherwise lost due to the dependency on *current* 356 // available gas. 357 stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) 358 359 if gas, overflow = math.SafeAdd(gas, cg); overflow { 360 return 0, errGasUintOverflow 361 } 362 return gas, nil 363 } 364 365 func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 366 gas := gt.Calls 367 if stack.Back(2).Sign() != 0 { 368 gas += params.CallValueTransferGas 369 } 370 memoryGas, err := memoryGasCost(mem, memorySize) 371 if err != nil { 372 return 0, err 373 } 374 var overflow bool 375 if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { 376 return 0, errGasUintOverflow 377 } 378 379 cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) 380 if err != nil { 381 return 0, err 382 } 383 // Replace the stack item with the new gas calculation. This means that 384 // either the original item is left on the stack or the item is replaced by: 385 // (availableGas - gas) * 63 / 64 386 // We replace the stack item so that it's available when the opCall instruction is 387 // called. This information is otherwise lost due to the dependency on *current* 388 // available gas. 389 stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) 390 391 if gas, overflow = math.SafeAdd(gas, cg); overflow { 392 return 0, errGasUintOverflow 393 } 394 return gas, nil 395 } 396 397 func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 398 return memoryGasCost(mem, memorySize) 399 } 400 401 func gasRevert(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 402 return memoryGasCost(mem, memorySize) 403 } 404 405 func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 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 = true//evm.ChainConfig().IsEIP158(evm.BlockNumber) 413 ) 414 415 if eip158 { 416 // if empty and transfers value 417 if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { 418 gas += gt.CreateBySuicide 419 } 420 } else if !evm.StateDB.Exist(address) { 421 gas += gt.CreateBySuicide 422 } 423 //} 424 425 if !evm.StateDB.HasSuicided(contract.Address()) { 426 evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas)) 427 } 428 return gas, nil 429 } 430 431 func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 432 gas, err := memoryGasCost(mem, memorySize) 433 if err != nil { 434 return 0, err 435 } 436 var overflow bool 437 if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow { 438 return 0, errGasUintOverflow 439 } 440 441 cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) 442 if err != nil { 443 return 0, err 444 } 445 // Replace the stack item with the new gas calculation. This means that 446 // either the original item is left on the stack or the item is replaced by: 447 // (availableGas - gas) * 63 / 64 448 // We replace the stack item so that it's available when the opCall instruction is 449 // called. 450 stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) 451 452 if gas, overflow = math.SafeAdd(gas, cg); overflow { 453 return 0, errGasUintOverflow 454 } 455 return gas, nil 456 } 457 458 func gasStaticCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 459 gas, err := memoryGasCost(mem, memorySize) 460 if err != nil { 461 return 0, err 462 } 463 var overflow bool 464 if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow { 465 return 0, errGasUintOverflow 466 } 467 468 cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) 469 if err != nil { 470 return 0, err 471 } 472 // Replace the stack item with the new gas calculation. This means that 473 // either the original item is left on the stack or the item is replaced by: 474 // (availableGas - gas) * 63 / 64 475 // We replace the stack item so that it's available when the opCall instruction is 476 // called. 477 stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) 478 479 if gas, overflow = math.SafeAdd(gas, cg); overflow { 480 return 0, errGasUintOverflow 481 } 482 return gas, nil 483 } 484 485 func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 486 return GasFastestStep, nil 487 } 488 489 func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 490 return GasFastestStep, nil 491 } 492 493 func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 494 return GasFastestStep, nil 495 }