core/vm: make gas cost reporting to tracers correct (#22702)

Previously, the makeCallVariantGasCallEIP2929 charged the cold account access cost directly, leading to an incorrect gas cost passed to the tracer from the main execution loop.
This change still temporarily charges the cost (to allow for an accurate calculation of the available gas for the call), but then afterwards refunds it and instead returns the correct total gas cost to be then properly charged in the main loop.
This commit is contained in:
Martin Holst Swende 2021-04-27 13:21:41 +02:00 committed by Daniel Liu
parent 6c77d63dc2
commit b5fe81f093

View file

@ -177,10 +177,15 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc) gasFunc {
return func(evm *EVM, contract *Contract, stack *Stack, mem *Memory, memorySize uint64) (uint64, error) {
addr := common.Address(stack.Back(1).Bytes20())
// Check slot presence in the access list
if !evm.StateDB.AddressInAccessList(addr) {
warmAccess := evm.StateDB.AddressInAccessList(addr)
// The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost, so
// the cost to charge for cold access, if any, is Cold - Warm
coldCost := ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929
if !warmAccess {
evm.StateDB.AddAddressToAccessList(addr)
// The WarmStorageReadCostEIP2929 (100) is already deducted in the form of a constant cost
if !contract.UseGas(ColdAccountAccessCostEIP2929 - WarmStorageReadCostEIP2929) {
// Charge the remaining difference here already, to correctly calculate available
// gas for call
if !contract.UseGas(coldCost) {
return 0, ErrOutOfGas
}
}
@ -189,7 +194,16 @@ func makeCallVariantGasCallEIP2929(oldCalculator gasFunc) gasFunc {
// - transfer value
// - memory expansion
// - 63/64ths rule
return oldCalculator(evm, contract, stack, mem, memorySize)
gas, err := oldCalculator(evm, contract, stack, mem, memorySize)
if warmAccess || err != nil {
return gas, err
}
// 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.
contract.Gas += coldCost
return gas + coldCost, nil
}
}