Skip to content

gasleft() returns incorrect value within calback #5621

Open
@zaqk

Description

@zaqk

Component

Forge

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

  • Foundry
  • Foundryup

What version of Foundry are you on?

forge 0.2.0 (dffdfde 2023-08-14T00:22:15.788827000Z)

What command(s) is the bug in?

forge test

Operating System

macOS (Apple Silicon)

Describe the bug

It seems that gasleft() is returning an extremely high gas usage amount within a function callback. I ran into this issue when trying to measure gas usage in a UniswapV3Pool callback.

Heres an example that you can test with forge test:

contract Callback {
    function execute(uint256 startGas) external returns (uint256, uint256) {
        uint256 g1 = GasTester(msg.sender).callbackResponse(startGas); // inaccurate value
        uint256 g2 = startGas - gasleft(); // inaccurate value
        return (g1, g2);
    }
}

contract GasTester {

    Callback callback;

    constructor() {
        callback = new Callback();
    }

    function run() public returns (uint256, uint256, uint256, uint256, uint256) {
        uint256 startGas = gasleft();  // accurate value

        // use some gas
        require(msg.sender == msg.sender && msg.sender != address(0));

        uint256 g0 = startGas - gasleft(); // accurate value


        (uint256 g1, uint256 g2) = callback.execute(startGas); // inaccurate values

        uint256 g3 = startGas - gasleft(); // accurate value


        return (startGas, g0, g1, g2, g3);
    }

    function callbackResponse(uint256 startGas) external returns (uint256) {
        return startGas - gasleft(); // inaccurate value
    }

}

the test case:

    function test_gas() public {
        GasTester gasTester = new GasTester();
        (uint256 startGas, uint256 g0, uint256 g1, uint256 g2, uint256 g3) = gasTester.run();
        console2.log("startGas", startGas);
        console2.log("g0", g0);
        console2.log("g1", g1);
        console2.log("g2", g2);
        console2.log("g3", g3);
    }

and finally the log output:

[PASS] test_gas() (gas: 291458)
Logs:
  startGas 9079256848778620484
  g0 26
  g1 281510161082736559
  g2 141863388262167292
  g3 1732

Test result: ok. 1 passed; 0 failed; 0 skipped; finished in 2.64ms
Ran 1 test suites: 1 tests passed, 0 failed, 0 skipped (1 total tests)

It seems that any gas usage calculated using gasleft() is accurate but if execution context changes gasleft() becomes extremely large. g0 ad g3 are accurate while g1 and g2 which are calculated in a callback or a separate contract are inaccurate.

I also ran into this previously closed issue which may be related (not 100% sure):
#3863

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status

    Todo

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions