Skip to content

Conversation

@zees-dev
Copy link
Contributor

@zees-dev zees-dev commented Oct 31, 2025

Description

Addresses #7448

This pull request introduces state forking support to the local node in forc-node, allowing developers to run a local node that mirrors the contract state from a remote node at latest block height (currently only latest is supported).

The contract bytecode and state is fetched dynamically (at runtime - from specified forked url) as the state is requested.

State Forking Feature

  • Added fork_url and fork_block_number to forc-node local, enabling users to specify a remote node and block height for state forking (it must support historical execution).
  • Refactored local/mod.rs to support state forking by integrating a new fork module, which handles fetching state from the remote node and merging it with local storage. The node now conditionally initializes with forking logic based on user input.

Dependency and Build Updates

  • Updated Cargo.toml and forc-node/Cargo.toml to use patched versions of fuel-core crates from a specific branch
    • This was required as we need to override the datasource in the combined database; the datasource attributes are private; the fuel-core v0.46.0 patch simply updates the visibility of the relevant attributes so that they can be overriden to provide fork functionality
  • Made the block_on_any_runtime function in forc-pkg/src/source/reg/mod.rs public, allowing it to be used outside its original module
    • This is necessary for async operations in the new forking logic since the overriden trait function impls are not async

Testing and Examples

  • Added new test contracts and supporting files (fork and fork-caller) to demonstrate and validate the state forking capability.

These updates collectively enable local development nodes to fork contract state from a remote node, greatly enhancing testing flexibility and realism for smart contract developers.

Related PR: FuelLabs/fuel-core#3134

Checklist

  • I have linked to any relevant issues.
  • I have commented my code, particularly in hard-to-understand areas.
  • I have updated the documentation where relevant (API docs, the reference, and the Sway book).
  • I have added tests that prove my fix is effective or that my feature works.
  • I have added (or requested a maintainer to add) the necessary Breaking* or New Feature labels where relevant.
  • I have done my best to ensure that my PR adheres to the Fuel Labs Code Review Standards.
  • I have requested a review from the relevant team or maintainers.

Note

Adds state forking to forc-node local via --fork-url/--fork-block-number, fetching contract bytecode/state on demand and persisting locally, with tests, docs, and dependency updates.

  • forc-node:
    • Local forking: New flags --fork-url and --fork-block-number enable mirroring contract state from a remote node; lazily fetches contract bytecode/storage and caches in local DB.
    • Storage plumbing: Introduces ForkingOnChainStorage/ForkClient and reconstructs CombinedDatabase to overlay remote state; supports non-interactive mode for config updates.
  • Chain config & utils:
    • check_and_update_chain_config supports non-interactive flows; block_on_any_runtime made public for blocking async calls from sync contexts.
  • Tests:
    • Adds integration tests and example contracts (fork, fork-caller) validating bytecode/state forking and transitive calls; updates EVM tests to newer revm API.
  • Docs:
    • New "Testing with Forc Node" guide and SUMMARY entry; spelling list updated (e.g., AMM, RocksDB).
  • Dependencies:
    • Patches fuel-core* crates to git master; bumps revm and enables features; aligns Cargo.toml/dev-deps accordingly.

Written by Cursor Bugbot for commit d6c6bd9. This will update automatically on new commits. Configure here.

@zees-dev zees-dev force-pushed the feat/forc-node-local-state-forking branch from 6fef5a7 to 5593f9b Compare October 31, 2025 03:33
@zees-dev zees-dev self-assigned this Oct 31, 2025
@zees-dev zees-dev added enhancement New feature or request forc dev-experience Anything to do with the developer experience team:tooling Tooling Team forc-node Everything related to forc-node, bootstrapping a fuel-core node labels Oct 31, 2025
@codspeed-hq
Copy link

codspeed-hq bot commented Oct 31, 2025

CodSpeed Performance Report

Merging #7478 will not alter performance

Comparing feat/forc-node-local-state-forking (f23981d) with master (ec51769)

Summary

✅ 25 untouched

@zees-dev zees-dev marked this pull request as ready for review October 31, 2025 05:35
@zees-dev zees-dev requested review from a team as code owners October 31, 2025 05:35

[[package]]
name = "std"
version = "0.69.1"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seem to be using outdated version of forc

@JoshuaBatty
Copy link
Member

Nice, this is looking really promising. It'd be great to also write up some documentation to include with this PR, stepping through an example use case of when and how to use this feature. Maybe in the same sort of vein as what we have written up for forc debug.

@zees-dev zees-dev requested review from a team as code owners November 4, 2025 08:17
Copy link
Member

@kayagokalp kayagokalp left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very excited for this! We also might want to make sure we depend on std via path instead of registry in the test. That way std will keep up-to-date with the repo for the tests.

