-
Notifications
You must be signed in to change notification settings - Fork 0
Description
Feature: State Forking for forc node
Summary
- Add a
forc nodelocal mode that can fork state from a remote Fuel RPC endpoint, similar to Foundry's Anvil for EVM. - Lazily fetch contract bytecode and storage from the fork target, caching retrieved data inside the local node's on-chain database for subsequent interactions.
- Support selecting the fork source via
--fork-urland optionally pinning to a specific block with--fork-block. - Scope the functionality to
forc noderunning in local mode; hosted RPC nodes remain unaffected.
Background / Motivation
forc node is currently limited to synthetic chain state that is configured locally.
State forking would introduce a data source wrapper that proxies missing contract resources to a remote Fuel client, persists the responses in the embedded database, and continues execution locally.
This unlocks workflows where builders can test against mainnet or testnet state without replicating full chain data, enabling fast reproduction of production scenarios.
State forking (at a high level) reuses an existing node's state at a chosen block height. When the local node encounters previously unseen contracts or storage slots, it pulls their bytecode/state over RPC, stores them locally, and then serves all subsequent reads/writes from the local cache.
Any new transactions mined by the local node continue mutating the cached state without affecting the upstream chain.
Proposed Implementation Highlights
CLI surface
--fork-url: Fuel node RPC endpoint to fork from; enabling this flag activates the forking data source.--fork-block: Optional block height to anchor the fork (defaults to latest when omitted).
Runtime behaviour (from the WIP prototype)
- All RPC interfaces stay backward compatible; state forking is an internal storage concern and should not alter existing API semantics.
- External tooling (e.g. scripts, wallets, SDKs) interacting with the local node should observe identical behaviour whether contracts are locally deployed or lazily fetched via forking.
Dependency considerations
- The feature relies on the
fuel-corecrate exposing theDataSourceattributes aspub(rather thanpub(crate)) so the forking storage wrapper can be constructed externally. - Additional
fuel-core-clientandfuel-core-storagedependencies are pulled intoforc-nodeto support RPC calls and structured storage helpers.
Prerequisites
- Blocking: Update the workspace to
fuel-corev0.46.0 (tracked in Bump fuel-core v0.46.0 sway#7445) so the forking changes can consume the latest API surface. - Blocking: Make PR to fuel-core to make the
DataSourceattributespub(instead ofpub(crate)) - Optional but helpful: Align the
fuel-coretoolchain with Rust 1.90.0 (tracked in Bump rust to 1.90 and fuel-vm 0.65.0 fuel-core#3110) to simplify testing local patches alongside the Sway workspace.
Proof of Concept Status
- A proof of concept was available - prior to chore: bumpt rust version to 1.90 sway#7427
- This PR updated rust to
v1.90.0; up fromv1.86.0(which bothswayandfuel-corewere using). This has introduced compilation errors since a local patch cannot be used forfuel-coredependencies.
- This PR updated rust to
- Additionally mainnet/testnet uses
fuel-corev0.46.0, hence the following PR must be merged first. - Prior to rust
v1.90.0update, the forking functionality had been tested locally end-to-end by launching a forked local node and usingforc-callto query and update contract state; once cached, subsequent interactions were indistinguishable from working with locally deployed contracts.
Acceptance Criteria
- Running
forc node --local --fork-url <rpc> [--fork-block <height>]starts a node that transparently pulls contract bytecode/storage from the specified remote endpoint on first access and persists it locally. - Subsequent interactions with forked contracts operate solely on the local cache, including state mutations created after the fork point.
- The feature is covered by integration tests and documented for end users.
- No
[patch.crates-io]overrides remain once the upstreamfuel-corerelease is consumed.
Follow-up
Once merged, we should monitor telemetry / user feedback to decide whether to expand forking support beyond contracts (e.g. UTXOs, messages) and whether to add guardrails for cache size or synchronization with the upstream chain.