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
This commit is contained in:
andri lim 2024-07-06 08:39:22 +07:00 committed by GitHub
parent c775c906a2
commit 4eaae5cbfa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 34 additions and 41 deletions

View File

@ -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) )

View File

@ -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)

View File

@ -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()

View File

@ -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"}