github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/core/wavm/gas/rules.go (about) 1 // Copyright 2019 The go-vnt Authors 2 // This file is part of the go-vnt library. 3 // 4 // The go-vnt 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-vnt 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-vnt library. If not, see <http://www.gnu.org/licenses/>. 16 17 package gas 18 19 import ( 20 "errors" 21 "math/big" 22 23 "github.com/vntchain/go-vnt/common" 24 "github.com/vntchain/go-vnt/common/math" 25 "github.com/vntchain/go-vnt/core/state" 26 "github.com/vntchain/go-vnt/core/vm" 27 "github.com/vntchain/go-vnt/core/wavm/contract" 28 "github.com/vntchain/go-vnt/params" 29 ops "github.com/vntchain/vnt-wasm/wasm/operators" 30 ) 31 32 const ( 33 WasmCostsRegular = 1 34 WasmCostsDiv = 16 35 WasmCostsMul = 4 36 WasmCostsMem = 2 37 WasmCostsStaticU256 = 64 38 WasmCostsStaticHash = 64 39 WasmCostsStaticAddress = 40 40 /// Memory stipend. Amount of free memory (in 64kb pages) each contract can use for stack. 41 WasmCostsInitialMem = 4096 42 /// Grow memory cost, per page (64kb) 43 WasmCostsGrowMem = 8192 44 WasmCostsMemcpy = 1 45 WasmCostsMaxStackHeight = 64 * 1024 46 WasmCostsOpcodesMul = 3 47 WasmCostsOpcodesDiv = 8 48 ) 49 50 const ErrorGasLimit = "Invocation resulted in gas limit violated" 51 const ErrorInitialMemLimit = "Initial memory limit" 52 const ErrorDisableFloatingPoint = "Wasm contract error: disabled floating point" 53 54 var errGasUintOverflow = errors.New("gas uint64 overflow") 55 56 type GasValue struct { 57 Metering Metering 58 Value uint64 59 } 60 61 type Gas struct { 62 Ops map[byte]InstructionType 63 Rules map[InstructionType]GasValue 64 } 65 66 type GasCounter struct { 67 Contract *contract.WASMContract 68 GasTable params.GasTable 69 } 70 71 func NewGas(disableFloatingPoint bool) Gas { 72 rules := Gas{ 73 Ops: map[byte]InstructionType{ 74 ops.Unreachable: InstructionTypeUnreachable, 75 ops.Nop: InstructionTypeNop, 76 ops.Block: InstructionTypeControlFlow, 77 ops.Loop: InstructionTypeControlFlow, 78 ops.If: InstructionTypeControlFlow, 79 ops.Else: InstructionTypeControlFlow, 80 ops.End: InstructionTypeControlFlow, 81 ops.Br: InstructionTypeControlFlow, 82 ops.BrIf: InstructionTypeControlFlow, 83 ops.BrTable: InstructionTypeControlFlow, 84 ops.Return: InstructionTypeControlFlow, 85 ops.Call: InstructionTypeControlFlow, 86 ops.CallIndirect: InstructionTypeControlFlow, 87 ops.Drop: InstructionTypeControlFlow, 88 ops.Select: InstructionTypeControlFlow, 89 90 ops.GetLocal: InstructionTypeLocal, 91 ops.SetLocal: InstructionTypeLocal, 92 ops.TeeLocal: InstructionTypeLocal, 93 ops.GetGlobal: InstructionTypeLocal, 94 ops.SetGlobal: InstructionTypeLocal, 95 96 ops.I32Load: InstructionTypeLoad, 97 ops.I64Load: InstructionTypeLoad, 98 ops.F32Load: InstructionTypeLoad, 99 ops.F64Load: InstructionTypeLoad, 100 ops.I32Load8s: InstructionTypeLoad, 101 ops.I32Load8u: InstructionTypeLoad, 102 ops.I32Load16s: InstructionTypeLoad, 103 ops.I32Load16u: InstructionTypeLoad, 104 ops.I64Load8s: InstructionTypeLoad, 105 ops.I64Load8u: InstructionTypeLoad, 106 ops.I64Load16s: InstructionTypeLoad, 107 ops.I64Load16u: InstructionTypeLoad, 108 ops.I64Load32s: InstructionTypeLoad, 109 ops.I64Load32u: InstructionTypeLoad, 110 111 ops.I32Store: InstructionTypeStore, 112 ops.I64Store: InstructionTypeStore, 113 ops.F32Store: InstructionTypeStore, 114 ops.F64Store: InstructionTypeStore, 115 ops.I32Store8: InstructionTypeStore, 116 ops.I32Store16: InstructionTypeStore, 117 ops.I64Store8: InstructionTypeStore, 118 ops.I64Store16: InstructionTypeStore, 119 ops.I64Store32: InstructionTypeStore, 120 121 ops.CurrentMemory: InstructionTypeCurrentMemory, 122 ops.GrowMemory: InstructionTypeGrowMemory, 123 124 ops.I32Const: InstructionTypeConst, 125 ops.I64Const: InstructionTypeConst, 126 127 ops.F32Const: InstructionTypeFloatConst, 128 ops.F64Const: InstructionTypeFloatConst, 129 130 ops.I32Eqz: InstructionTypeIntegerComparsion, 131 ops.I32Eq: InstructionTypeIntegerComparsion, 132 ops.I32Ne: InstructionTypeIntegerComparsion, 133 ops.I32LtS: InstructionTypeIntegerComparsion, 134 ops.I32LtU: InstructionTypeIntegerComparsion, 135 ops.I32GtS: InstructionTypeIntegerComparsion, 136 ops.I32GtU: InstructionTypeIntegerComparsion, 137 ops.I32LeS: InstructionTypeIntegerComparsion, 138 ops.I32LeU: InstructionTypeIntegerComparsion, 139 ops.I32GeS: InstructionTypeIntegerComparsion, 140 ops.I32GeU: InstructionTypeIntegerComparsion, 141 142 ops.I64Eqz: InstructionTypeIntegerComparsion, 143 ops.I64Eq: InstructionTypeIntegerComparsion, 144 ops.I64Ne: InstructionTypeIntegerComparsion, 145 ops.I64LtS: InstructionTypeIntegerComparsion, 146 ops.I64LtU: InstructionTypeIntegerComparsion, 147 ops.I64GtS: InstructionTypeIntegerComparsion, 148 ops.I64GtU: InstructionTypeIntegerComparsion, 149 ops.I64LeS: InstructionTypeIntegerComparsion, 150 ops.I64LeU: InstructionTypeIntegerComparsion, 151 ops.I64GeS: InstructionTypeIntegerComparsion, 152 ops.I64GeU: InstructionTypeIntegerComparsion, 153 154 ops.F32Eq: InstructionTypeFloatComparsion, 155 ops.F32Ne: InstructionTypeFloatComparsion, 156 ops.F32Lt: InstructionTypeFloatComparsion, 157 ops.F32Gt: InstructionTypeFloatComparsion, 158 ops.F32Le: InstructionTypeFloatComparsion, 159 ops.F32Ge: InstructionTypeFloatComparsion, 160 161 ops.F64Eq: InstructionTypeFloatComparsion, 162 ops.F64Ne: InstructionTypeFloatComparsion, 163 ops.F64Lt: InstructionTypeFloatComparsion, 164 ops.F64Gt: InstructionTypeFloatComparsion, 165 ops.F64Le: InstructionTypeFloatComparsion, 166 ops.F64Ge: InstructionTypeFloatComparsion, 167 168 ops.I32Clz: InstructionTypeBit, 169 ops.I32Ctz: InstructionTypeBit, 170 ops.I32Popcnt: InstructionTypeBit, 171 ops.I32Add: InstructionTypeAdd, 172 ops.I32Sub: InstructionTypeAdd, 173 ops.I32Mul: InstructionTypeMul, 174 ops.I32DivS: InstructionTypeDiv, 175 ops.I32DivU: InstructionTypeDiv, 176 ops.I32RemS: InstructionTypeDiv, 177 ops.I32RemU: InstructionTypeDiv, 178 ops.I32And: InstructionTypeBit, 179 ops.I32Or: InstructionTypeBit, 180 ops.I32Xor: InstructionTypeBit, 181 ops.I32Shl: InstructionTypeBit, 182 ops.I32ShrS: InstructionTypeBit, 183 ops.I32ShrU: InstructionTypeBit, 184 ops.I32Rotl: InstructionTypeBit, 185 ops.I32Rotr: InstructionTypeBit, 186 187 ops.I64Clz: InstructionTypeBit, 188 ops.I64Ctz: InstructionTypeBit, 189 ops.I64Popcnt: InstructionTypeBit, 190 ops.I64Add: InstructionTypeAdd, 191 ops.I64Sub: InstructionTypeAdd, 192 ops.I64Mul: InstructionTypeMul, 193 ops.I64DivS: InstructionTypeDiv, 194 ops.I64DivU: InstructionTypeDiv, 195 ops.I64RemS: InstructionTypeDiv, 196 ops.I64RemU: InstructionTypeDiv, 197 ops.I64And: InstructionTypeBit, 198 ops.I64Or: InstructionTypeBit, 199 ops.I64Xor: InstructionTypeBit, 200 ops.I64Shl: InstructionTypeBit, 201 ops.I64ShrS: InstructionTypeBit, 202 ops.I64ShrU: InstructionTypeBit, 203 ops.I64Rotl: InstructionTypeBit, 204 ops.I64Rotr: InstructionTypeBit, 205 206 ops.F32Abs: InstructionTypeFloat, 207 ops.F32Neg: InstructionTypeFloat, 208 ops.F32Ceil: InstructionTypeFloat, 209 ops.F32Floor: InstructionTypeFloat, 210 ops.F32Trunc: InstructionTypeFloat, 211 ops.F32Nearest: InstructionTypeFloat, 212 ops.F32Sqrt: InstructionTypeFloat, 213 ops.F32Add: InstructionTypeFloat, 214 ops.F32Sub: InstructionTypeFloat, 215 ops.F32Mul: InstructionTypeFloat, 216 ops.F32Div: InstructionTypeFloat, 217 ops.F32Min: InstructionTypeFloat, 218 ops.F32Max: InstructionTypeFloat, 219 ops.F32Copysign: InstructionTypeFloat, 220 ops.F64Abs: InstructionTypeFloat, 221 ops.F64Neg: InstructionTypeFloat, 222 ops.F64Ceil: InstructionTypeFloat, 223 ops.F64Floor: InstructionTypeFloat, 224 ops.F64Trunc: InstructionTypeFloat, 225 ops.F64Nearest: InstructionTypeFloat, 226 ops.F64Sqrt: InstructionTypeFloat, 227 ops.F64Add: InstructionTypeFloat, 228 ops.F64Sub: InstructionTypeFloat, 229 ops.F64Mul: InstructionTypeFloat, 230 ops.F64Div: InstructionTypeFloat, 231 ops.F64Min: InstructionTypeFloat, 232 ops.F64Max: InstructionTypeFloat, 233 ops.F64Copysign: InstructionTypeFloat, 234 235 ops.I32WrapI64: InstructionTypeConversion, 236 ops.I64ExtendSI32: InstructionTypeConversion, 237 ops.I64ExtendUI32: InstructionTypeConversion, 238 239 ops.I32TruncSF32: InstructionTypeFloatConversion, 240 ops.I32TruncUF32: InstructionTypeFloatConversion, 241 ops.I32TruncSF64: InstructionTypeFloatConversion, 242 ops.I32TruncUF64: InstructionTypeFloatConversion, 243 ops.I64TruncSF32: InstructionTypeFloatConversion, 244 ops.I64TruncUF32: InstructionTypeFloatConversion, 245 ops.I64TruncSF64: InstructionTypeFloatConversion, 246 ops.I64TruncUF64: InstructionTypeFloatConversion, 247 ops.F32ConvertSI32: InstructionTypeFloatConversion, 248 ops.F32ConvertUI32: InstructionTypeFloatConversion, 249 ops.F32ConvertSI64: InstructionTypeFloatConversion, 250 ops.F32ConvertUI64: InstructionTypeFloatConversion, 251 ops.F32DemoteF64: InstructionTypeFloatConversion, 252 ops.F64ConvertSI32: InstructionTypeFloatConversion, 253 ops.F64ConvertUI32: InstructionTypeFloatConversion, 254 ops.F64ConvertSI64: InstructionTypeFloatConversion, 255 ops.F64ConvertUI64: InstructionTypeFloatConversion, 256 ops.F64PromoteF32: InstructionTypeFloatConversion, 257 258 ops.I32ReinterpretF32: InstructionTypeReinterpretation, 259 ops.I64ReinterpretF64: InstructionTypeReinterpretation, 260 ops.F32ReinterpretI32: InstructionTypeReinterpretation, 261 ops.F64ReinterpretI64: InstructionTypeReinterpretation, 262 }, 263 Rules: map[InstructionType]GasValue{ 264 InstructionTypeLoad: GasValue{Metering: MeteringFixed, Value: WasmCostsMem}, 265 InstructionTypeStore: GasValue{Metering: MeteringFixed, Value: WasmCostsMem}, 266 InstructionTypeDiv: GasValue{Metering: MeteringFixed, Value: WasmCostsDiv}, 267 InstructionTypeMul: GasValue{Metering: MeteringFixed, Value: WasmCostsMul}, 268 }, 269 } 270 if disableFloatingPoint { 271 rules.Rules[InstructionTypeFloat] = GasValue{ 272 Metering: MeteringForbidden, Value: 0, 273 } 274 rules.Rules[InstructionTypeFloatComparsion] = GasValue{ 275 Metering: MeteringForbidden, Value: 0, 276 } 277 rules.Rules[InstructionTypeFloatConst] = GasValue{ 278 Metering: MeteringForbidden, Value: 0, 279 } 280 rules.Rules[InstructionTypeFloatConversion] = GasValue{ 281 Metering: MeteringForbidden, Value: 0, 282 } 283 } 284 return rules 285 } 286 287 func (gas Gas) GasCost(op byte) uint64 { 288 metering := gas.Rules[gas.Ops[op]] 289 switch metering.Metering { 290 case MeteringForbidden: 291 panic(ErrorDisableFloatingPoint) 292 case MeteringFixed: 293 return metering.Value 294 default: 295 return WasmCostsRegular 296 } 297 } 298 299 func constGasFunc(gas uint64) uint64 { 300 return gas 301 } 302 303 func NewGasCounter(contract *contract.WASMContract, gasTable params.GasTable) GasCounter { 304 return GasCounter{ 305 Contract: contract, 306 GasTable: gasTable, 307 } 308 309 } 310 311 func (gas GasCounter) Charge(amount uint64) { 312 if !gas.ChargeGas(amount) { 313 panic(ErrorGasLimit) 314 } 315 } 316 317 func (gas GasCounter) ChargeGas(amount uint64) bool { 318 return gas.Contract.UseGas(amount) 319 } 320 321 func (gas GasCounter) AdjustedCharge(amount uint64) { 322 // gas.Charge(amount * WasmCostsOpcodesMul / WasmCostsOpcodesDiv) 323 gas.Charge(amount) 324 } 325 326 func (gas GasCounter) GasQuickStep() { 327 gas.Charge(constGasFunc(vm.GasQuickStep)) 328 } 329 330 func (gas GasCounter) GasFastestStep() { 331 gas.Charge(constGasFunc(vm.GasFastestStep)) 332 } 333 334 func (gas GasCounter) GasGetBlockNumber() { 335 gas.Charge(constGasFunc(vm.GasQuickStep)) 336 } 337 338 func (gas GasCounter) GasGetBalanceFromAddress() { 339 gas.Charge(constGasFunc(vm.GasQuickStep)) 340 } 341 342 func (gas GasCounter) GasMemoryCost(size uint64) { 343 gas.Charge(constGasFunc(vm.GasQuickStep * size)) 344 } 345 346 func (gas GasCounter) GasGetGas() { 347 gas.Charge(constGasFunc(vm.GasQuickStep)) 348 } 349 350 func (gas GasCounter) GasGetBlockHash() { 351 gas.Charge(constGasFunc(vm.GasExtStep)) 352 } 353 354 func (gas GasCounter) GasGetBlockProduser() { 355 gas.Charge(constGasFunc(vm.GasQuickStep)) 356 } 357 358 func (gas GasCounter) GasGetTimestamp() { 359 gas.Charge(constGasFunc(vm.GasQuickStep)) 360 } 361 362 func (gas GasCounter) GasGetOrigin() { 363 gas.Charge(constGasFunc(vm.GasQuickStep)) 364 } 365 366 func (gas GasCounter) GasGetSender() { 367 gas.Charge(constGasFunc(vm.GasQuickStep)) 368 } 369 370 func (gas GasCounter) GasGetGasLimit() { 371 gas.Charge(constGasFunc(vm.GasQuickStep)) 372 } 373 374 // func (vm *VM) GasGenerateKey() error { 375 // return vm.adjustedCharge(constGasFunc(20)) 376 // } 377 378 // func (vm *VM) GasGetStorageCount() error { 379 // return nil 380 // } 381 382 func (gas GasCounter) GasGetValue() { 383 gas.Charge(constGasFunc(vm.GasQuickStep)) 384 } 385 386 //todo 验证sha3 gas消耗,和evm保持一致 387 func (gas GasCounter) GasSHA3(size uint64) { 388 gas.Charge(params.Sha3Gas) 389 gas.Charge(params.Sha3WordGas * size) 390 } 391 392 func (gas GasCounter) GasGetContractAddress() { 393 gas.Charge(constGasFunc(vm.GasQuickStep)) 394 } 395 396 func (gas GasCounter) GasAssert() { 397 gas.Charge(constGasFunc(vm.GasQuickStep)) 398 } 399 400 func (gas GasCounter) GasRevert() { 401 gas.Charge(constGasFunc(vm.GasQuickStep)) 402 } 403 404 func (gas GasCounter) GasSendFromContract() { 405 gas.Charge(constGasFunc(params.CallStipend)) 406 } 407 408 // func (gas GasCounter) GasGetContractValue() { 409 // gas.Charge(constGasFunc(params.CallValueTransferGas)) 410 // } 411 412 func (gas GasCounter) GasFromI64() { 413 gas.Charge(constGasFunc(vm.GasQuickStep)) 414 } 415 416 func (gas GasCounter) GasFromU64() { 417 gas.Charge(constGasFunc(vm.GasQuickStep)) 418 } 419 420 func (gas GasCounter) GasToI64() { 421 gas.Charge(constGasFunc(vm.GasQuickStep)) 422 } 423 424 func (gas GasCounter) GasToU64() { 425 gas.Charge(constGasFunc(vm.GasQuickStep)) 426 } 427 428 func (gas GasCounter) GasConcat(size uint64) { 429 gas.Charge(constGasFunc(WasmCostsMem * size)) 430 } 431 432 func (gas GasCounter) GasEqual() { 433 gas.Charge(constGasFunc(vm.GasQuickStep)) 434 } 435 436 func (gas GasCounter) GasLog(size uint64, topics uint64) { 437 requestedSize, overflow := vm.BigUint64(new(big.Int).SetUint64(size)) 438 if overflow { 439 panic(errGasUintOverflow) 440 } 441 costgas := uint64(0) 442 if costgas, overflow = math.SafeAdd(costgas, params.LogGas); overflow { 443 panic(errGasUintOverflow) 444 } 445 if costgas, overflow = math.SafeAdd(costgas, topics*params.LogTopicGas); overflow { 446 panic(errGasUintOverflow) 447 } 448 var memorySizeGas uint64 449 if memorySizeGas, overflow = math.SafeMul(requestedSize, params.LogDataGas); overflow { 450 panic(errGasUintOverflow) 451 } 452 if costgas, overflow = math.SafeAdd(costgas, memorySizeGas); overflow { 453 panic(errGasUintOverflow) 454 } 455 gas.Charge(costgas) 456 } 457 458 func (gas GasCounter) GasCall(address common.Address, value, gasLimit, blockNumber *big.Int, chainConfig *params.ChainConfig, statedb *state.StateDB) uint64 { 459 var ( 460 callgas = gas.GasTable.Calls 461 transfersValue = value.Sign() != 0 462 ) 463 if transfersValue && statedb.Empty(address) { 464 callgas += params.CallNewAccountGas 465 } 466 if transfersValue { 467 callgas += params.CallValueTransferGas 468 } 469 tempgas, err := gas.callGas(gas.GasTable, gas.Contract.Gas, callgas, gasLimit) 470 if err != nil { 471 panic(err.Error()) 472 } 473 474 var overflow bool 475 if callgas, overflow = math.SafeAdd(callgas, tempgas); overflow { 476 panic(errGasUintOverflow) 477 } 478 gas.Charge(callgas) 479 return tempgas 480 } 481 482 func (gas GasCounter) callGas(gasTable params.GasTable, availableGas, base uint64, callCost *big.Int) (uint64, error) { 483 if gasTable.CreateBySuicide > 0 { 484 availableGas = availableGas - base 485 gas := availableGas - availableGas/64 486 // If the bit length exceeds 64 bit we know that the newly calculated "gas" for EIP150 487 // is smaller than the requested amount. Therefor we return the new gas instead 488 // of returning an error. 489 if callCost.BitLen() > 64 || gas < callCost.Uint64() { 490 return gas, nil 491 } 492 } 493 if callCost.BitLen() > 64 { 494 return 0, errGasUintOverflow 495 } 496 return callCost.Uint64(), nil 497 } 498 499 func (gas GasCounter) GasStore(stateDb *state.StateDB, contractAddr common.Address, loc common.Hash, value common.Hash) { 500 var ( 501 y, x = value, loc 502 val = stateDb.GetState(contractAddr, x) 503 ) 504 // This checks for 3 scenario's and calculates gas accordingly 505 // 1. From a zero-value address to a non-zero value (NEW VALUE) 506 // 2. From a non-zero value address to a zero-value address (DELETE) 507 // 3. From a non-zero to a non-zero (CHANGE) 508 if (val == common.Hash{} && y != common.Hash{}) { 509 // 0 => non 0 510 gas.Charge(constGasFunc(params.SstoreSetGas)) 511 // return params.SstoreSetGas, nil 512 } else if (val != common.Hash{} && y == common.Hash{}) { 513 stateDb.AddRefund(params.SstoreRefundGas) 514 gas.Charge(constGasFunc(params.SstoreClearGas)) 515 // return params.SstoreClearGas, nil 516 } else { 517 // non 0 => non 0 (or 0 => 0) 518 gas.Charge(constGasFunc(params.SstoreResetGas)) 519 // return params.SstoreResetGas, nil 520 } 521 } 522 523 func (gas GasCounter) GasLoad() { 524 gas.Charge(constGasFunc(gas.GasTable.SLoad)) 525 } 526 527 func (gas GasCounter) GasEcrecover() { 528 gas.Charge(constGasFunc(params.EcrecoverGas)) 529 } 530 531 func (gas GasCounter) GasPow(exponent *big.Int) { 532 expByteLen := uint64((exponent.BitLen() + 7) / 8) 533 var ( 534 costgas = expByteLen * gas.GasTable.ExpByte // no overflow check required. Max is 256 * ExpByte gas 535 overflow bool 536 ) 537 if costgas, overflow = math.SafeAdd(costgas, vm.GasQuickStep); overflow { 538 panic(errGasUintOverflow) 539 } 540 gas.Charge(constGasFunc(costgas)) 541 } 542 543 func (gas GasCounter) GasCostZero() { 544 gas.Charge(constGasFunc(0)) 545 } 546 547 func (gas GasCounter) GasReturnAddress() { 548 gas.AdjustedCharge(constGasFunc(WasmCostsStaticAddress)) 549 } 550 551 func (gas GasCounter) GasReturnU256() { 552 gas.AdjustedCharge(constGasFunc(WasmCostsStaticU256)) 553 } 554 555 func (gas GasCounter) GasReturnHash() { 556 gas.AdjustedCharge(constGasFunc(WasmCostsStaticHash)) 557 } 558 559 func (gas GasCounter) GasReturnPointer(size uint64) { 560 gas.AdjustedCharge(constGasFunc(size)) 561 } 562 563 func (gas GasCounter) GasInitialMemory(initial uint64) { 564 amount := initial * WasmCostsInitialMem 565 if !gas.ChargeGas(amount) { 566 panic(ErrorInitialMemLimit) 567 } 568 }