This repository has been archived by the owner on Jan 9, 2024. It is now read-only.
GasCost calculation mismatch for opCode CALL/STATICCALL with RPCdaemon #296
Labels
bug
Something isn't working
Executing the
debug_traceTransaction
call using the following input:we see a mismatch on gasCost calculation between RPCDaemon/erigon and Silkrpc/Silkworm/Evmone
Erigon:
See core/vm/interpreter.go
//Static portion of gas
cost = operation.constantGas // For tracing (ad esempio per la CALL e 100)
// Dynamic portion of gas
// consume the gas and return an error if not enough gas is available.
// cost is explicitly set so that the capture state defer method can get the proper cost
if operation.dynamicGas != nil {
var dynamicCost uint64
dynamicCost, err = operation.dynamicGas(in.evm, contract, locStack, mem, memorySize)
}
So the gasCost is the sum between static part and dynamica one using the gas returned by operation.dynamicGas
Then is called the Tracer:
in.cfg.Tracer.CaptureState(in.evm, pc, op, gasCopy, cost, mem, locStack, in.returnData, contract, in.evm.depth, err)
The routine operation.dynamicGas() in our case is' :
makeCallVariantGasCallEIP2929() in core/vm/operations_acl.go
In the routine contract.Gas (is the gasLeft) (GasLeft - static cost opcode)
if !warmAccess
decrease by coldCost (2500)
gas, err := oldCalculator() // decrease by 1/64 of the gas-left
if warmAccess
return
// In case of a cold access, we temporarily add the cold charge back, and also
// add it to the returned gas. By adding it to the return, it will be charged
// outside of this function, as part of the dynamic gas, and that will make it
// also become correctly reported to tracers.
Using the transaction reported below:
"pc":15411,"op":"DUP7","gas":77277,"gasCost":3,"depth":2
"pc":15412,"op":"GAS","gas":77274,"gasCost":2,"depth":2
"pc":15413,"op":"CALL","gas":77272,"gasCost":76106,"depth":2
==============
"pc":0,"op":"PUSH1","gas":73506,"gasCost":3,"depth":3
"pc":2,"op":"PUSH1","gas":73503,"gasCost":3,"depth":3
"pc":4,"op":"MSTORE","gas":73500,"gasCost":12,"depth":3
in makeCallVariantGasCallEIP2929: 77172 (contract.Gas is already decreased by opcode cost)
if !warmAccess
77172-2500 = 74672 (coldCost)
74672-(74672/64) = 73506 (old-calculator)
73506+2500=76006
After the routine it is summed the static parte (100) = 76106
Seems the gasCost calculation for CALL and any other opcode different. Is it correct
In silkrpc (tracer) with current interface using gas-left and nsg.gas it is not possible calculate gasCost of the CALL in the same way of ERIGON.
call_impl() in silkworm/third_party/evmone/lib/evmone/instructions_calls.cpp
in input we have:
if (state.rev >= EVMC_BERLIN && state.host.access_account(dst) == EVMC_ACCESS_COLD)
decraese gas-left by 2500 (coldCost)
// assign msg.gas = gas
msg.gas = std::min(msg.gas, state.gas_left - state.gas_left / 64);
then it is executed the execute() where the tracer is called
const auto result = state.host.call(msg);
the tracer is called with gas-left and msg.gas with same value. Because during ExecutionState the reset() is caled
using transaction data:
"depth":2,"gas":77277,"gasCost":3,"op":"DUP7","pc":15411
"depth":2,"gas":77274,"gasCost":2,"op":"GAS","pc":15412
"depth":2,"gas":77272,"gasCost":73506,"op":"CALL","pc":15413
--------------
"depth":3,"gas":73506,"gasCost":3,"op":"PUSH1","pc":0
"depth":3,"gas":73503,"gasCost":3,"op":"PUSH1","pc":2
"depth":3,"gas":73500,"gasCost":12,"op":"MSTORE","pc":4
in call_impl() 77172 ( OPcode cost is already decreased)
gas = 77272
gasLeft = 77172
if (state.rev >= EVMC_BERLIN && state.host.access_account(dst) == EVMC_ACCESS_COLD)
state.gas_left -= 2500 (74672)
msg.gas = min(74672, 74672-(74672/64)) // 73506
msg.gas = 73506
gas-left = 74672
const auto result = state.host.call(msg);
the tracer receives:
msg.gas = 73506
gas-left = 73506
The text was updated successfully, but these errors were encountered: