feature: `forc-node` state forking
- Dominant language
- Rust
- Stars
- 0
- Forks
- 0
- Avg merge
- 1d 22h
- Merged PRs (30d)
- 3
Description
# 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](https://github.com/FuelLabs/fuel-core/blob/f60a0bcf96ef7c392ddb9fb7b8c4a2652db72ea3/crates/fuel-core/src/state/data_source.rs#L31) 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 https://github.com/FuelLabs/sway/pull/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 https://github.com/FuelLabs/fuel-core/pull/3110) to simplify testing local patches alongside the Sway workspace.
## Proof of Concept Status
- A proof of concept was available - prior to https://github.com/FuelLabs/sway/pull/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](https://github.com/FuelLabs/sway/pull/7445) 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 [--fork-block ]` 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.
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.