Skip to content

Conversation

@0xDevNinja
Copy link

@0xDevNinja 0xDevNinja commented Jan 8, 2026

This PR adds initial support for an optional chainstore fallback in Forest. When the new environment variable FOREST_ENABLE_CHAINSTORE_FALLBACK is set to 1, missing blocks will be fetched via Bitswap and then retried in the local store.

Key changes:

  • Added src/chain/store/blockstore_fallback.rs implementing a FallbackBlockstore wrapper around any blockstore. It checks FOREST_ENABLE_CHAINSTORE_FALLBACK and uses a BitswapFetcher to retrieve missing blocks when enabled.
  • Added blockstore_fallback to src/chain/store/mod.rs and re-exported it.
  • Updated the README with an "Optional Chainstore Fallback" section documenting how to enable the feature.
  • Provided traits BlockGetter and BitswapFetcher to abstract over block fetching and bitswap network.

This resolves #6353 by enabling a fallback blockstore similar to Lotus' LOTUS_ENABLE_CHAINSTORE_FALLBACK. Future enhancements can integrate this wrapper into the main chain store.

Closes #6353

Summary by CodeRabbit

Release Notes

  • New Features

    • Introduced experimental, opt-in chainstore fallback mechanism that automatically fetches missing blocks from the network via Bitswap when enabled.
  • Documentation

    • Added documentation for the optional chainstore fallback feature, including how to enable it and expected behavior.

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

