GasCost calculation mismatch for opCode CALL/STATICCALL with RPCdaemon
Executing the debug_traceTransaction call using the following input:
{
"jsonrpc":"2.0",
"method":"debug_traceTransaction",
"params":[
"0xeb3803f052e817e41e381b5ac150d0967e37b2e298d9a1dc079750abeeafbead",
{
"disableStorage": false,
"disableMemory": false,
"disableStack": false
}
],
"id":1
}
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)
cost += dynamicCost // total cost, for debug tracing
if err != nil || !contract.UseGas(dynamicCost) {
return nil, ErrOutOfGas
}
}
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:
- gas = <gasLeft>
- gasLeft = <gasLeft-costoOpcode>
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