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