Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug(anvil): --cache-path is ignored #9639

Open
2 tasks done
folex opened this issue Jan 7, 2025 · 5 comments
Open
2 tasks done

bug(anvil): --cache-path is ignored #9639

folex opened this issue Jan 7, 2025 · 5 comments
Labels
C-anvil Command: anvil T-bug Type: bug

Comments

@folex
Copy link

folex commented Jan 7, 2025

Component

Anvil

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

  • Foundry
  • Foundryup

What version of Foundry are you on?

forge 0.3.0 (5e72c69 2025-01-07T00:23:20.105032000Z)

What command(s) is the bug in?

anvil --fork-url

Operating System

macOS (Apple Silicon)

Describe the bug

Hello, folks!

It seems that for me, anvil ignores --cache-path:

RUST_LOG=debug,cache=trace anvil --cache-path "/tmp/test" --fork-url https://rpc.testnet.fluence.dev --fork-block-number 295905 --no-rate-limit --fork-chain-id 52164803

2025-01-07T13:37:57.231521Z TRACE cache: reading json cache path="/Users/folex/.foundry/cache/rpc/52164803/295905/storage.json"

^C

2025-01-07T13:38:29.247340Z TRACE flush{path=Some("/Users/folex/.foundry/cache/rpc/52164803/295905/storage.json")}: cache: saving json cache
2025-01-07T13:38:29.247781Z TRACE flush{path=Some("/Users/folex/.foundry/cache/rpc/52164803/295905/storage.json")}: cache: saved json cache
foundryup: installed - forge 0.3.0 (5e72c69 2025-01-07T00:23:20.105032000Z)
foundryup: installed - cast 0.3.0 (5e72c69 2025-01-07T00:23:20.035938000Z)
foundryup: installed - anvil 0.3.0 (5e72c69 2025-01-07T00:23:20.032323000Z)
foundryup: installed - chisel 0.3.0 (5e72c69 2025-01-07T00:23:19.732130000Z)

% anvil --version
anvil 0.3.0 (5e72c69 2025-01-07T00:23:20.032323000Z)

Am I doing something wrong here?

copied from #8654 (comment)

@folex folex added T-bug Type: bug T-needs-triage Type: this issue needs to be labelled labels Jan 7, 2025
@zerosnacks zerosnacks changed the title --cache-path is ignored bug(anvil): --cache-path is ignored Jan 7, 2025
@zerosnacks zerosnacks added C-anvil Command: anvil T-to-investigate Type: to investigate and removed T-needs-triage Type: this issue needs to be labelled labels Jan 7, 2025
@yash-atreya
Copy link
Member

What you see in the trace log: TRACE cache: reading json cache path is the foundry block cache path, which differs from anvil's --cache-path. The former stores the forked block from the remote chain to avoid subsequent calls that require details about this block. (e.g re-initializing the BlockEnv on restart), the latter is --cache-path where your local changes are stored on disk upon exceeding the --max-persisted-states limit. (default: 500 blocks)

@yash-atreya yash-atreya removed the T-to-investigate Type: to investigate label Jan 7, 2025
@folex
Copy link
Author

folex commented Jan 8, 2025

My end goal is to reuse fork's state in tests.

I want Anvil to fork an existing chain, run my tests on Anvil's RPC once, then save the cache/state/snapshot/etc, commit to git, and reuse in the tests so that further test runs enjoy fast Anvil start, ie not wait for the eth_getStorageAt and instead use it from cache.

I've tried different approaches: anvil_dumpState + anvil_loadState did not revive the contract's state for some reason.

So I thought to use the --cache-path instead: take storage.json, put it in my git repo and load on test run. With a possibility for each test to have its own storage.json/cache/snapshot/etc.

Could you please give me some advice on that setup? Is that possible, what's the best way to approach that?

Currently, it seems that the best I can is to put storage.json to ~/.foundry/rpc/cache/... before every test. It is not as local as I'd wish it to be, but could work.

Thank you!

@yash-atreya
Copy link
Member

@folex You'd want to use dumpState and loadState with the --preserve-historical-states flag enabled.

If you're using the API you can do the following:

cast rpc anvil_dumpState true

@folex
Copy link
Author

folex commented Jan 9, 2025

@yash-atreya hm, --preserve-historical-states certainly has changed the behaviour.

Now, after anvil_loadState I see it is doing eth_getCode. That's new!

However, if I do the following

  1. start Anvil as a fork with --preserve-historical-states
  2. run my test – let it fetch storage, code, etc
  3. do dumpState true
  4. stop anvil
  5. remove cache/rpc/.../storage.json
  6. start Anvil with the same fork parameters
  7. do anvil_loadState
  8. run my test

It still goes fetch storage via a bunch of getStorageAt calls, which takes a lot of time – 30-40 seconds in total of ~400 slots.

From what I observe and understand, it seems that only storage.json affects the caching of storage.

If my conclusion is correct, it would be helpful to be able to override the storage.json path!

Another thing I've noticed is that if I start Anvil fork with --state ./anvil, then remove storage.json and restart with the same --state ./anvil, it crashes:

% RUST_LOG=debug,cache=trace anvil --fork-url https://rpc.testnet.fluence.dev --fork-block-number 295904 --no-rate-limit --fork-chain-id 52164803  --state ./anvil

2025-01-09T09:25:43.916704Z DEBUG alloy_rpc_client::call: sending request method=eth_getBlockByNumber id=0
2025-01-09T09:25:44.079025Z DEBUG ReqwestTransport{url=https://rpc.testnet.fluence.dev/}: reqwest::connect: starting new connection: https://rpc.testnet.fluence.dev/
2025-01-09T09:25:44.081215Z DEBUG ReqwestTransport{url=https://rpc.testnet.fluence.dev/}: hyper_util::client::legacy::connect::http: connecting to 34.54.118.37:443
2025-01-09T09:25:44.123112Z DEBUG ReqwestTransport{url=https://rpc.testnet.fluence.dev/}: hyper_util::client::legacy::connect::http: connected to 34.54.118.37:443
2025-01-09T09:25:44.542292Z DEBUG ReqwestTransport{url=https://rpc.testnet.fluence.dev/}: hyper_util::client::legacy::pool: pooling idle connection for ("https", rpc.testnet.fluence.dev)
2025-01-09T09:25:44.542454Z DEBUG ReqwestTransport{url=https://rpc.testnet.fluence.dev/}: alloy_transport_http::reqwest_transport: received response from server status=200 OK
2025-01-09T09:25:44.542757Z DEBUG ReqwestTransport{url=https://rpc.testnet.fluence.dev/}: alloy_transport_http::reqwest_transport: retrieved response body. Use `trace` for full body bytes=1776
2025-01-09T09:25:44.543324Z DEBUG alloy_rpc_client::call: sending request method=eth_gasPrice id=1
2025-01-09T09:25:44.543512Z DEBUG ReqwestTransport{url=https://rpc.testnet.fluence.dev/}: hyper_util::client::legacy::pool: reuse idle connection for ("https", rpc.testnet.fluence.dev)
2025-01-09T09:25:44.898336Z DEBUG ReqwestTransport{url=https://rpc.testnet.fluence.dev/}: hyper_util::client::legacy::pool: pooling idle connection for ("https", rpc.testnet.fluence.dev)
2025-01-09T09:25:44.898459Z DEBUG ReqwestTransport{url=https://rpc.testnet.fluence.dev/}: alloy_transport_http::reqwest_transport: received response from server status=200 OK
2025-01-09T09:25:44.898502Z DEBUG ReqwestTransport{url=https://rpc.testnet.fluence.dev/}: alloy_transport_http::reqwest_transport: retrieved response body. Use `trace` for full body bytes=46
2025-01-09T09:25:44.898720Z TRACE cache: reading json cache path="/Users/folex/.foundry/cache/rpc/52164803/295904/storage.json"
2025-01-09T09:25:44.906070Z TRACE flush{path=Some("/Users/folex/.foundry/cache/rpc/52164803/295904/storage.json")}: cache: saving json cache
2025-01-09T09:25:44.910626Z TRACE flush{path=Some("/Users/folex/.foundry/cache/rpc/52164803/295904/storage.json")}: cache: saved json cache
Error: failed to load init state

Caused by:
    Rpc error RpcError { code: InternalError, message: "Best hash not found for best number 295906", data: None }

Location:
    /Users/runner/work/foundry/foundry/crates/anvil/src/config.rs:1078:45

@folex
Copy link
Author

folex commented Jan 9, 2025

Another unexpected thing is that if I start Anvil not from within a terminal, but from the Rust code like that:

    let _anvil = Anvil::new()
        .fork("https://rpc.testnet.fluence.dev")
        .fork_block_number(295904)
        .args([
            "--no-rate-limit",
            "--fork-chain-id",
            "52164803",
            "--preserve-historical-states",
        ])
        .port(8545u16)
        .try_spawn()?;

It does a lot of eth_blockNumber and eth_getTransactionCount calls, which takes 30-40 seconds in my case.

Anvil started from within terminal works instantly (for the second time).

I wonder, where the difference comes from 🤔

Once I passed RUST_LOG=cache=trace,anvil=trace, I see now it uses the same storage.json:

2025-01-09T09:57:17.490573Z TRACE anvil: line="2025-01-09T09:57:17.490283Z TRACE cache: reading json cache path=\"/Users/folex/.foundry/cache/rpc/52164803/295904/storage.json\"\n"

So there must be some difference in default parameters in anvil-cli-from-terminal and anvil-cli-from-rust :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
C-anvil Command: anvil T-bug Type: bug
Projects
Status: Todo
Development

No branches or pull requests

3 participants