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