Skip to content

fix(rpc): backfill tipset messages from p2p network in a few RPC methods#6421

Merged
LesnyRumcajs merged 6 commits intomainfrom
hm/rpc-backfill-full-tipsets
Jan 15, 2026
Merged

fix(rpc): backfill tipset messages from p2p network in a few RPC methods#6421
LesnyRumcajs merged 6 commits intomainfrom
hm/rpc-backfill-full-tipsets

Conversation

@hanabi1224
Copy link
Copy Markdown
Contributor

@hanabi1224 hanabi1224 commented Jan 14, 2026

Summary of changes

Changes introduced in this pull request:

  • backfill tipset messages from p2p network when FOREST_RPC_BACKFILL_FULL_TIPSET_FROM_NETWORK=1

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.

Summary by CodeRabbit

  • Refactor

    • Removed an optional in-memory tipset reconstruction path; RPC handlers now use a single async tipset resolution flow.
  • New Features

    • Added FOREST_RPC_BACKFILL_FULL_TIPSET_FROM_NETWORK env var to optionally backfill full tipsets from the network.
  • API

    • Public surface expanded with a centralized tipset retrieval helper for consistent usage across RPCs.

✏️ Tip: You can customize this high-level summary in your review settings.

@hanabi1224 hanabi1224 added the RPC requires calibnet RPC checks to run on CI label Jan 14, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Jan 14, 2026

Walkthrough

Removed Tipset::fill_from_blockstore. RPC message-loading was changed to asynchronously resolve full tipsets via get_full_tipset or load_full_tipset (env-toggleable backfill). RPC handler bounds and chain_sync re-exports updated accordingly.

Changes

Cohort / File(s) Summary
Tipset API
src/blocks/tipset.rs
Removed pub fn fill_from_blockstore(&self, store: &impl Blockstore) -> Option<FullTipset>.
Module re-exports
src/chain_sync/mod.rs
Re-export list updated to include get_full_tipset alongside load_full_tipset and ChainFollower.
RPC handlers & helpers
src/rpc/methods/chain.rs
Added imports: get_full_tipset, load_full_tipset, is_env_truthy. ChainGetParentMessages and ChainGetMessagesInTipset handlers now require Blockstore + Send + Sync + 'static. load_api_messages_from_tipset converted from a sync store-based helper to async load_api_messages_from_tipset<DB: Blockstore + Send + Sync + 'static>(ctx: &RPCState<DB>, tipset_keys: &TipsetKey), resolving full tipsets via get_full_tipset (network backfill) or load_full_tipset (local).
Docs
docs/docs/users/reference/env_variables.md, docs/dictionary.txt
Added FOREST_RPC_BACKFILL_FULL_TIPSET_FROM_NETWORK env var entry and added backfill to dictionary.
Changelog
CHANGELOG.md
Added unreleased entry describing the new env var for RPC backfill behavior.

Sequence Diagram(s)

sequenceDiagram
    participant Client as RPC Client
    participant RPC as RPC handler (RPCState)
    participant ChainSync as chain_sync (get_full_tipset / load_full_tipset)
    participant Store as Blockstore / ChainStore
    participant Network as P2P Network

    Client->>RPC: ChainGetParentMessages / ChainGetMessagesInTipset request
    RPC->>ChainSync: resolve full tipset (tipset_key, ctx)
    alt SHOULD_BACKFILL (env enabled)
        ChainSync->>Network: request full tipset / missing blocks
        Network-->>ChainSync: full tipset (blocks + messages)
    else local-only
        ChainSync->>Store: load persisted full tipset
        Store-->>ChainSync: full tipset (blocks + messages)
    end
    ChainSync-->>RPC: FullTipset
    RPC->>RPC: extract messages, dedupe -> ApiMessage list
    RPC-->>Client: respond with messages
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • LesnyRumcajs
  • sudo-shashank
🚥 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 summarizes the main change: adding network-based backfilling of tipset messages in RPC methods via an environment variable.

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