Copy link

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This PR is being reviewed by Cursor Bugbot

Details

Your team is on the Bugbot Free tier. On this plan, Bugbot will review limited PRs each billing cycle for each member of your team.

To receive Bugbot reviews on all of your PRs, visit the Cursor dashboard to activate Pro and start your 14-day free trial.

Ok(exists)
} else {
Ok(false)
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Inconsistent Key Slicing Causes Panics

The exists method for Column::ContractsRawCode attempts to slice key[..32] without first checking if key.len() >= 32. This causes a panic when the key is shorter than 32 bytes. The other methods (size_of_value, get, read) have the same issue. In contrast, Column::ContractsState correctly checks key.len() == 64 before slicing, preventing out-of-bounds access.

Fix in Cursor Fix in Web

xgreenx added a commit to FuelLabs/fuel-core that referenced this pull request Nov 18, 2025
## Description

This pull request makes a small change to the visibility of struct
fields in the `DataSource` struct.
The fields `data` and `stage` are now public, which allows them to be
accessed from outside the module.

Currently there is no way to override these attributes with custom
values externally.
This is required for FuelLabs/sway#7478 - as we
override these attributes to enable contract state forking in the PR.

## Checklist
- [ ] Breaking changes are clearly marked as such in the PR description
and changelog
- [ ] New behavior is reflected in tests
- [ ] [The specification](https://github.com/FuelLabs/fuel-specs/)
matches the implemented behavior (link update PR if changes are needed)

### Before requesting review
- [x] I have reviewed the code myself
- [ ] I have created follow-up issues caused by this PR and linked them
here

### After merging, notify other teams

[Add or remove entries as needed]

- [ ] [Rust SDK](https://github.com/FuelLabs/fuels-rs/)
- [x] [Sway compiler](https://github.com/FuelLabs/sway/)
- [ ] [Platform
documentation](https://github.com/FuelLabs/devrel-requests/issues/new?assignees=&labels=new+request&projects=&template=NEW-REQUEST.yml&title=%5BRequest%5D%3A+)
(for out-of-organization contributors, the person merging the PR will do
this)

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> Expose `DataSource` fields `data` and `stage` publicly and add
corresponding changelog entry.
> 
> - **State**:
> - `crates/fuel-core/src/state/data_source.rs`: Make `DataSource`
fields `data` and `stage` public.
> - **Changelog**:
> - `.changes/changed/3134.md`: Add entry noting public visibility of
`DataSource` fields.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
ab6b0e3. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: z <[email protected]>
Co-authored-by: Green Baneling <[email protected]>
@zees-dev zees-dev deployed to fuel-sway-bot November 26, 2025 10:54 — with GitHub Actions Active
@cursor
Copy link

cursor bot commented Nov 26, 2025

PR Summary

Adds state forking to forc-node local, lazily fetching contract bytecode/state from a remote node and persisting locally, with flags to configure the fork and comprehensive tests/docs.

  • forc-node (local):
    • Add state forking via --fork-url and --fork-block-number; persist to RocksDB; supports --historical-execution.
    • Implement ForkClient and ForkingOnChainStorage to lazily fetch contract bytecode/state from a remote GraphQL endpoint and cache locally; integrate by rebuilding CombinedDatabase with forked on-chain storage.
    • Add --non-interactive to local/testnet/ignition paths and auto chain-config updates; refactor check_and_update_chain_config to accept non-interactive mode.
  • Core utilities:
    • Expose forc-pkg::source::reg::block_on_any_runtime for blocking async calls inside storage wrappers.
  • Dependencies:
    • Patch fuel-core crates to git master and update revm usage in tests.
  • Tests:
    • Add fork demo contracts (fork, fork-caller) and E2E tests validating bytecode/state hydration, state isolation, and transitive calls; update health check test.
  • Docs:
    • New guide: "Testing with Forc Node" including fork workflow; update SUMMARY and spellcheck list.

Written by Cursor Bugbot for commit f23981d. This will update automatically on new commits. Configure here.

let port = portpicker::pick_unused_port().expect("pick port");

let db_path = tempfile::tempdir()
.expect("Failed to create temp dir for tests")
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Temporary directory deleted immediately after path extraction

The run_node function creates a temporary directory with tempfile::tempdir(), extracts its path, but immediately drops the TempDir handle. When TempDir is dropped, it automatically deletes the directory. The resulting db_path therefore points to a non-existent directory when passed to LocalCmd for RocksDB storage. The TempDir handle needs to be kept alive for the duration the directory is needed, or into_path() can be used to take ownership of the path without auto-deletion.

Fix in Cursor Fix in Web

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dev-experience Anything to do with the developer experience enhancement New feature or request forc forc-node Everything related to forc-node, bootstrapping a fuel-core node team:tooling Tooling Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants