runtimeverification / kontrol

BSD 3-Clause "New" or "Revised" License
56 stars 9 forks source link

Add support for fork Foundry tests #13

Open palinatolmach opened 1 year ago

palinatolmach commented 1 year ago

Related: https://github.com/runtimeverification/evm-semantics/issues/1401

We should consider supporting Foundry fork tests, which would make it easier to reproduce exploits, perform meaningful inter-contract analysis, and simplify the application of FV to the existing test suits that contain fork tests. We can also re-verify the property tests against the updated mainnet state against potentially changing mainnet state (e.g., if other contracts change through a proxy).

The existing workaround is to set the contracts' bytecode using the etch cheatcode (as discussed in https://github.com/runtimeverification/evm-semantics/issues/1401), but that would still require careful reconstruction of the state such as setting storage variables according to their values in a certain block, etc.

Perhaps we might look into re-using the information fetched by Foundry when its run in the fork-test mode:

forge test --fork-url <your_rpc_url>
jinxinglim commented 4 months ago

Things to consider

When we run forge test --fork-url <some_fork_url>, only the necessary storage will be fetched from the forked node.

For example, the following two tests can be found in this fork-testing branch of ercx-kontrol repo: https://github.com/runtimeverification/ercx-kontrol/tree/fork-testing.

    function test_vault_totalSupply() public view {
        // to be fetched from https://etherscan.io/token/0x4c406C068106375724275Cbff028770C544a1333#readContract
        uint256 currentTotalSupply = 403372338086380169872; 
        assertEq(cut4626.totalSupply(), currentTotalSupply);
    }

    function test_balanceOf_highest_holder() public view {
        // to be fetched from https://etherscan.io/token/0x4c406C068106375724275Cbff028770C544a1333#balances
        address highestHolder = 0x096697720056886b905D0DEB0f06AfFB8e4665E5;
        uint256 amount = 184197797095128198548; 
        assertEq(cut4626.balanceOf(highestHolder), amount);
    }

And only the following storage values are retrieved which are found in the file ~/.foundry/cache/rpc/<chain name>/<block number> (see https://book.getfoundry.sh/forge/fork-testing?highlight=fork-url%20cache#forking-mode):

...
    "storage": {
        "0x7109709ecfa91a80626ff3989d68f67f5b1dd12d": {
            "0x6661696c65640000000000000000000000000000000000000000000000000000": "0x0"
        },
        "0x4c406c068106375724275cbff028770c544a1333": {
            "0xf2d41a00f724aafd5389bd9279e365cac950b52aeee06556f9fae36cbce2f7e9": "0x9fc42088948986d94",
            "0x2": "0x15ddea6c54d175ea90"
        }
    },
...

where 0x4c406c068106375724275cbff028770c544a1333 is the address of cut4626, 0xf2d41a00f724aafd5389bd9279e365cac950b52aeee06556f9fae36cbce2f7e9 represents the storage slot of cut4626.balanceOf(highestHolder) and 0x2 represents the storage slot of totalSupply().


If we want kontrol to support --fork-url, it can only be done if:

  1. the test suite is runnable with forge test --fork-url so that we can retrieve the corresponding cache file, or

  2. there exists some other command/s that allow us to fetch the necessary storage values without running forge build/test so that we will not encounter any compilation error in the event that the test suite contains kontrol cheatcodes that are only parsable by kontrol but not forge. For example, error such as "unknown cheatcode with selector 0x25449d64; you may have a mismatch between the Vm interface (likely in forge-std) and the forge version" will occur when you run forge test with kontrol-only cheatcodes.

Useful links/comments