From 4eaae5cbfa8845b0975ab53f502fdf0c27d733ab Mon Sep 17 00:00:00 2001 From: andri lim Date: Sat, 6 Jul 2024 08:39:22 +0700 Subject: [PATCH] EVM gasCall values always stay on positive side (#2459) * EVM gasCall values always stay on positive side This is also another part of preparations before converting GasInt to uint64 * Fix test_evm_support --- nimbus/evm/interpreter/gas_costs.nim | 42 ++++++++++--------- .../evm/interpreter/op_handlers/oph_call.nim | 28 ++++--------- tests/test_evm_support.nim | 3 +- tools/t8n/testdata/00-521/exp.txt | 2 +- 4 files changed, 34 insertions(+), 41 deletions(-) diff --git a/nimbus/evm/interpreter/gas_costs.nim b/nimbus/evm/interpreter/gas_costs.nim index 273f988f6..26cc5d267 100644 --- a/nimbus/evm/interpreter/gas_costs.nim +++ b/nimbus/evm/interpreter/gas_costs.nim @@ -67,7 +67,8 @@ type kind*: Op isNewAccount*: bool - gasBalance*: GasInt + gasLeft*: GasInt + gasCallEIP2929*: GasInt contractGas*: UInt256 currentMemSize*: GasNatural memOffset*: GasNatural @@ -348,7 +349,6 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) = static(4 * FeeSchedule[GasLogTopic]) func `prefix gasCall`(value: UInt256, params: GasParams): EvmResult[CallGasResult] {.nimcall.} = - # From the Yellow Paper, going through the equation from bottom to top # https://ethereum.github.io/yellowpaper/paper.pdf#appendix.H # @@ -369,15 +369,18 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) = # The discussion for the draft EIP-5, which proposes to change the CALL opcode also goes over # the current implementation - https://github.com/ethereum/EIPs/issues/8 - # Both gasCost and childGasLimit can go below zero - # but that is an OOG condition. Leaving this function - # both of them are positive integers. + # Both gasCost and childGasLimit are always on positive side - var gasCost: int64 = `prefix gasMemoryExpansion`( + var gasLeft = params.gasLeft + if gasLeft < params.gasCallEIP2929: + return err(opErr(OutOfGas)) + gasLeft -= params.gasCallEIP2929 + + var gasCost: GasInt = `prefix gasMemoryExpansion`( params.currentMemSize, params.memOffset, params.memLength) - var childGasLimit: int64 + var childGasLimit: GasInt # Cnew_account if params.isNewAccount and params.kind == Call: @@ -398,33 +401,34 @@ template gasCosts(fork: EVMFork, prefix, ResultGasCostsName: untyped) = # Cextra gasCost += static(FeeSchedule[GasCall]) + if gasLeft < gasCost: + return err(opErr(OutOfGas)) + gasLeft -= gasCost + # Cgascap when fork >= FkTangerine: # https://github.com/ethereum/EIPs/blob/master/EIPS/eip-150.md - let gas = `prefix all_but_one_64th`(params.gasBalance - gasCost) - if params.contractGas > high(int64).u256 or - gas < params.contractGas.truncate(int64): + let gas = `prefix all_but_one_64th`(gasLeft) + if params.contractGas > high(GasInt).u256 or + gas < params.contractGas.truncate(GasInt): childGasLimit = gas else: - childGasLimit = params.contractGas.truncate(int64) + childGasLimit = params.contractGas.truncate(GasInt) else: - if params.contractGas > high(int64).u256: + if params.contractGas > high(GasInt).u256: return err(gasErr(GasIntOverflow)) - childGasLimit = params.contractGas.truncate(int64) + childGasLimit = params.contractGas.truncate(GasInt) - if childGasLimit > 0: # skip check if childGasLimit is negative - if gasCost.u256 + childGasLimit.u256 > high(int64).u256: - return err(gasErr(GasIntOverflow)) + if gasCost.u256 + childGasLimit.u256 + params.gasCallEIP2929.u256 > high(GasInt).u256: + return err(gasErr(GasIntOverflow)) gasCost += childGasLimit + gasCost += params.gasCallEIP2929 # Ccallgas - Gas sent to the child message if not value.isZero and params.kind in {Call, CallCode}: childGasLimit += static(FeeSchedule[GasCallStipend]) - if gasCost <= 0 and childGasLimit <= 0: - return err(opErr(OutOfGas)) - # at this point gasCost and childGasLimit is always > 0 ok( (gasCost, childGasLimit) ) diff --git a/nimbus/evm/interpreter/op_handlers/oph_call.nim b/nimbus/evm/interpreter/op_handlers/oph_call.nim index a25e72e31..66ae0751d 100644 --- a/nimbus/evm/interpreter/op_handlers/oph_call.nim +++ b/nimbus/evm/interpreter/op_handlers/oph_call.nim @@ -210,21 +210,18 @@ proc callOp(k: var VmCtx): EvmResultVoid = let p = ? cpt.callParams - - var (gasCost, childGasLimit) = ? cpt.gasCosts[Call].c_handler( p.value, GasParams( kind: Call, isNewAccount: not cpt.accountExists(p.contractAddress), - gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, + gasLeft: cpt.gasMeter.gasRemaining, + gasCallEIP2929: p.gasCallEIP2929, contractGas: p.gas, currentMemSize: cpt.memory.len, memOffset: p.memOffset, memLength: p.memLength)) - # at this point gasCost is always > 0 - gasCost += p.gasCallEIP2929 ? cpt.opcodeGastCost(Call, gasCost, reason = $Call) cpt.returnData.setLen(0) @@ -285,21 +282,18 @@ proc callCodeOp(k: var VmCtx): EvmResultVoid = let cpt = k.cpt p = ? cpt.callCodeParams - - var (gasCost, childGasLimit) = ? cpt.gasCosts[CallCode].c_handler( p.value, GasParams( kind: CallCode, isNewAccount: not cpt.accountExists(p.contractAddress), - gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, + gasLeft: cpt.gasMeter.gasRemaining, + gasCallEIP2929: p.gasCallEIP2929, contractGas: p.gas, currentMemSize: cpt.memory.len, memOffset: p.memOffset, memLength: p.memLength)) - # at this point gasCost is always > 0 - gasCost += p.gasCallEIP2929 ? cpt.opcodeGastCost(CallCode, gasCost, reason = $CallCode) cpt.returnData.setLen(0) @@ -361,21 +355,18 @@ proc delegateCallOp(k: var VmCtx): EvmResultVoid = let cpt = k.cpt p = ? cpt.delegateCallParams - - var (gasCost, childGasLimit) = ? cpt.gasCosts[DelegateCall].c_handler( p.value, GasParams( kind: DelegateCall, isNewAccount: not cpt.accountExists(p.contractAddress), - gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, + gasLeft: cpt.gasMeter.gasRemaining, + gasCallEIP2929: p.gasCallEIP2929, contractGas: p.gas, currentMemSize: cpt.memory.len, memOffset: p.memOffset, memLength: p.memLength)) - # at this point gasCost is always > 0 - gasCost += p.gasCallEIP2929 ? cpt.opcodeGastCost(DelegateCall, gasCost, reason = $DelegateCall) cpt.returnData.setLen(0) @@ -431,21 +422,18 @@ proc staticCallOp(k: var VmCtx): EvmResultVoid = let cpt = k.cpt p = ? cpt.staticCallParams - - var (gasCost, childGasLimit) = ? cpt.gasCosts[StaticCall].c_handler( p.value, GasParams( kind: StaticCall, isNewAccount: not cpt.accountExists(p.contractAddress), - gasBalance: cpt.gasMeter.gasRemaining - p.gasCallEIP2929, + gasLeft: cpt.gasMeter.gasRemaining, + gasCallEIP2929: p.gasCallEIP2929, contractGas: p.gas, currentMemSize: cpt.memory.len, memOffset: p.memOffset, memLength: p.memLength)) - # at this point gasCost is always > 0 - gasCost += p.gasCallEIP2929 ? cpt.opcodeGastCost(StaticCall, gasCost, reason = $StaticCall) cpt.returnData.setLen(0) diff --git a/tests/test_evm_support.nim b/tests/test_evm_support.nim index c716f5d1e..5e5a3aa50 100644 --- a/tests/test_evm_support.nim +++ b/tests/test_evm_support.nim @@ -381,7 +381,8 @@ proc runTestOverflow() = when defined(evmc_enabled): check res.error == "EVMC_FAILURE" else: - check res.error == "Opcode Dispatch Error: GasIntOverflow, depth=1" + # After gasCall values always on positive, this test become OOG + check res.error == "Opcode Dispatch Error: OutOfGas, depth=1" proc evmSupportMain*() = runStackTests() diff --git a/tools/t8n/testdata/00-521/exp.txt b/tools/t8n/testdata/00-521/exp.txt index 284640556..d16489231 100644 --- a/tools/t8n/testdata/00-521/exp.txt +++ b/tools/t8n/testdata/00-521/exp.txt @@ -12,6 +12,6 @@ {"pc":8,"op":96,"gas":"0xf","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} {"pc":10,"op":96,"gas":"0xc","gasCost":"0x3","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0"],"depth":2,"refund":0,"opName":"PUSH1"} {"pc":12,"op":90,"gas":"0x9","gasCost":"0x2","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xfa"],"depth":2,"refund":0,"opName":"GAS"} -{"pc":13,"op":241,"gas":"0x7","gasCost":"0x9","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xfa","0x7"],"depth":2,"refund":0,"opName":"CALL","error":"Opcode Dispatch Error: OutOfGas, depth=2"} +{"pc":13,"op":241,"gas":"0x7","gasCost":"0x7","memSize":0,"stack":["0x0","0x0","0x0","0x0","0x0","0xfa","0x7"],"depth":2,"refund":0,"opName":"CALL","error":"Opcode Dispatch Error: OutOfGas, depth=2"} {"pc":12,"op":80,"gas":"0x0","gasCost":"0x2","memSize":0,"stack":["0x0"],"depth":1,"refund":0,"opName":"POP","error":"Opcode Dispatch Error: OutOfGas, depth=1"} {"output":"","gasUsed":"0xa54","error":"Opcode Dispatch Error: OutOfGas, depth=1"}