✨ Finishing touches
  • 📝 Generate docstrings

🧹 Recent nitpick comments
src/rpc/methods/chain.rs (1)

1319-1342: Verify backfill call won’t hang RPCs + consider local-first fallback when env is enabled.
Right now, when FOREST_RPC_BACKFILL_FULL_TIPSET_FROM_NETWORK is truthy, you always go through get_full_tipset(...). Please confirm:

  • get_full_tipset has bounded timeouts / retries (so RPCs can’t hang indefinitely)
  • it doesn’t always hit the network when the full tipset is already locally available (or that this is intentionally acceptable)

Based on learnings, adding a default timeout is generally preferred to avoid “hang forever” behavior.

Proposed shape (local-first + timeout) — adjust types to match actual signatures
 async fn load_api_messages_from_tipset<DB: Blockstore + Send + Sync + 'static>(
     ctx: &crate::rpc::RPCState<DB>,
     tipset_keys: &TipsetKey,
 ) -> Result<Vec<ApiMessage>, ServerError> {
@@
-    let full_tipset = if *SHOULD_BACKFILL {
-        get_full_tipset(
-            &ctx.sync_network_context,
-            ctx.chain_store(),
-            None,
-            tipset_keys,
-        )
-        .await?
-    } else {
-        load_full_tipset(ctx.chain_store(), tipset_keys)?
-    };
+    // Prefer local data; only backfill from network if enabled and local load fails.
+    let full_tipset = match load_full_tipset(ctx.chain_store(), tipset_keys) {
+        Ok(ts) => ts,
+        Err(local_err) if *SHOULD_BACKFILL => {
+            use std::time::Duration;
+            // Pick a sane default; optionally make it configurable.
+            let timeout = Duration::from_secs(30);
+            tokio::time::timeout(
+                timeout,
+                get_full_tipset(
+                    &ctx.sync_network_context,
+                    ctx.chain_store(),
+                    None,
+                    tipset_keys,
+                ),
+            )
+            .await
+            .context("timed out backfilling full tipset from network")??
+        }
+        Err(local_err) => return Err(local_err.into()),
+    };

📜 Recent review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4705b46 and ff69dc8.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • src/rpc/methods/chain.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use anyhow::Result<T> for most operations and add context with .context() when operations fail
Use tokio::task::spawn_blocking for CPU-intensive work such as VM execution and cryptography operations
Use .get() instead of indexing with [index] for safe element access
Do not use unwrap() in production code; use ? or expect() with descriptive messages instead
Do not use dbg! macro in non-test Rust code
Do not use todo! macro in non-test Rust code
Use strum crate for enum string conversions
Use derive_more crate for common trait implementations
Document all public functions and structs with doc comments
Use #[cfg(test)] or #[cfg(feature = "doctest-private")] for test-only code
Use channel-based communication (flume, tokio channels) between async tasks
Use consistent formatting following cargo fmt standards
Ensure code passes cargo clippy --all-targets --no-deps -- --deny=warnings linter checks

Files:

  • src/rpc/methods/chain.rs
🧠 Learnings (5)
📓 Common learnings
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5886
File: scripts/tests/calibnet_eth_mapping_check.sh:49-49
Timestamp: 2025-08-07T09:37:03.079Z
Learning: In Forest project scripts, `forest_wait_api` (called within `forest_init`) ensures basic RPC service readiness, while `forest_wait_for_healthcheck_ready` performs additional comprehensive checks including DB backfill completion. When using `--backfill-db` flag, basic RPC operations can proceed after `forest_init`, but operations requiring complete DB backfill should wait for `forest_wait_for_healthcheck_ready`.
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5930
File: build.rs:64-77
Timestamp: 2025-08-13T09:43:20.301Z
Learning: hanabi1224 prefers hard compile-time errors in build scripts rather than runtime safeguards or collision detection, believing it's better to fail fast and fix root causes of issues like malformed snapshot names.
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6057
File: src/cli/subcommands/f3_cmd.rs:0-0
Timestamp: 2025-09-09T10:37:17.947Z
Learning: hanabi1224 prefers having default timeouts (like 10m for --no-progress-timeout) to prevent commands from hanging indefinitely, even when the timeout flag isn't explicitly provided by users. This fail-fast approach is preferred over requiring explicit flag usage.
📚 Learning: 2025-08-28T12:52:46.927Z
Learnt from: LesnyRumcajs
Repo: ChainSafe/forest PR: 6011
File: src/cli/main.rs:18-25
Timestamp: 2025-08-28T12:52:46.927Z
Learning: In Forest CLI (src/cli/main.rs), the early RPC network check before Cli::parse_from() does not block help/version commands because clap processes these internally before reaching the RPC call. LesnyRumcajs confirmed this implementation works correctly and that RPC call failures are acceptable in this context.

Applied to files:

  • src/rpc/methods/chain.rs
📚 Learning: 2025-08-08T12:11:55.266Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5867
File: src/ipld/util.rs:461-487
Timestamp: 2025-08-08T12:11:55.266Z
Learning: Forest (src/ipld/util.rs, Rust): In UnorderedChainStream::poll_next, dropping `extract_sender` (when no more tipsets and the extract queue is empty) is the intended shutdown signal for workers. Any subsequent attempt to enqueue work after this drop is a logic error and should be treated as an error; do not change `send()` to ignore a missing sender.

Applied to files:

  • src/rpc/methods/chain.rs
📚 Learning: 2026-01-05T12:54:40.850Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/cron_state.rs:8-8
Timestamp: 2026-01-05T12:54:40.850Z
Learning: In Rust code reviews, do not derive Eq for a struct if any field does not implement Eq (e.g., types from external dependencies). If a type like CronStateLotusJson includes fields wrapping external dependencies that lack Eq, derive PartialEq (or implement PartialEq manually) but avoid deriving Eq. This ensures comparisons compile and reflect actual equivalence semantics. When needed, consider implementing custom PartialEq (and possibly Eq) only after ensuring all fields (or wrappers) implement Eq, or keep PartialEq-only if full equality semantics cannot be expressed.

Applied to files:

  • src/rpc/methods/chain.rs
📚 Learning: 2026-01-05T12:56:13.802Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/evm_state.rs:41-44
Timestamp: 2026-01-05T12:56:13.802Z
Learning: In Rust codebases (e.g., Forest), do not add #[cfg(test)] to functions already annotated with #[test]. The #[test] attribute ensures the function is compiled only for tests, so a separate #[cfg(test)] is redundant and can be removed if present. Apply this check to all Rust files that contain #[test] functions.

Applied to files:

  • src/rpc/methods/chain.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (10)
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: cargo-publish-dry-run
  • GitHub Check: rubocop
  • GitHub Check: Build Ubuntu
  • GitHub Check: All lint checks
  • GitHub Check: Build MacOS
  • GitHub Check: tests-release
  • GitHub Check: Check
  • GitHub Check: Deploy to Cloudflare Pages
  • GitHub Check: Coverage
🔇 Additional comments (4)
CHANGELOG.md (1)

46-47: Changelog entry looks good (concise + correctly categorized).

src/rpc/methods/chain.rs (3)

13-35: Imports + env parsing wiring are straightforward.


298-312: RPC handler bound update is consistent with the new async loading path.


372-380: RPC handler bound update is consistent with the new async loading path.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.


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

@hanabi1224 hanabi1224 marked this pull request as ready for review January 14, 2026 11:20
@hanabi1224 hanabi1224 requested a review from a team as a code owner January 14, 2026 11:20
@hanabi1224 hanabi1224 requested review from LesnyRumcajs and akaladarshi and removed request for a team January 14, 2026 11:20
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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/rpc/methods/chain.rs (1)

1305-1344: Add error context and bound timeout for p2p fetch in RPC path

load_api_messages_from_tipset calls get_full_tipset, which triggers a p2p fetch and persist without proper error context or timeout handling. Two issues:

  1. Add .context(...) around get_full_tipset(...).await to include the TipsetKey in error messages, following coding guidelines.
  2. Wrap the get_full_tipset call with tokio::time::timeout to prevent indefinite hangs on the RPC path. The underlying chain_exchange_full_tipset has no timeout, which is unsafe for RPC usage.

Consider using tokio::task::spawn_blocking if the blockstore persist operation blocks the async runtime.

🧹 Nitpick comments (2)
src/chain_sync/mod.rs (1)

14-21: Confirm get_full_tipset is meant to be part of the public API surface

Re-exporting get_full_tipset from src/chain_sync/mod.rs makes it publicly reachable as crate::chain_sync::get_full_tipset. If this is only intended for internal RPC backfill wiring, consider reducing to pub(crate) use ... to avoid locking in an API contract.

Also ensure get_full_tipset is documented at its definition site (it’s now effectively part of the public API).

src/rpc/methods/chain.rs (1)

284-298: Avoid loading the parent Tipset just to get its key

In ChainGetParentMessages, you already have the parent TipsetKey at block_header.parents, so Tipset::load_required(store, &block_header.parents)? is redundant and can fail even though backfill-by-key would work.

Proposed change
         if block_header.epoch == 0 {
             Ok(vec![])
         } else {
-            let parent_tipset = Tipset::load_required(store, &block_header.parents)?;
-            load_api_messages_from_tipset(&ctx, parent_tipset.key()).await
+            load_api_messages_from_tipset(&ctx, &block_header.parents).await
         }
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bde1046 and b741a6d.

📒 Files selected for processing (3)
  • src/blocks/tipset.rs
  • src/chain_sync/mod.rs
  • src/rpc/methods/chain.rs
💤 Files with no reviewable changes (1)
  • src/blocks/tipset.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use anyhow::Result<T> for most operations and add context with .context() when operations fail
Use tokio::task::spawn_blocking for CPU-intensive work such as VM execution and cryptography operations
Use .get() instead of indexing with [index] for safe element access
Do not use unwrap() in production code; use ? or expect() with descriptive messages instead
Do not use dbg! macro in non-test Rust code
Do not use todo! macro in non-test Rust code
Use strum crate for enum string conversions
Use derive_more crate for common trait implementations
Document all public functions and structs with doc comments
Use #[cfg(test)] or #[cfg(feature = "doctest-private")] for test-only code
Use channel-based communication (flume, tokio channels) between async tasks
Use consistent formatting following cargo fmt standards
Ensure code passes cargo clippy --all-targets --no-deps -- --deny=warnings linter checks

Files:

  • src/chain_sync/mod.rs
  • src/rpc/methods/chain.rs
**/mod.rs

📄 CodeRabbit inference engine (AGENTS.md)

Each module should have a mod.rs file that exports the public API with private submodules for implementation details

Files:

  • src/chain_sync/mod.rs
🧠 Learnings (3)
📓 Common learnings
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5944
File: src/chain/store/index.rs:0-0
Timestamp: 2025-08-18T03:09:47.932Z
Learning: In Forest's tipset_by_height caching implementation, hanabi1224 prefers performance-conscious solutions that leverage finality guarantees rather than expensive chain walking for fork detection. The approach of constraining cache lookups to finalized epochs (using CHECKPOINT_INTERVAL >= CHAIN_FINALITY) provides fork safety without the performance cost of ancestry verification.
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5930
File: build.rs:64-77
Timestamp: 2025-08-13T09:43:20.301Z
Learning: hanabi1224 prefers hard compile-time errors in build scripts rather than runtime safeguards or collision detection, believing it's better to fail fast and fix root causes of issues like malformed snapshot names.
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6057
File: src/cli/subcommands/f3_cmd.rs:0-0
Timestamp: 2025-09-09T10:37:17.947Z
Learning: hanabi1224 prefers having default timeouts (like 10m for --no-progress-timeout) to prevent commands from hanging indefinitely, even when the timeout flag isn't explicitly provided by users. This fail-fast approach is preferred over requiring explicit flag usage.
📚 Learning: 2026-01-05T12:54:40.850Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/cron_state.rs:8-8
Timestamp: 2026-01-05T12:54:40.850Z
Learning: In Rust code reviews, do not derive Eq for a struct if any field does not implement Eq (e.g., types from external dependencies). If a type like CronStateLotusJson includes fields wrapping external dependencies that lack Eq, derive PartialEq (or implement PartialEq manually) but avoid deriving Eq. This ensures comparisons compile and reflect actual equivalence semantics. When needed, consider implementing custom PartialEq (and possibly Eq) only after ensuring all fields (or wrappers) implement Eq, or keep PartialEq-only if full equality semantics cannot be expressed.

Applied to files:

  • src/chain_sync/mod.rs
  • src/rpc/methods/chain.rs
📚 Learning: 2026-01-05T12:56:13.802Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/evm_state.rs:41-44
Timestamp: 2026-01-05T12:56:13.802Z
Learning: In Rust codebases (e.g., Forest), do not add #[cfg(test)] to functions already annotated with #[test]. The #[test] attribute ensures the function is compiled only for tests, so a separate #[cfg(test)] is redundant and can be removed if present. Apply this check to all Rust files that contain #[test] functions.

Applied to files:

  • src/chain_sync/mod.rs
  • src/rpc/methods/chain.rs
🧬 Code graph analysis (2)
src/chain_sync/mod.rs (1)
src/chain_sync/chain_follower.rs (3)
  • chain_follower (130-323)
  • get_full_tipset (426-444)
  • load_full_tipset (469-493)
src/rpc/methods/chain.rs (1)
src/chain_sync/chain_follower.rs (1)
  • get_full_tipset (426-444)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (8)
  • GitHub Check: Coverage
  • GitHub Check: tests-release
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: Build Ubuntu
  • GitHub Check: cargo-publish-dry-run
  • GitHub Check: Build MacOS
  • GitHub Check: All lint checks
  • GitHub Check: rubocop
🔇 Additional comments (1)
src/rpc/methods/chain.rs (1)

358-366: Double-check the intended “unknown tipset key” behavior after switching to backfill

ChainGetMessagesInTipset still calls load_required_tipset_or_heaviest before backfilling messages. That likely prevents the RPC from fetching/persisting tipsets that aren’t already known to the local chain (good for avoiding arbitrary network reads), but it also means “missing tipset headers” won’t be recovered here.

If the goal is strictly “messages are missing but tipset exists locally”, this is perfect—otherwise consider whether you want to pass &tipset_key directly when Some(...) and only fall back to heaviest when None.

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

@codecov
Copy link
Copy Markdown

codecov Bot commented Jan 14, 2026

Codecov Report

❌ Patch coverage is 58.33333% with 10 lines in your changes missing coverage. Please review.
✅ Project coverage is 58.53%. Comparing base (b7f3ec6) to head (ff69dc8).
⚠️ Report is 3 commits behind head on main.

Files with missing lines Patch % Lines
src/rpc/methods/chain.rs 58.33% 9 Missing and 1 partial ⚠️
Additional details and impacted files
Files with missing lines Coverage Δ
src/blocks/tipset.rs 87.44% <ø> (-0.11%) ⬇️
src/rpc/methods/chain.rs 52.39% <58.33%> (-0.27%) ⬇️

... and 7 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 b7f3ec6...ff69dc8. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Comment thread src/rpc/methods/chain.rs
) -> Result<Self::Ok, ServerError> {
let tipset = ctx
.chain_store()
.load_required_tipset_or_heaviest(&tipset_key)?;
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Small doubt: Is it possible here that tipset_key is available in the store but the messages (full-tipset) is not available?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Yes. Messages are periodically garbage collected.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

So the tipset is not garbage collected 👍🏼.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Block headers are the spine of the chain that are never garbage collected

| `FOREST_ZSTD_FRAME_CACHE_DEFAULT_MAX_SIZE` | positive integer | 268435456 | 536870912 | The default zstd frame cache max size in bytes |
| `FOREST_JWT_DISABLE_EXP_VALIDATION` | 1 or true | empty | 1 | Whether or not to disable JWT expiration validation |
| `FOREST_ETH_BLOCK_CACHE_SIZE` | positive integer | 500 | 1 | The size of Eth block cache |
| `FOREST_RPC_BACKFILL_FULL_TIPSET_FROM_NETWORK` | 1 or true | false | 1 | Whether or not to backfill full tipsets from the p2p network |
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Actually, let's add some warning that enabling this might lead to excessive disk and bandwidth usage.

Also, let's add a CHANGELOG entry.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/rpc/methods/chain.rs (1)

1306-1354: Move the backfill warning to LazyLock initialization to log once instead of per-request.

The tracing::warn! is currently logged on every RPC request when FOREST_RPC_BACKFILL_FULL_TIPSET_FROM_NETWORK is enabled. Since load_api_messages_from_tipset is called for each RPC request (from ChainGetParentMessages, ChainGetParentReceipts, etc.), the warning creates spam in logs. Moving the warning into the LazyLock::new() closure ensures it fires only once during initialization while preserving the important message for users:

Proposed change
 async fn load_api_messages_from_tipset<DB: Blockstore + Send + Sync + 'static>(
     ctx: &crate::rpc::RPCState<DB>,
     tipset_keys: &TipsetKey,
 ) -> Result<Vec<ApiMessage>, ServerError> {
-    static SHOULD_BACKFILL: LazyLock<bool> =
-        LazyLock::new(|| is_env_truthy("FOREST_RPC_BACKFILL_FULL_TIPSET_FROM_NETWORK"));
+    static SHOULD_BACKFILL: LazyLock<bool> = LazyLock::new(|| {
+        let enabled = is_env_truthy("FOREST_RPC_BACKFILL_FULL_TIPSET_FROM_NETWORK");
+        if enabled {
+            tracing::warn!(
+                "Full tipset backfilling from network is enabled via FOREST_RPC_BACKFILL_FULL_TIPSET_FROM_NETWORK; excessive disk and bandwidth usage is expected."
+            );
+        }
+        enabled
+    });
     let full_tipset = if *SHOULD_BACKFILL {
-        tracing::warn!(
-            "Full tipset backfilling from network is enabled via FOREST_RPC_BACKFILL_FULL_TIPSET_FROM_NETWORK, excessive disk and bandwidth usage is expected."
-        );
         get_full_tipset(
             &ctx.sync_network_context,
             ctx.chain_store(),
             None,
             tipset_keys,
         )
         .await?
     } else {
         load_full_tipset(ctx.chain_store(), tipset_keys)?
     };

The network layer uses adaptive timeouts (CHAIN_EXCHANGE_TIMEOUT_MILLIS with recv_timeout()) to prevent indefinite hangs, and load_full_tipset is purely local. Both code paths are safe.

🤖 Fix all issues with AI agents
In `@CHANGELOG.md`:
- Around line 46-47: Fix the typo in the changelog entry text for PR `#6421`:
replace "metheods" with "methods" in the sentence "-
[`#6421`](https://github.com/ChainSafe/forest/pull/6421) Add an environment
variable `FOREST_RPC_BACKFILL_FULL_TIPSET_FROM_NETWORK` to enable backfilling
full tipsets from network in a few RPC metheods." so the word reads "methods".
📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 991411a and 9a78ef9.

📒 Files selected for processing (2)
  • CHANGELOG.md
  • src/rpc/methods/chain.rs
🧰 Additional context used
📓 Path-based instructions (1)
**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

**/*.rs: Use anyhow::Result<T> for most operations and add context with .context() when operations fail
Use tokio::task::spawn_blocking for CPU-intensive work such as VM execution and cryptography operations
Use .get() instead of indexing with [index] for safe element access
Do not use unwrap() in production code; use ? or expect() with descriptive messages instead
Do not use dbg! macro in non-test Rust code
Do not use todo! macro in non-test Rust code
Use strum crate for enum string conversions
Use derive_more crate for common trait implementations
Document all public functions and structs with doc comments
Use #[cfg(test)] or #[cfg(feature = "doctest-private")] for test-only code
Use channel-based communication (flume, tokio channels) between async tasks
Use consistent formatting following cargo fmt standards
Ensure code passes cargo clippy --all-targets --no-deps -- --deny=warnings linter checks

Files:

  • src/rpc/methods/chain.rs
🧠 Learnings (3)
📓 Common learnings
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5930
File: build.rs:64-77
Timestamp: 2025-08-13T09:43:20.301Z
Learning: hanabi1224 prefers hard compile-time errors in build scripts rather than runtime safeguards or collision detection, believing it's better to fail fast and fix root causes of issues like malformed snapshot names.
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6057
File: src/cli/subcommands/f3_cmd.rs:0-0
Timestamp: 2025-09-09T10:37:17.947Z
Learning: hanabi1224 prefers having default timeouts (like 10m for --no-progress-timeout) to prevent commands from hanging indefinitely, even when the timeout flag isn't explicitly provided by users. This fail-fast approach is preferred over requiring explicit flag usage.
📚 Learning: 2026-01-05T12:54:40.850Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/cron_state.rs:8-8
Timestamp: 2026-01-05T12:54:40.850Z
Learning: In Rust code reviews, do not derive Eq for a struct if any field does not implement Eq (e.g., types from external dependencies). If a type like CronStateLotusJson includes fields wrapping external dependencies that lack Eq, derive PartialEq (or implement PartialEq manually) but avoid deriving Eq. This ensures comparisons compile and reflect actual equivalence semantics. When needed, consider implementing custom PartialEq (and possibly Eq) only after ensuring all fields (or wrappers) implement Eq, or keep PartialEq-only if full equality semantics cannot be expressed.

Applied to files:

  • src/rpc/methods/chain.rs
📚 Learning: 2026-01-05T12:56:13.802Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6381
File: src/lotus_json/actors/states/evm_state.rs:41-44
Timestamp: 2026-01-05T12:56:13.802Z
Learning: In Rust codebases (e.g., Forest), do not add #[cfg(test)] to functions already annotated with #[test]. The #[test] attribute ensures the function is compiled only for tests, so a separate #[cfg(test)] is redundant and can be removed if present. Apply this check to all Rust files that contain #[test] functions.

Applied to files:

  • src/rpc/methods/chain.rs
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (9)
  • GitHub Check: tests-release
  • GitHub Check: Build MacOS
  • GitHub Check: Build Ubuntu
  • GitHub Check: cargo-publish-dry-run
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: Coverage
  • GitHub Check: rubocop
  • GitHub Check: Deploy to Cloudflare Pages
  • GitHub Check: All lint checks
🔇 Additional comments (2)
src/rpc/methods/chain.rs (2)

13-14: Imports look consistent with the new backfill path.

Also applies to: 31-32


285-300: RPC handler bound changes (Send + Sync + 'static) are reasonable for async tipset loading.

One thing to double-check: the backfill path can introduce long tail latency for these endpoints; make sure get_full_tipset enforces a timeout and fails fast rather than hanging.

Also applies to: 359-368

✏️ Tip: You can disable this entire section by setting review_details to false in your review settings.

Comment thread CHANGELOG.md Outdated
Comment thread src/rpc/methods/chain.rs
@LesnyRumcajs LesnyRumcajs added this pull request to the merge queue Jan 15, 2026
Merged via the queue into main with commit bf7c644 Jan 15, 2026
52 checks passed
@LesnyRumcajs LesnyRumcajs deleted the hm/rpc-backfill-full-tipsets branch January 15, 2026 19:23
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