foundry-rs / foundry

Foundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.
https://getfoundry.sh
Apache License 2.0
8.35k stars 1.77k forks source link

Arbitrum fork can't read l2 block number #5085

Open noyyyy opened 1 year ago

noyyyy commented 1 year ago

Component

Forge, Anvil

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

What version of Foundry are you on?

forge 0.2.0 (1caa0fa 2023-05-30T00:11:10.062347000Z)

What command(s) is the bug in?

forge test --mt testGetArbL2BlockNumber -vvvv

Operating System

macOS (Apple Silicon)

Describe the bug

Since block.number on arbitrum is block number on l1, arbitrum has a precompiled address (0x64) to reflect l2 address. Call address(0x64) arbBlockNumber to get l2 block number.

interface ArbSys {
    /**
     * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0)
     * @return block number as int
     */
    function arbBlockNumber() external view returns (uint);
}

Create arbitrum fork and call 0x64 with arbBlockNumber(), it wil revert with "EvmError: InvalidFEOpcode". I think it's just because the foundry evm doesn't fulfill the precompile contract function, but there should be a way to get l2 block number on arbitrum fork. Fulfill it to compatible with arbitrum official implemtation would be great.

A minimal test to reproduce it

interface ArbSys {
    /**
     * @notice Get Arbitrum block number (distinct from L1 block number; Arbitrum genesis block has block number 0)
     * @return block number as int
     */
    function arbBlockNumber() external view returns (uint);
}

contract ArbL2NumberTest is Test {
    function testGetArbL2BlockNumber() public {
        // <https://arbiscan.io/block/75219831>
        vm.createSelectFork("https://rpc.ankr.com/arbitrum", 75219831);

        ArbSys(address(0x64)).arbBlockNumber();
    }
}
mattsse commented 1 year ago

I think it's just because the foundry evm doesn't fulfill the precompile contract function

yes, no precompile for 0x64

what's the code for this precompile?

noyyyy commented 1 year ago

I think it's just because the foundry evm doesn't fulfill the precompile contract function

yes, no precompile for 0x64

what's the code for this precompile?

The precompile 0x64 is call ArbSys and its code is here https://github.com/OffchainLabs/nitro/blob/master/precompiles/ArbSys.go. I think implement some view function is enough for now.

mattsse commented 1 year ago

fyi you can override code like this

https://book.getfoundry.sh/cheatcodes/get-deployed-code?highlight=getDeployedCode#getdeployedcode

noyyyy commented 1 year ago

fyi you can override code like this

https://book.getfoundry.sh/cheatcodes/get-deployed-code?highlight=getDeployedCode#getdeployedcode

I think I can't resolve it by just writing solidity code and setting code to 0x64, since the block.number on arbitrum reflects l1 block number https://github.com/foundry-rs/foundry/blob/a5c27411c7e5d1dd574df758060da8ad501ecbde/evm/src/utils.rs#L171-L182

What I want is l2 block number.

mds1 commented 1 year ago

Related to https://github.com/foundry-rs/foundry/issues/748

ultrasecreth commented 1 year ago

+1 here.

Trying to write a script that deploys some contracts and then records at which block (even if approx) they're deployed. Can't do it without a way of getting the L2 block number

impactdni2 commented 1 year ago

+1 here as well.

Attempting to replay live transactions against anvil and seeing transactions that succeed live, but fail when sent against foundry. For what it's worth, hardhat is also failing for me with what looks to be the same issue.

Reproduction with: https://arbiscan.io/tx/0xfa343658648795c9e430e037974a8e631bb412a4576aef4c7933a73cdf99b658 anvil -f [your_arbitrum_node] --fork-block-number 117853669 curl http://localhost:8545/ -X POST -H "Content-Type: application/json" --data '{"jsonrpc":"2.0","method":"eth_sendRawTransaction","params":["0xf8cc448405f5e1008314c64c940fd60b53b895b0e961523b478abcc476b97fb48f80b864b460af9400000000000000000000000000000000000000000000000000000000000f414a000000000000000000000000acd048081317050d7ba4a6b181578968457df293000000000000000000000000acd048081317050d7ba4a6b181578968457df29383014986a08288b86d6305691d1fed5a626a6e44aa81bdf0d670a467669762ace90dc15423a02e55968f530e45fdd948a472c75478ed379395b26554ac1933bf24ede93d0da6"],"id":1}'

Succeeded on-chain, but fails locally: Transaction: 0xfa343658648795c9e430e037974a8e631bb412a4576aef4c7933a73cdf99b658 Gas used: 1246868 Error: reverted with custom error:

shubham-0536 commented 1 year ago

I am also getting this error.

 ← ()
    ├─ [0] 0x0000000000000000000000000000000000000064::arbBlockNumber() [staticcall]
    │   └─ ← "EvmError: InvalidFEOpcode"
    └─ ← "EvmError: Revert"

Has anyone found a resolution for this issue?

mattsse commented 1 year ago

looks like this is related to arbitrum precompile,

ptal at https://github.com/saucepoint/foundry-arbitrum/

shubham-0536 commented 1 year ago

@mattsse Could you kindly provide more details on how to address this problem? In test cases, there is an already-deployed contract on arbitrum that utilizes arbBlockNumber(), leading to the occurrence of this error.

mattsse commented 1 year ago

hmm,

you could add the precompile call of the arbysys interface

https://docs.arbitrum.io/for-devs/dev-tools-and-resources/precompiles#arbsys https://github.com/OffchainLabs/nitro/blob/v2.0.14/contracts/src/precompiles/ArbSys.sol

to the mock contract

https://github.com/saucepoint/foundry-arbitrum/blob/main/src/ArbitrumTest.sol

that should be a simple PR

ultrasecreth commented 1 year ago

hmm,

you could add the precompile call of the arbysys interface

https://docs.arbitrum.io/for-devs/dev-tools-and-resources/precompiles#arbsys https://github.com/OffchainLabs/nitro/blob/v2.0.14/contracts/src/precompiles/ArbSys.sol

to the mock contract

https://github.com/saucepoint/foundry-arbitrum/blob/main/src/ArbitrumTest.sol

that should be a simple PR

The problem with this approach is that you still can't get the real arbitrum block, the mock can return an arbitrary value, but if you're fork testing (or writing a script) and need to work with the real block, it's not a solution

adamxyzxyz commented 10 months ago

Any updates on this? Also facing this issue.

hanzel98 commented 9 months ago

I'm also facing the issue, I can't specify the block number on Arbitrum on my tests

image_2024-02-12_17-15-10

trojanMcAfee commented 8 months ago

+1 here

mattsse commented 8 months ago

fyi @klkvr prime candiate for chain specific precompile

working on making this possible

ashablovskiy commented 8 months ago

@noyyyy @trojanMcAfee you may try to change Arbitrum chainId to 4216138 (vm.chainId(4216138)), thats worked for me.

josechifflet commented 8 months ago

@ashablovskiy That worked for me aswell, i was struggling with that too! Thanks 🤝