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.
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