Skip to content

fix: ensure the result state tree is loadable in ForestStateCompute#6871

Merged
hanabi1224 merged 7 commits intomainfrom
hm/verify-result-state-tree
Apr 8, 2026
Merged

fix: ensure the result state tree is loadable in ForestStateCompute#6871
hanabi1224 merged 7 commits intomainfrom
hm/verify-result-state-tree

Conversation

@hanabi1224
Copy link
Copy Markdown
Contributor

@hanabi1224 hanabi1224 commented Apr 8, 2026

Summary of changes

There's a chance that an incomplete state tree presents (e.g. from bad/wrong diff snapshot import). ForestStateCompute should verify the result state tree is loadable and recompute when needed.

Changes introduced in this pull request:

Reference issue to close (if applicable)

Closes

Other information and links

Change checklist

  • I have performed a self-review of my own code,
  • I have made corresponding changes to the documentation. All new code adheres to the team's documentation standards,
  • I have added tests that prove my fix is effective or that my feature works (if possible),
  • I have made sure the CHANGELOG is up-to-date. All user-facing changes should be reflected in this document.

Outside contributions

  • I have read and agree to the CONTRIBUTING document.
  • I have read and agree to the AI Policy document. I understand that failure to comply with the guidelines will lead to rejection of the pull request.

Summary by CodeRabbit

  • New Features

    • Added a --force option to the state compute command to explicitly force recomputation.
  • Bug Fixes

    • State compute now prefers and validates cached state when possible, and automatically recomputes and revalidates when cache is invalid or missing to ensure correct results and avoid unnecessary work.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 8, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 512475b1-d92b-4111-b8a9-c37b7da3b3b1

📥 Commits

Reviewing files that changed from the base of the PR and between 88714f2 and 3a69e66.

⛔ Files ignored due to path filters (2)
  • src/rpc/snapshots/forest__rpc__tests__rpc__v0.snap is excluded by !**/*.snap
  • src/rpc/snapshots/forest__rpc__tests__rpc__v1.snap is excluded by !**/*.snap
📒 Files selected for processing (2)
  • src/cli/subcommands/state_cmd.rs
  • src/rpc/methods/state.rs
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/cli/subcommands/state_cmd.rs
  • src/rpc/methods/state.rs

Walkthrough

Forest.StateCompute RPC gains an optional force_recompute parameter (default false). When false it tries to reuse a cached executed tipset’s state_root and validates it with StateTree::new_from_root(...); otherwise (or on validation failure) it recomputes state via compute_tipset_state(...). CLI and CHANGELOG updated to expose --force.

Changes

Cohort / File(s) Summary
RPC: State compute
src/rpc/methods/state.rs
Forest.StateCompute upgraded RpcMethod<2>RpcMethod<3); params now (epoch, n_epochs, force_recompute) (Option<bool>). Attempts ctx.state_manager.load_executed_tipset(&ts) and StateTree::new_from_root(...) when force_recompute is false; falls back to compute_tipset_state(ts, NO_CALLBACK, VMTrace::NotTraced) and validates recomputed root. Updates DESCRIPTION and imports including NO_CALLBACK.
CLI
src/cli/subcommands/state_cmd.rs
Adds --force flag to StateCommands::Compute (force: bool) and sends (epoch, n_epochs, Some(force)) in RPC request to trigger recompute when requested.
Changelog
CHANGELOG.md
Adds unreleased entry documenting --force for forest-cli state compute.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI
  participant RPC as Forest.StateCompute
  participant SM as StateManager
  participant VM as VM / compute_tipset_state
  participant ST as StateTree

  CLI->>RPC: request(epoch, n_epochs, force_recompute)
  alt force_recompute == false
    RPC->>SM: load_executed_tipset(ts)
    SM-->>RPC: ExecutedTipset(state_root) / None
    alt received state_root
      RPC->>ST: StateTree::new_from_root(state_root)
      alt valid
        ST-->>RPC: OK
        RPC-->>CLI: return cached state_root
      else invalid
        ST-->>RPC: Err
        RPC->>VM: compute_tipset_state(ts, NO_CALLBACK, NotTraced)
        VM-->>RPC: computed_state_root
        RPC->>ST: StateTree::new_from_root(computed_state_root)
        ST-->>RPC: OK
        RPC-->>CLI: return recomputed state_root
      end
    else no cached
      RPC->>VM: compute_tipset_state(ts, NO_CALLBACK, NotTraced)
      VM-->>RPC: computed_state_root
      RPC->>ST: StateTree::new_from_root(computed_state_root)
      ST-->>RPC: OK
      RPC-->>CLI: return recomputed state_root
    end
  else force_recompute == true
    RPC->>VM: compute_tipset_state(ts, NO_CALLBACK, NotTraced)
    VM-->>RPC: computed_state_root
    RPC->>ST: StateTree::new_from_root(computed_state_root)
    ST-->>RPC: OK
    RPC-->>CLI: return recomputed state_root
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • PR #5946: Earlier change to Forest.StateCompute arity/multi-epoch behavior — touches the same RPC and CLI surfaces.
  • PR #6073: Adjusts StateTree loading/validation/error handling used by this change.
  • PR #6018: Modifies tipset selection/handling for edge/null epochs in the same RPC flow.

