github.com/devfans/go-ethereum@v1.5.10-0.20170326212234-7419d0c38291/core/vm/gas_table.go (about) 1 package vm 2 3 import ( 4 gmath "math" 5 "math/big" 6 7 "github.com/ethereum/go-ethereum/common" 8 "github.com/ethereum/go-ethereum/common/math" 9 "github.com/ethereum/go-ethereum/params" 10 ) 11 12 // memoryGasCosts calculates the quadratic gas for memory expansion. It does so 13 // only for the memory region that is expanded, not the total memory. 14 func memoryGasCost(mem *Memory, newMemSize uint64) (uint64, error) { 15 // The maximum that will fit in a uint64 is max_word_count - 1 16 // anything above that will result in an overflow. 17 if newMemSize > gmath.MaxUint64-32 { 18 return 0, errGasUintOverflow 19 } 20 21 if newMemSize == 0 { 22 return 0, nil 23 } 24 25 newMemSizeWords := toWordSize(newMemSize) 26 newMemSize = newMemSizeWords * 32 27 28 if newMemSize > uint64(mem.Len()) { 29 square := newMemSizeWords * newMemSizeWords 30 linCoef := newMemSizeWords * params.MemoryGas 31 quadCoef := square / params.QuadCoeffDiv 32 newTotalFee := linCoef + quadCoef 33 34 fee := newTotalFee - mem.lastGasCost 35 mem.lastGasCost = newTotalFee 36 37 return fee, nil 38 } 39 return 0, nil 40 } 41 42 func constGasFunc(gas uint64) gasFunc { 43 return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 44 return gas, nil 45 } 46 } 47 48 func gasCalldataCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 49 gas, err := memoryGasCost(mem, memorySize) 50 if err != nil { 51 return 0, err 52 } 53 54 var overflow bool 55 if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { 56 return 0, errGasUintOverflow 57 } 58 59 words, overflow := bigUint64(stack.Back(2)) 60 if overflow { 61 return 0, errGasUintOverflow 62 } 63 64 if words, overflow = math.SafeMul(toWordSize(words), params.CopyGas); overflow { 65 return 0, errGasUintOverflow 66 } 67 68 if gas, overflow = math.SafeAdd(gas, words); overflow { 69 return 0, errGasUintOverflow 70 } 71 return gas, nil 72 } 73 74 func gasSStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 75 var ( 76 y, x = stack.Back(1), stack.Back(0) 77 val = evm.StateDB.GetState(contract.Address(), common.BigToHash(x)) 78 ) 79 // This checks for 3 scenario's and calculates gas accordingly 80 // 1. From a zero-value address to a non-zero value (NEW VALUE) 81 // 2. From a non-zero value address to a zero-value address (DELETE) 82 // 3. From a non-zero to a non-zero (CHANGE) 83 if common.EmptyHash(val) && !common.EmptyHash(common.BigToHash(y)) { 84 // 0 => non 0 85 return params.SstoreSetGas, nil 86 } else if !common.EmptyHash(val) && common.EmptyHash(common.BigToHash(y)) { 87 evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SstoreRefundGas)) 88 89 return params.SstoreClearGas, nil 90 } else { 91 // non 0 => non 0 (or 0 => 0) 92 return params.SstoreResetGas, nil 93 } 94 } 95 96 func makeGasLog(n uint64) gasFunc { 97 return func(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 98 requestedSize, overflow := bigUint64(stack.Back(1)) 99 if overflow { 100 return 0, errGasUintOverflow 101 } 102 103 gas, err := memoryGasCost(mem, memorySize) 104 if err != nil { 105 return 0, err 106 } 107 108 if gas, overflow = math.SafeAdd(gas, params.LogGas); overflow { 109 return 0, errGasUintOverflow 110 } 111 if gas, overflow = math.SafeAdd(gas, n*params.LogTopicGas); overflow { 112 return 0, errGasUintOverflow 113 } 114 115 var memorySizeGas uint64 116 if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow { 117 return 0, errGasUintOverflow 118 } 119 if gas, overflow = math.SafeAdd(gas, memorySizeGas); overflow { 120 return 0, errGasUintOverflow 121 } 122 return gas, nil 123 } 124 } 125 126 func gasSha3(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 127 var overflow bool 128 gas, err := memoryGasCost(mem, memorySize) 129 if err != nil { 130 return 0, err 131 } 132 133 if gas, overflow = math.SafeAdd(gas, params.Sha3Gas); overflow { 134 return 0, errGasUintOverflow 135 } 136 137 wordGas, overflow := bigUint64(stack.Back(1)) 138 if overflow { 139 return 0, errGasUintOverflow 140 } 141 if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.Sha3WordGas); overflow { 142 return 0, errGasUintOverflow 143 } 144 if gas, overflow = math.SafeAdd(gas, wordGas); overflow { 145 return 0, errGasUintOverflow 146 } 147 return gas, nil 148 } 149 150 func gasCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 151 gas, err := memoryGasCost(mem, memorySize) 152 if err != nil { 153 return 0, err 154 } 155 156 var overflow bool 157 if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { 158 return 0, errGasUintOverflow 159 } 160 161 wordGas, overflow := bigUint64(stack.Back(2)) 162 if overflow { 163 return 0, errGasUintOverflow 164 } 165 if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow { 166 return 0, errGasUintOverflow 167 } 168 if gas, overflow = math.SafeAdd(gas, wordGas); overflow { 169 return 0, errGasUintOverflow 170 } 171 return gas, nil 172 } 173 174 func gasExtCodeCopy(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 175 gas, err := memoryGasCost(mem, memorySize) 176 if err != nil { 177 return 0, err 178 } 179 180 var overflow bool 181 if gas, overflow = math.SafeAdd(gas, gt.ExtcodeCopy); overflow { 182 return 0, errGasUintOverflow 183 } 184 185 wordGas, overflow := bigUint64(stack.Back(3)) 186 if overflow { 187 return 0, errGasUintOverflow 188 } 189 190 if wordGas, overflow = math.SafeMul(toWordSize(wordGas), params.CopyGas); overflow { 191 return 0, errGasUintOverflow 192 } 193 194 if gas, overflow = math.SafeAdd(gas, wordGas); overflow { 195 return 0, errGasUintOverflow 196 } 197 return gas, nil 198 } 199 200 func gasMLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 201 var overflow bool 202 gas, err := memoryGasCost(mem, memorySize) 203 if err != nil { 204 return 0, errGasUintOverflow 205 } 206 if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { 207 return 0, errGasUintOverflow 208 } 209 return gas, nil 210 } 211 212 func gasMStore8(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 213 var overflow bool 214 gas, err := memoryGasCost(mem, memorySize) 215 if err != nil { 216 return 0, errGasUintOverflow 217 } 218 if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { 219 return 0, errGasUintOverflow 220 } 221 return gas, nil 222 } 223 224 func gasMStore(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 225 var overflow bool 226 gas, err := memoryGasCost(mem, memorySize) 227 if err != nil { 228 return 0, errGasUintOverflow 229 } 230 if gas, overflow = math.SafeAdd(gas, GasFastestStep); overflow { 231 return 0, errGasUintOverflow 232 } 233 return gas, nil 234 } 235 236 func gasCreate(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 237 var overflow bool 238 gas, err := memoryGasCost(mem, memorySize) 239 if err != nil { 240 return 0, err 241 } 242 if gas, overflow = math.SafeAdd(gas, params.CreateGas); overflow { 243 return 0, errGasUintOverflow 244 } 245 return gas, nil 246 } 247 248 func gasBalance(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 249 return gt.Balance, nil 250 } 251 252 func gasExtCodeSize(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 253 return gt.ExtcodeSize, nil 254 } 255 256 func gasSLoad(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 257 return gt.SLoad, nil 258 } 259 260 func gasExp(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 261 expByteLen := uint64((stack.data[stack.len()-2].BitLen() + 7) / 8) 262 263 var ( 264 gas = expByteLen * gt.ExpByte // no overflow check required. Max is 256 * ExpByte gas 265 overflow bool 266 ) 267 if gas, overflow = math.SafeAdd(gas, GasSlowStep); overflow { 268 return 0, errGasUintOverflow 269 } 270 return gas, nil 271 } 272 273 func gasCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 274 var ( 275 gas = gt.Calls 276 transfersValue = stack.Back(2).Sign() != 0 277 address = common.BigToAddress(stack.Back(1)) 278 eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber) 279 ) 280 if eip158 { 281 if evm.StateDB.Empty(address) && transfersValue { 282 gas += params.CallNewAccountGas 283 } 284 } else if !evm.StateDB.Exist(address) { 285 gas += params.CallNewAccountGas 286 } 287 if transfersValue { 288 gas += params.CallValueTransferGas 289 } 290 memoryGas, err := memoryGasCost(mem, memorySize) 291 if err != nil { 292 return 0, err 293 } 294 var overflow bool 295 if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { 296 return 0, errGasUintOverflow 297 } 298 299 cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) 300 if err != nil { 301 return 0, err 302 } 303 // Replace the stack item with the new gas calculation. This means that 304 // either the original item is left on the stack or the item is replaced by: 305 // (availableGas - gas) * 63 / 64 306 // We replace the stack item so that it's available when the opCall instruction is 307 // called. This information is otherwise lost due to the dependency on *current* 308 // available gas. 309 stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) 310 311 if gas, overflow = math.SafeAdd(gas, cg); overflow { 312 return 0, errGasUintOverflow 313 } 314 return gas, nil 315 } 316 317 func gasCallCode(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 318 gas := gt.Calls 319 if stack.Back(2).Sign() != 0 { 320 gas += params.CallValueTransferGas 321 } 322 memoryGas, err := memoryGasCost(mem, memorySize) 323 if err != nil { 324 return 0, err 325 } 326 var overflow bool 327 if gas, overflow = math.SafeAdd(gas, memoryGas); overflow { 328 return 0, errGasUintOverflow 329 } 330 331 cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) 332 if err != nil { 333 return 0, err 334 } 335 // Replace the stack item with the new gas calculation. This means that 336 // either the original item is left on the stack or the item is replaced by: 337 // (availableGas - gas) * 63 / 64 338 // We replace the stack item so that it's available when the opCall instruction is 339 // called. This information is otherwise lost due to the dependency on *current* 340 // available gas. 341 stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) 342 343 if gas, overflow = math.SafeAdd(gas, cg); overflow { 344 return 0, errGasUintOverflow 345 } 346 return gas, nil 347 } 348 349 func gasReturn(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 350 return memoryGasCost(mem, memorySize) 351 } 352 353 func gasSuicide(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 354 var gas uint64 355 // EIP150 homestead gas reprice fork: 356 if evm.ChainConfig().IsEIP150(evm.BlockNumber) { 357 gas = gt.Suicide 358 var ( 359 address = common.BigToAddress(stack.Back(0)) 360 eip158 = evm.ChainConfig().IsEIP158(evm.BlockNumber) 361 ) 362 363 if eip158 { 364 // if empty and transfers value 365 if evm.StateDB.Empty(address) && evm.StateDB.GetBalance(contract.Address()).Sign() != 0 { 366 gas += gt.CreateBySuicide 367 } 368 } else if !evm.StateDB.Exist(address) { 369 gas += gt.CreateBySuicide 370 } 371 } 372 373 if !evm.StateDB.HasSuicided(contract.Address()) { 374 evm.StateDB.AddRefund(new(big.Int).SetUint64(params.SuicideRefundGas)) 375 } 376 return gas, nil 377 } 378 379 func gasDelegateCall(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 380 gas, err := memoryGasCost(mem, memorySize) 381 if err != nil { 382 return 0, err 383 } 384 var overflow bool 385 if gas, overflow = math.SafeAdd(gas, gt.Calls); overflow { 386 return 0, errGasUintOverflow 387 } 388 389 cg, err := callGas(gt, contract.Gas, gas, stack.Back(0)) 390 if err != nil { 391 return 0, err 392 } 393 // Replace the stack item with the new gas calculation. This means that 394 // either the original item is left on the stack or the item is replaced by: 395 // (availableGas - gas) * 63 / 64 396 // We replace the stack item so that it's available when the opCall instruction is 397 // called. 398 stack.data[stack.len()-1] = new(big.Int).SetUint64(cg) 399 400 if gas, overflow = math.SafeAdd(gas, cg); overflow { 401 return 0, errGasUintOverflow 402 } 403 return gas, nil 404 } 405 406 func gasPush(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 407 return GasFastestStep, nil 408 } 409 410 func gasSwap(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 411 return GasFastestStep, nil 412 } 413 414 func gasDup(gt params.GasTable, evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) { 415 return GasFastestStep, nil 416 }