foundry icon indicating copy to clipboard operation
foundry copied to clipboard

`vm.resumeGasMetering` can cause tests with expected reverts to fail with an `OutOfGas` error

Open emo-eth opened this issue 1 year ago • 1 comments

Component

Forge

Have you ensured that all of these are up to date?

  • [X] Foundry
  • [X] Foundryup

What version of Foundry are you on?

forge 0.2.0 (6672134 2023-08-08T00:21:59.824374000Z)

What command(s) is the bug in?

forge test

Operating System

macOS (Apple Silicon)

Describe the bug

After calling vm.pauseGasMetering, calling vm.resumeGasMetering within a reverting external call causes tests to fail with an OutOfGas error.

There seem to broadly be inconsistencies and unexpected behavior with the GasMetering functions; see #5491 as possibly related.

A reproduction, which eliminates self-external-calls as the issue.


import {Test, Vm} from "forge-std/Test.sol";

contract RevertingExternalContract {
    error MyError();

    Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));

    function externalReverts() external {
        vm.resumeGasMetering();
        revert MyError();
    }
}

contract MeteringTest is Test {
    error MyError();

    RevertingExternalContract externalContract;

    function setUp() public {
        externalContract = new RevertingExternalContract();
    }

    function testSelfNormalRevert() public {
        vm.expectRevert(MeteringTest.MyError.selector);
        this.selfReverts();
    }

    function testSelfMeteringRevert() public {
        vm.pauseGasMetering();
        vm.expectRevert(MeteringTest.MyError.selector);
        this.selfReverts();
    }

    function testExternalNormalRevert() public {
        vm.expectRevert(RevertingExternalContract.MyError.selector);
        externalContract.externalReverts();
    }

    function testExternalMeteringRevert() public {
        vm.pauseGasMetering();
        vm.expectRevert(RevertingExternalContract.MyError.selector);
        externalContract.externalReverts();
    }

    function testExternalMeteringManualCheck() public {
        vm.pauseGasMetering();
        (bool success,) = address(this).call(abi.encodeWithSelector(this.selfReverts.selector));
        assertEq(success, false);
    }

    function selfReverts() external {
        vm.resumeGasMetering();
        revert MyError();
    }
}

Output of running these tests:

[PASS] testSelfNormalRevert() (gas: 3953)
Test result: FAILED. 2 passed; 3 failed; 0 skipped; finished in 402.42µs
Ran 1 test suites: 2 tests passed, 3 failed, 0 skipped (5 total tests)

Failing tests:
Encountered 3 failing tests in test/Metering.t.sol:MeteringTest
[FAIL. Reason: EvmError: OutOfGas] testExternalMeteringManualCheck() (gas: 9223372036854754743)
[FAIL. Reason: EvmError: OutOfGas] testExternalMeteringRevert() (gas: 9223372036854754743)
[FAIL. Reason: EvmError: OutOfGas] testSelfMeteringRevert() (gas: 9223372036854754743)

emo-eth avatar Aug 08 '23 16:08 emo-eth