Suggested reviewers

  • akaladarshi
  • LesnyRumcajs
  • elmattic
🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: adding verification to ensure the result state tree is loadable in ForestStateCompute, which is the core fix implemented across all modified files.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hm/verify-result-state-tree
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch hm/verify-result-state-tree

Comment @coderabbitai help to get the list of available commands and usage tips.

@hanabi1224 hanabi1224 added the RPC requires calibnet RPC checks to run on CI label Apr 8, 2026
@hanabi1224 hanabi1224 marked this pull request as ready for review April 8, 2026 06:42
@hanabi1224 hanabi1224 requested a review from a team as a code owner April 8, 2026 06:42
@hanabi1224 hanabi1224 requested review from LesnyRumcajs and akaladarshi and removed request for a team April 8, 2026 06:42
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
src/rpc/methods/state.rs (1)

1592-1603: Sound defensive logic for handling incomplete state trees.

The approach of validating the cached state tree and falling back to recomputation is appropriate for the stated objective of handling bad/wrong diff snapshot imports.

Two minor suggestions:

  1. Add error context on line 1601 — per coding guidelines, errors should include context for debuggability.

  2. Optional: Add a debug/info log when fallback occurs — this would help diagnose when incomplete state trees are encountered in production.

🔧 Proposed refinement
 let ExecutedTipset { state_root, .. } =
     ctx.state_manager.load_executed_tipset(&ts).await?;
 let state_root = if StateTree::new_from_root(ctx.store_owned(), &state_root).is_ok() {
     state_root
 } else {
+    tracing::debug!(epoch = ts.epoch(), "Cached state tree unloadable, recomputing");
     let ExecutedTipset { state_root, .. } = ctx
         .state_manager
         .compute_tipset_state(ts, NO_CALLBACK, VMTrace::NotTraced)
         .await?;
-    _ = StateTree::new_from_root(ctx.store_owned(), &state_root)?;
+    _ = StateTree::new_from_root(ctx.store_owned(), &state_root)
+        .context("recomputed state tree is not loadable")?;
     state_root
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/rpc/methods/state.rs` around lines 1592 - 1603, The code validates a
cached state root by calling StateTree::new_from_root and falls back to
ctx.state_manager.compute_tipset_state; add contextual error messages and a
fallback log: when the second StateTree::new_from_root(...)? is used, wrap its
error with context (e.g., include the tipset id/ts and mention "failed
validating recomputed state root") so the propagated error includes debug info,
and insert a debug/info log right before calling compute_tipset_state(...)
indicating fallback due to invalid cached state (referencing ExecutedTipset,
StateTree::new_from_root, compute_tipset_state, ctx.state_manager,
ctx.store_owned, NO_CALLBACK, VMTrace::NotTraced).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/rpc/methods/state.rs`:
- Around line 1592-1603: The code validates a cached state root by calling
StateTree::new_from_root and falls back to
ctx.state_manager.compute_tipset_state; add contextual error messages and a
fallback log: when the second StateTree::new_from_root(...)? is used, wrap its
error with context (e.g., include the tipset id/ts and mention "failed
validating recomputed state root") so the propagated error includes debug info,
and insert a debug/info log right before calling compute_tipset_state(...)
indicating fallback due to invalid cached state (referencing ExecutedTipset,
StateTree::new_from_root, compute_tipset_state, ctx.state_manager,
ctx.store_owned, NO_CALLBACK, VMTrace::NotTraced).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e85008e9-5e61-4800-878b-649245822ab1

📥 Commits

Reviewing files that changed from the base of the PR and between 4cfb27b and 701bd69.

📒 Files selected for processing (1)
  • src/rpc/methods/state.rs

@codecov
Copy link
Copy Markdown

codecov Bot commented Apr 8, 2026

Codecov Report

❌ Patch coverage is 0% with 19 lines in your changes missing coverage. Please review.
✅ Project coverage is 64.04%. Comparing base (19d1045) to head (3a69e66).
⚠️ Report is 5 commits behind head on main.
✅ All tests successful. No failed tests found.

Files with missing lines Patch % Lines
src/rpc/methods/state.rs 0.00% 16 Missing ⚠️
src/cli/subcommands/state_cmd.rs 0.00% 3 Missing ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
src/cli/subcommands/state_cmd.rs 0.00% <0.00%> (ø)
src/rpc/methods/state.rs 45.90% <0.00%> (-0.35%) ⬇️

... and 13 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 755b8e0...3a69e66. Read the comment docs.

🚀 New features to boost your workflow:
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@akaladarshi
Copy link
Copy Markdown
Collaborator

@hanabi1224 Shouldn't this API always re-compute regardless if the state root is present or not?

Also can you add some documentation for the ForestStateCompute API so we can differentiate with StateCompute.

LesnyRumcajs
LesnyRumcajs previously approved these changes Apr 8, 2026
@hanabi1224
Copy link
Copy Markdown
Contributor Author

hanabi1224 commented Apr 8, 2026

@hanabi1224 Shouldn't this API always re-compute regardless if the state root is present or not?

Also can you add some documentation for the ForestStateCompute API so we can differentiate with StateCompute.

@akaladarshi description added. This one is typically used by forest-cli state compute to backfill state trees in batches, cache would help speed up the process. load_executed_tipset verifies all useful side products of state computation (message receipts and events) and this PR verifies the result state tree as well so in terms of effect, the change should be a performance optimization with equevilant result and side products. Does that make sense?

Update:
Added another force_recompute parameter to bypass cache

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/rpc/methods/state.rs`:
- Around line 1532-1534: Update the DESCRIPTION constant string to accurately
reflect actual behavior: state cache is only reused when
StateTree::new_from_root(...) succeeds (make explicit that cache reuse depends
on successful state tree reconstruction), and explain that this Forest-specific
range recomputation uses on-chain messages from the tipsets rather than
caller-supplied messages (contrast with Filecoin.StateCompute). Edit the
DESCRIPTION const to include both points and reference StateTree::new_from_root
and Filecoin.StateCompute so readers understand the difference.
- Around line 1597-1604: When rebuilding the state root fails, wrap the errors
from StateTree::new_from_root and state_manager.compute_tipset_state with
context including the tipset epoch so callers know which epoch failed; modify
the branch that currently calls StateTree::new_from_root(ctx.store_owned(),
&state_root) and the call to ctx.state_manager.compute_tipset_state(ts,
NO_CALLBACK, VMTrace::NotTraced).await to use .context(format!("... epoch {}",
ts.epoch())) (or similar) on the Result so both the StateTree::new_from_root and
compute_tipset_state failures include the epoch in their anyhow::Error context.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: e1c0551a-c12c-4a25-a1ef-e0e13b1ca916

📥 Commits

Reviewing files that changed from the base of the PR and between 701bd69 and 196ad00.

⛔ Files ignored due to path filters (2)
  • src/rpc/snapshots/forest__rpc__tests__rpc__v0.snap is excluded by !**/*.snap
  • src/rpc/snapshots/forest__rpc__tests__rpc__v1.snap is excluded by !**/*.snap
📒 Files selected for processing (1)
  • src/rpc/methods/state.rs

Comment thread src/rpc/methods/state.rs
Comment thread src/rpc/methods/state.rs Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/cli/subcommands/state_cmd.rs`:
- Around line 37-38: The force field in the CLI struct (field name: force) is
currently an Option<bool> and missing the #[arg(long)] attribute so clap treats
it as a positional; update the declaration for the force field by adding the
#[arg(long)] attribute and make it a simple bool (false by default, true when
--force is passed) to behave as a proper --force flag used by the state command
handlers (look for the struct that defines force in state_cmd.rs and its
usages).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 3c3265c3-deb9-4696-b4df-afe6cb30618e

📥 Commits

Reviewing files that changed from the base of the PR and between 196ad00 and 88714f2.

⛔ Files ignored due to path filters (2)
  • src/rpc/snapshots/forest__rpc__tests__rpc__v0.snap is excluded by !**/*.snap
  • src/rpc/snapshots/forest__rpc__tests__rpc__v1.snap is excluded by !**/*.snap
📒 Files selected for processing (3)
  • CHANGELOG.md
  • src/cli/subcommands/state_cmd.rs
  • src/rpc/methods/state.rs
✅ Files skipped from review due to trivial changes (1)
  • CHANGELOG.md

Comment thread src/cli/subcommands/state_cmd.rs Outdated
@hanabi1224 hanabi1224 enabled auto-merge April 8, 2026 10:30
@hanabi1224 hanabi1224 added this pull request to the merge queue Apr 8, 2026
Merged via the queue into main with commit 86c73fa Apr 8, 2026
79 of 80 checks passed
@hanabi1224 hanabi1224 deleted the hm/verify-result-state-tree branch April 8, 2026 10:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

RPC requires calibnet RPC checks to run on CI

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants