Skip to content

EVM/Exec: prevent fatal erros when intermediate transaction runs out of gas

Context

Fixes #6731 (closed).

Based on !11276 (merged).

This increased the successful tests from ethereum/tests by +1591. With !11276 (merged) it adds up to +3482, which increase the overall confidence from 35% to 61.5% (+26.5%).

With the help of the evm-evaluation-assesor I was able to identify a bug where an intermediate call from a smart contract call would kill/exit the entire execution if the intermediate state ended up with an OutOfGas error, to some extent this should not happen.

An intermediate call can have a gas value to the sub-context where the execution is done. This does not mean that an OutOfGas error should end the entire transaction as there could still be other execution to proceed and still enough gas at one level above the depth where the OOG error happens.

The error can be clearly seen in the execution of the third test of sstore_combinations_initial00_2 (from ethereum/tests).

> evm-evaluation-assessor --eth-tests ~/ethereum/tests/ -o tests.logs -t sstore_combinations_initial00_2

Look out for:

  • GeneralStateTests/stTimeConsuming/sstore_combinations_initial00_2.json
  • src/GeneralStateTestsFiller/stTimeConsuming/sstore_combinations_initial00_2Filler.json

More precisely the yul code of the third data in the filler file is quite useful:

// Base execution is triggered with (0x1e8480) 2 000 000 gas

{
    (MSTORE 100 428)
    (CALL 300000 0xb000000000000000000000000000000000000000 0 0 32 0 0)
    (DELEGATECALL 300000 0x3000000000000000000000000000000000000000 0 0 0 0)
    (DELEGATECALL 300000 0xb000000000000000000000000000000000000000 0 32 0 0)
    (DELEGATECALL 300000 0x2000000000000000000000000000000000000000 0 0 0 0) // ==> OOG
    (CALL 600000 0x2000000000000000000000000000000000000000 0 0 0 0 0) // ==> Should be executed but is not
}

Here's a dummy example on Sepolia, this is smart-contract that will return an OOG error on the first call and succeed on the second call if the base call was made with enough gas:

pragma solidity ^0.8.20;

contract TestEthLink {
    function sendViaCall(address payable _to) public payable {
        (bool sent, bytes memory data) = _to.call{gas: 1, value: msg.value}("");
        (bool sent_0, bytes memory data_0) = _to.call{value: msg.value}("");
    }
}

Contract is https://sepolia.etherscan.io/address/0xae549ae286998da6c9e1860c48431a88e5984fbe.

Execution succeed with a warning as expected https://sepolia.etherscan.io/tx/0xc2419854d481adbf150889df84d3447b5df11f8eb89651f8ad3118973abad906.

image

Here's also a stack-detailed execution https://sepolia.etherscan.io/vmtrace?txhash=0xc2419854d481adbf150889df84d3447b5df11f8eb89651f8ad3118973abad906.

Adding this link for more context:

Manually testing the MR

Run the evm-evaluation-assessor on sstore_combinations_initial00_2 before and after the patch (look out for the third test in particular):

> evm-evaluation-assessor --eth-tests ~/ethereum/tests/ -o tests.logs -t sstore_combinations_initial00_2

Run this tezt test:

dune exec tezt/tests/main.exe -- --file evm_rollup.ml out_of_gas call

Checklist

  • Document the interface of any function added or modified (see the coding guidelines)
  • Document any change to the user interface, including configuration parameters (see node configuration)
  • Provide automatic testing (see the testing guide).
  • For new features and bug fixes, add an item in the appropriate changelog (docs/protocols/alpha.rst for the protocol and the environment, CHANGES.rst at the root of the repository for everything else).
  • Select suitable reviewers using the Reviewers field below.
  • Select as Assignee the next person who should take action on that MR
Edited by Rodi-Can Bozman

Merge request reports