…al bitswap fallback (ChainSafe#6353)

Introduces FallbackBlockstore wrapper implementing get_with_fallback to fetch missing blocks via Bitswap when FOREST_ENABLE_CHAINSTORE_FALLBACK is set. Adds environment variable check and uses asynchronous Bitswap fetch.

Closes ChainSafe#6353.
Adds mod blockstore_fallback and re-exports it in store::mod. This exposes the fallback blockstore functionality for optional bitswap fallback. Part of issue ChainSafe#6353.
Add documentation for the FOREST_ENABLE_CHAINSTORE_FALLBACK environment variable and describe how to enable the fallback blockstore via Bitswap.

Part of issue ChainSafe#6353.
@0xDevNinja 0xDevNinja requested a review from a team as a code owner January 8, 2026 16:45
@0xDevNinja 0xDevNinja requested review from LesnyRumcajs and sudo-shashank and removed request for a team January 8, 2026 16:45
@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 8, 2026

Walkthrough

The PR introduces an optional chainstore fallback mechanism that enables fetching missing blocks via Bitswap from the peer-to-peer network. Implementation includes trait definitions for block storage and network retrieval, a fallback blockstore wrapper coordinating local and remote access, and documentation describing the feature controlled via an environment variable.

Changes

Cohort / File(s) Summary
Documentation
README.md
Added experimental "Optional Chainstore Fallback" section describing feature activation via FOREST_ENABLE_CHAINSTORE_FALLBACK=1 environment variable and fallback behavior on block miss.
Fallback blockstore implementation
src/chain/store/blockstore_fallback.rs
New module defining BlockGetter and BitswapFetcher traits for local store access and network-based block fetching, and FallbackBlockstore<S, B> struct providing get_with_fallback() method that attempts local retrieval, conditionally invokes network fetch via Bitswap on miss, and re-reads from local store after successful network fetch.
Module integration
src/chain/store/mod.rs
Added module declaration for blockstore_fallback and expanded public re-exports to include newly defined traits and struct.

Sequence Diagram

sequenceDiagram
    participant Client
    participant FallbackBlockstore
    participant LocalStore as BlockGetter<br/>(Local Store)
    participant Bitswap as BitswapFetcher<br/>(Network)

    Client->>FallbackBlockstore: get_with_fallback(cid)
    FallbackBlockstore->>LocalStore: get(cid)
    LocalStore-->>FallbackBlockstore: Some(block) or None

    alt Block found locally
        FallbackBlockstore-->>Client: Some(block)
    else Block not found
        FallbackBlockstore->>FallbackBlockstore: Check FOREST_ENABLE_CHAINSTORE_FALLBACK env var
        alt Fallback enabled
            FallbackBlockstore->>Bitswap: fetch_block(cid)
            Bitswap-->>FallbackBlockstore: Ok(()) or Err
            alt Fetch succeeded
                FallbackBlockstore->>LocalStore: get(cid) [retry]
                LocalStore-->>FallbackBlockstore: Some(block)
                FallbackBlockstore-->>Client: Some(block)
            else Fetch failed
                FallbackBlockstore-->>Client: Err
            end
        else Fallback disabled
            FallbackBlockstore-->>Client: None
        end
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Suggested reviewers

  • sudo-shashank
  • LesnyRumcajs
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 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 a fallback blockstore with bitswap support capabilities.
Linked Issues check ✅ Passed The PR implements all core requirements from #6353: fallback blockstore with bitswap support, environment variable toggle, and network block fetching.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the fallback blockstore feature. README update, new module, and trait definitions are all in scope.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
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

🤖 Fix all issues with AI agents
In @README.md:
- Line 36: The sentence "To  enable fallback, set the environment variable:"
contains a double space after "To"; fix it by replacing "To  enable fallback,
set the environment variable:" with "To enable fallback, set the environment
variable:" in the README (the line containing the string "To  enable fallback,
set the environment variable:").

In @src/chain/store/blockstore_fallback.rs:
- Around line 61-66: The code reads FOREST_ENABLE_CHAINSTORE_FALLBACK via
env::var inside get_with_fallback on the hot path; move that env var read out of
the hot path by caching the boolean at construction or in a static LazyLock so
get_with_fallback checks a stored flag instead of calling env::var each time.
Concretely, add a field like enable_fallback to the BlockstoreFallback (or
initialize a static std::sync::LazyLock<bool> with
env::var("FOREST_ENABLE_CHAINSTORE_FALLBACK") == "1"), set it once at creation,
and replace the inline env::var check in get_with_fallback with a read of that
cached boolean.
🧹 Nitpick comments (1)
README.md (1)

32-43: Section placement breaks "Run with Docker" flow.

The "Optional Chainstore Fallback" section is inserted between the "Run with Docker" header (line 30) and the actual Docker instructions (line 45), disrupting the logical structure. Consider either making this a subsection under "Run with Docker" or moving it to a more appropriate location (e.g., after the Docker section or under a dedicated "Configuration" or "Advanced Features" section).

📜 Review details

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0af174d and 91ef7b2.

📒 Files selected for processing (3)
  • README.md
  • src/chain/store/blockstore_fallback.rs
  • src/chain/store/mod.rs
🧰 Additional context used
🧠 Learnings (7)
📓 Common learnings
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5867
File: src/ipld/util.rs:553-558
Timestamp: 2025-08-08T12:10:45.218Z
Learning: Forest project targets Rust stable >=1.89; features stabilized in 1.88 like let-chains are acceptable in this codebase.
📚 Learning: 2025-08-08T12:10:45.218Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5867
File: src/ipld/util.rs:553-558
Timestamp: 2025-08-08T12:10:45.218Z
Learning: Forest project targets Rust stable >=1.89; features stabilized in 1.88 like let-chains are acceptable in this codebase.

Applied to files:

  • README.md
  • src/chain/store/blockstore_fallback.rs
📚 Learning: 2025-08-11T12:42:42.848Z
Learnt from: elmattic
Repo: ChainSafe/forest PR: 5836
File: src/tool/subcommands/api_cmd/api_run_tests.rs:186-190
Timestamp: 2025-08-11T12:42:42.848Z
Learning: In the Forest project's test infrastructure (specifically in `src/tool/subcommands/api_cmd/api_run_tests.rs`), the team prefers to use only `ws` (non-secure WebSocket) connections for simplicity in their stateful API test scenarios, as security is not a concern in their testing context.

Applied to files:

  • README.md
📚 Learning: 2025-10-17T09:36:15.757Z
Learnt from: elmattic
Repo: ChainSafe/forest PR: 6128
File: src/ipld/util.rs:23-30
Timestamp: 2025-10-17T09:36:15.757Z
Learning: Always run `cargo check` or `cargo build` to verify actual compilation errors in the Forest codebase before flagging them as issues. Do not rely solely on documentation or assumptions about trait implementations.

Applied to files:

  • README.md
📚 Learning: 2025-09-11T16:03:14.328Z
Learnt from: akaladarshi
Repo: ChainSafe/forest PR: 6000
File: src/tool/subcommands/api_cmd/state_decode_params_tests/miner.rs:4-9
Timestamp: 2025-09-11T16:03:14.328Z
Learning: In the Forest codebase's state_decode_params_tests module, common imports like `to_vec`, `TokenAmount`, `Cid`, etc. are centralized in the mod.rs file and made available to submodules through `use super::*;`, eliminating the need for duplicate imports in individual test files.

Applied to files:

  • src/chain/store/mod.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/chain/store/mod.rs
  • src/chain/store/blockstore_fallback.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/store/mod.rs
  • src/chain/store/blockstore_fallback.rs
🔇 Additional comments (6)
src/chain/store/mod.rs (1)

9-10: LGTM!

The module declaration and re-export pattern is consistent with existing modules like chain_store and errors.

src/chain/store/blockstore_fallback.rs (5)

1-13: LGTM!

Clear module documentation and minimal imports.


15-20: LGTM!

The BlockGetter trait provides a clean abstraction. Verify that existing Blockstore implementations can easily implement this trait when integrating the fallback into the main chain store.


22-28: LGTM!

The BitswapFetcher trait clearly documents expectations. Implementors should ensure appropriate timeouts are applied in fetch_block to avoid indefinite hangs during network fetch.


40-49: LGTM!

The struct definition and constructor are well-designed. The trait bounds (BlockGetter + Send + Sync) are appropriately applied at the impl level rather than the trait definition.


54-75: Control flow is correct.

The fallback logic properly:

  1. Attempts local read first
  2. Checks if fallback is enabled (pending the env var caching fix)
  3. Propagates bitswap errors
  4. Re-reads from local store after network fetch


Forest supports an experimental fallback blockstore to fetch missing blocks from the network via Bitswap when they are not available locally. This behavior is disabled by default.

To enable fallback, set the environment variable:
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Typo: double space before "enable".

-To  enable fallback, set the environment variable:
+To enable fallback, set the environment variable:
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
To enable fallback, set the environment variable:
To enable fallback, set the environment variable:
🤖 Prompt for AI Agents
In @README.md at line 36, The sentence "To  enable fallback, set the environment
variable:" contains a double space after "To"; fix it by replacing "To  enable
fallback, set the environment variable:" with "To enable fallback, set the
environment variable:" in the README (the line containing the string "To  enable
fallback, set the environment variable:").

Comment on lines +61 to +66
let enable = env::var("FOREST_ENABLE_CHAINSTORE_FALLBACK")
.map(|v| v == "1")
.unwrap_or(false);
if !enable {
return Ok(None);
}
Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Avoid repeated env::var() calls on hot path.

Reading the environment variable on every get_with_fallback() call incurs syscall overhead and string allocation. During chain sync, this could be called thousands of times. Cache the value at construction time or use std::sync::LazyLock (stable in Rust 1.80+).

🔧 Suggested fix using LazyLock
 use std::env;
 use std::sync::Arc;
+use std::sync::LazyLock;
 
 use cid::Cid;
 use anyhow::Result;
+
+static FALLBACK_ENABLED: LazyLock<bool> = LazyLock::new(|| {
+    env::var("FOREST_ENABLE_CHAINSTORE_FALLBACK")
+        .map(|v| v == "1")
+        .unwrap_or(false)
+});

Then in get_with_fallback:

-        // Check environment variable to decide if fallback is enabled.
-        let enable = env::var("FOREST_ENABLE_CHAINSTORE_FALLBACK")
-            .map(|v| v == "1")
-            .unwrap_or(false);
-        if !enable {
+        if !*FALLBACK_ENABLED {
             return Ok(None);
         }

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In @src/chain/store/blockstore_fallback.rs around lines 61 - 66, The code reads
FOREST_ENABLE_CHAINSTORE_FALLBACK via env::var inside get_with_fallback on the
hot path; move that env var read out of the hot path by caching the boolean at
construction or in a static LazyLock so get_with_fallback checks a stored flag
instead of calling env::var each time. Concretely, add a field like
enable_fallback to the BlockstoreFallback (or initialize a static
std::sync::LazyLock<bool> with env::var("FOREST_ENABLE_CHAINSTORE_FALLBACK") ==
"1"), set it once at creation, and replace the inline env::var check in
get_with_fallback with a read of that cached boolean.

@hanabi1224 hanabi1224 self-requested a review January 9, 2026 11:16
@hanabi1224 hanabi1224 self-assigned this Jan 9, 2026
@hanabi1224
Copy link
Contributor

Hey @0xDevNinja could you please fix outstanding AI reviews first and I will review later.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement fallback blockstore

3 participants