Skip to content

feature: forc-node state forking #136

@zees-dev

Description

@zees-dev

Feature: State Forking for forc node

Summary

  • Add a forc node local 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-url and optionally pinning to a specific block with --fork-block.
  • Scope the functionality to forc node running 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-core crate exposing the DataSource attributes as pub (rather than pub(crate)) so the forking storage wrapper can be constructed externally.
  • Additional fuel-core-client and fuel-core-storage dependencies are pulled into forc-node to support RPC calls and structured storage helpers.

Prerequisites

  • Blocking: Update the workspace to fuel-core v0.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 DataSource attributes pub (instead of pub(crate))
  • Optional but helpful: Align the fuel-core toolchain 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 from v1.86.0 (which both sway and fuel-core were using). This has introduced compilation errors since a local patch cannot be used for fuel-core dependencies.
  • Additionally mainnet/testnet uses fuel-core v0.46.0, hence the following PR must be merged first.
  • Prior to rust v1.90.0 update, the forking functionality had been tested locally end-to-end by launching a forked local node and using forc-call to 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 upstream fuel-core release 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.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or requestforcforc-nodeEverything related to forc-node, bootstrapping a fuel-core nodeteam:toolingTooling Team

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions