Skip to content

Conversation

@hanabi1224
Copy link
Contributor

@hanabi1224 hanabi1224 commented Nov 5, 2025

Summary of changes

Changes introduced in this pull request:

  • implement Filecoin.GhainGetTipSet v2
  • parity tests
  • snapshot tests
  • update testing framework accordingly

Reference issue to close (if applicable)

Closes #6220

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

  • New Features

    • ChainGetTipSet v2: select tipsets by key, height (with anchors), or tag (Latest/Finalized/Safe); added safe/finality selection helpers.
    • API test runner: offline mode and filter tests by API version/path.
  • Bug Fixes

    • Clarified tipset-related error message wording.
  • Documentation

    • Changelog updated noting ChainGetTipSet v2.
  • Tests

    • Added selector validation unit tests and new RPC snapshots exercising selection and offline-aware scenarios.

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 5, 2025

Walkthrough

Adds a versioned ChainGetTipSet implementation (v2) with TipsetSelector types (key/height/tag), finality-aware resolution (F3 vs EC), and helper APIs; refactors RPC client/path handling to use ApiPaths.path(); threads offline and API-path filtering through the RPC test harness and adds related tests and snapshots.

Changes

Cohort / File(s) Summary
Changelog & compose
CHANGELOG.md, scripts/tests/api_compare/docker-compose.yml
Add changelog entry for ChainGetTipSet v2 and pass --offline to the api-compare service.
RPC client & request plumbing
src/rpc/client.rs, src/rpc/request.rs, src/rpc/reflect/mod.rs
Replace BitFlags usage by selecting a single ApiPaths via Request::api_path()/max_api_path(), change get_or_init_client to take ApiPaths, and add ApiPaths::path() accessor for URL construction.
RPC types & serialization
src/rpc/types/mod.rs
Add serde attributes to ApiTipsetKey and an is_none() helper.
Tipset selector types & validation
src/rpc/methods/chain/types.rs
New public types: TipsetSelector, TipsetHeight, TipsetAnchor, TipsetTag with validation, serde/JsonSchema derives, and helper methods.
Tipset selector tests
src/rpc/methods/chain/types/tests.rs
Add unit tests covering valid and invalid TipsetSelector validation cases.
ChainGetTipSet logic (v1/v2) & finality helpers
src/rpc/methods/chain.rs, src/rpc/methods/chain/types.rs
Make types module public, add SAFE_HEIGHT_DISTANCE, change v1 signature to accept TipsetSelector and return Option<Tipset>, and implement ChainGetTipSetV2 with helpers: get_tipset_by_anchor, get_tipset_by_tag, get_latest_safe_tipset, get_latest_finalized_tipset, get_ec_finalized_tipset, plus selection between F3 and EC finality.
Chain store message
src/chain/store/index.rs
Adjust tipset-height error message wording/format.
RPC test harness: offline & API-path filtering
src/tool/subcommands/api_cmd.rs, src/tool/subcommands/api_cmd/api_compare_tests.rs, src/tool/subcommands/api_cmd/generate_test_snapshot.rs
Add offline: bool and filter_version: Option<ApiPaths> to test generation/run flow; thread offline through snapshot/test creation; add path: rpc::ApiPaths to TestDump; gate generated tests by API_PATHS.
Snapshots registry
src/tool/subcommands/api_cmd/test_snapshots.txt
Insert three new ChainGetTipSet snapshot files (height/key/tag).
Tests-only tipset helper
src/blocks/tipset.rs
Add #[cfg(test)] impl Default for TipsetKey for test convenience.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant RPC as RPC Server
    participant Method as ChainGetTipSetV2
    participant Store as ChainStore
    participant Finality as FinalityLogic

    Client->>RPC: Call ChainGetTipSetV2(selector)
    RPC->>Method: handle(selector)
    Method->>Method: selector.validate()

    alt selector == key
        Method->>Store: lookup by key
        Store-->>Method: Option<Tipset>
    else selector == height
        Method->>Method: resolve anchor/null-tipset policy
        Method->>Store: lookup by height/anchor
        Store-->>Method: Option<Tipset>
    else selector == tag
        alt tag == Latest
            Method->>Store: get_heaviest_tipset()
            Store-->>Method: Tipset
        else tag == Finalized
            Method->>Finality: get_latest_finalized_tipset() (F3 vs EC selection)
            Finality-->>Method: Option<Tipset>
        else tag == Safe
            Method->>Finality: get_latest_safe_tipset()
            Finality-->>Method: Tipset
        end
    end

    Method-->>RPC: Ok(Some/None) or Err
    RPC-->>Client: Response
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

  • Areas needing extra attention:
    • Finality selection logic combining F3 and EC (get_latest_finalized_tipset, get_ec_finalized_tipset).
    • Height/anchor resolution and null-tipset policy.
    • Request/client refactor from BitFlags to ApiPaths and URL construction via ApiPaths::path().
    • Test harness changes: offline gating and API-path filtering, and snapshot additions.

Possibly related PRs

Suggested reviewers

  • akaladarshi
  • LesnyRumcajs

Pre-merge checks and finishing touches

✅ 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 'feat(rpc): ChainGetTipset v2' accurately and concisely summarizes the main change: implementing ChainGetTipSet v2 RPC method.
Linked Issues check ✅ Passed The PR implements ChainGetTipSet v2 [#6231], extends RPC testing framework for multiple API versions [#6220], includes parity and snapshot tests, and updates documentation as required.
Out of Scope Changes check ✅ Passed All changes align with linked objectives: v2 API implementation, testing framework enhancements, offline mode support, and validation for multi-version testing.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch hm/ChainGetTipSetV2

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 Nov 6, 2025
@hanabi1224 hanabi1224 marked this pull request as ready for review November 7, 2025 02:22
@hanabi1224 hanabi1224 requested a review from a team as a code owner November 7, 2025 02:22
@hanabi1224 hanabi1224 requested review from LesnyRumcajs and akaladarshi and removed request for a team November 7, 2025 02:22
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: 0

🧹 Nitpick comments (7)
CHANGELOG.md (1)

32-32: Use consistent “Tipset” casing across entries.

Elsewhere you use “Tipset” (e.g., ChainGetFinalizedTipset). Recommend: Filecoin.ChainGetTipset for consistency and grepability.

src/tool/subcommands/api_cmd/generate_test_snapshot.rs (1)

47-49: Also accept method aliases to avoid false “RPC method not found”.

Snapshots/tests might record an alias. Consider matching NAME or NAME_ALIAS before the API_PATHS check.

Apply this minimal change:

-            if test_dump.request.method_name.as_ref() == <$ty>::NAME
-                && <$ty>::API_PATHS.contains(test_dump.path)
+            let name = test_dump.request.method_name.as_ref();
+            if (name == <$ty>::NAME
+                || <$ty>::NAME_ALIAS.is_some_and(|a| a == name))
+                && <$ty>::API_PATHS.contains(test_dump.path)
             {
src/rpc/reflect/mod.rs (1)

166-172: Clarify path semantics and make formatting reusable.

The helper returns a path segment (no leading slash). Document this to avoid misuse and consider a Display impl for reuse.

You can add:

-    pub fn path(&self) -> &'static str {
+    /// Returns the relative path segment (without leading slash), e.g. `rpc/v1`.
+    pub fn path(&self) -> &'static str {
         match self {
             Self::V0 => "rpc/v0",
             Self::V1 => "rpc/v1",
             Self::V2 => "rpc/v2",
         }
     }

Optionally:

impl core::fmt::Display for ApiPaths {
    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
        f.write_str(self.path())
    }
}
src/rpc/methods/chain/types/tests.rs (1)

6-17: Add a non-empty round‑trip case as well.

Great baseline. Add one with key/height/tag populated to catch serde attribute regressions.

src/rpc/request.rs (1)

46-52: Make ApiPaths precedence explicit via refactor for code clarity.

The current implementation using iter().max() works correctly because ApiPaths has explicit discriminants (V0=1, V1=2, V2=4), making the Ord comparison deterministic. However, relying on implicit enum Ord behavior is a maintainability risk. The suggested explicit precedence refactor guards against accidental reordering and clarifies intent:

-    pub fn max_api_path(api_paths: BitFlags<ApiPaths>) -> anyhow::Result<ApiPaths> {
-        api_paths.iter().max().context("No supported versions")
-    }
+    pub fn max_api_path(api_paths: BitFlags<ApiPaths>) -> anyhow::Result<ApiPaths> {
+        // Highest supported first to make precedence explicit.
+        if api_paths.contains(ApiPaths::V2) {
+            Ok(ApiPaths::V2)
+        } else if api_paths.contains(ApiPaths::V1) {
+            Ok(ApiPaths::V1)
+        } else if api_paths.contains(ApiPaths::V0) {
+            Ok(ApiPaths::V0)
+        } else {
+            anyhow::bail!("No supported versions")
+        }
+    }

Server capability negotiation is already in place: api_path() operates on self.api_paths (server-supported versions), and the result is passed to get_or_init_client() for correct URL routing.

src/tool/subcommands/api_cmd.rs (1)

476-476: Fix grammar in documentation.

The documentation reads "The nodes to test against is offline" but should be "The node to test against is offline" (singular) or "The nodes to test against are offline" (plural).

Apply this diff to fix the grammar:

-    /// The nodes to test against is offline, the chain is out of sync.
+    /// The node to test against is offline, the chain is out of sync.
src/rpc/methods/chain.rs (1)

1144-1144: Unreachable error case due to validation.

Line 1144 returns an error for "no tipset found for selector," but this should be unreachable because selector.validate() (line 1123) ensures exactly one of key, height, or tag is specified. The three preceding conditionals (lines 1125, 1130, 1140) should cover all valid cases.

Consider replacing with:

unreachable!("selector validation ensures one criterion is specified")

This makes the invariant explicit and will help catch bugs if the validation logic changes.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2bc2eda and 6c84c1a.

📒 Files selected for processing (14)
  • CHANGELOG.md (1 hunks)
  • scripts/tests/api_compare/docker-compose.yml (1 hunks)
  • src/chain/store/index.rs (1 hunks)
  • src/rpc/client.rs (3 hunks)
  • src/rpc/methods/chain.rs (3 hunks)
  • src/rpc/methods/chain/types.rs (1 hunks)
  • src/rpc/methods/chain/types/tests.rs (1 hunks)
  • src/rpc/reflect/mod.rs (1 hunks)
  • src/rpc/request.rs (2 hunks)
  • src/rpc/types/mod.rs (1 hunks)
  • src/tool/subcommands/api_cmd.rs (6 hunks)
  • src/tool/subcommands/api_cmd/api_compare_tests.rs (13 hunks)
  • src/tool/subcommands/api_cmd/generate_test_snapshot.rs (1 hunks)
  • src/tool/subcommands/api_cmd/test_snapshots.txt (1 hunks)
🧰 Additional context used
🧠 Learnings (8)
📓 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: 2025-09-02T14:23:53.808Z
Learnt from: akaladarshi
Repo: ChainSafe/forest PR: 5923
File: src/tool/subcommands/api_cmd/test_snapshots.txt:206-252
Timestamp: 2025-09-02T14:23:53.808Z
Learning: In the Forest project, .rpcsnap.json.zst snapshot files listed in src/tool/subcommands/api_cmd/test_snapshots.txt are not stored in the repository itself but are downloaded from a DigitalOcean (DO) bucket when needed. The manifest file serves as an index/catalog of available snapshots.

Applied to files:

  • src/tool/subcommands/api_cmd/test_snapshots.txt
📚 Learning: 2025-08-25T14:11:10.790Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 5978
File: .github/workflows/unit-tests.yml:86-96
Timestamp: 2025-08-25T14:11:10.790Z
Learning: hanabi1224's RPC snapshot tests include a checksum validation mechanism that compares against HTTP HEAD headers, automatically re-downloading snapshots if the cached version doesn't match, providing protection against corrupted cached files.

Applied to files:

  • src/tool/subcommands/api_cmd/test_snapshots.txt
📚 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:

  • src/tool/subcommands/api_cmd.rs
📚 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:

  • src/tool/subcommands/api_cmd/api_compare_tests.rs
📚 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/tool/subcommands/api_cmd/api_compare_tests.rs
📚 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/rpc/methods/chain.rs
📚 Learning: 2025-08-18T03:09:47.932Z
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.

Applied to files:

  • src/rpc/methods/chain.rs
🧬 Code graph analysis (4)
src/tool/subcommands/api_cmd/generate_test_snapshot.rs (1)
src/rpc/reflect/mod.rs (2)
  • request (290-300)
  • path (166-172)
src/rpc/client.rs (3)
src/rpc/request.rs (1)
  • max_api_path (46-48)
src/rpc/segregation_layer.rs (2)
  • req (99-99)
  • req (110-110)
src/rpc/reflect/mod.rs (1)
  • path (166-172)
src/tool/subcommands/api_cmd/api_compare_tests.rs (4)
src/chain/store/index.rs (1)
  • chain (191-198)
src/rpc/reflect/mod.rs (1)
  • path (166-172)
src/rpc/segregation_layer.rs (2)
  • req (99-99)
  • req (110-110)
src/rpc/methods/chain/types.rs (3)
  • validate (38-56)
  • validate (73-82)
  • validate (109-115)
src/rpc/methods/chain.rs (2)
src/blocks/tipset.rs (5)
  • tsk (265-269)
  • epoch (306-308)
  • epoch (543-545)
  • key (336-339)
  • key (530-533)
src/rpc/methods/state.rs (16)
  • handle (109-114)
  • handle (132-138)
  • handle (151-157)
  • handle (172-178)
  • handle (196-205)
  • handle (223-231)
  • handle (248-255)
  • handle (272-282)
  • handle (298-305)
  • handle (335-465)
  • handle (484-492)
  • handle (508-538)
  • handle (555-561)
  • handle (577-597)
  • handle (615-624)
  • handle (641-663)
⏰ 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). (7)
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: tests-release
  • GitHub Check: tests
  • GitHub Check: cargo-publish-dry-run
  • GitHub Check: Build MacOS
  • GitHub Check: Build Ubuntu
  • GitHub Check: All lint checks
🔇 Additional comments (4)
scripts/tests/api_compare/docker-compose.yml (1)

274-286: LGTM: offline compare wired correctly.

--offline fits the api-serve flow and keeps Lotus as reference. Timeout env present; no further changes needed.

src/chain/store/index.rs (1)

158-163: Message-only change; ensure tests don’t hard‑match full string.

If any tests assert on the exact error text, switch them to substring/pattern to avoid brittleness.

src/tool/subcommands/api_cmd/test_snapshots.txt (1)

16-18: Entries are correctly formatted and follow the established snapshot workflow.

The three new ChainGetTipset snapshots (lines 16-18) are properly formatted, unique, and follow the naming convention of existing entries. The manifest file is embedded at compile-time and watched by the build system. Per the established workflow, entries should only be added after uploading corresponding .rpcsnap.json.zst files to the DigitalOcean bucket via scripts/tests/upload_rcpsnaps.sh, which updates this manifest atomically. CI automatically validates checksums via HTTP HEAD headers during test execution. Assuming the standard upload process was followed, these entries will be validated when tests run.

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

996-1005: Verify behavior change for ChainGetTipSet v0/v1 with empty tipset key.

The updated logic returns an error when tsk is None (line 1003), but this might differ from the previous behavior. Please verify:

  1. Whether the previous implementation defaulted to the heaviest tipset when given an empty key
  2. If this error behavior matches Lotus for v0/v1 API paths
  3. Whether this constitutes a breaking change for existing clients

The error message matches Lotus per the comment, but it's worth confirming that v0/v1 clients expect this behavior.

impl TipsetSelector {
/// Validate ensures that the TipSetSelector is valid. It checks that only one of
/// the selection criteria is specified. If no criteria are specified, it returns
/// nil, indicating that the default selection criteria should be used as defined
Copy link
Member

Choose a reason for hiding this comment

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

Is this copied from Lotus? There's no nil, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed. Actually, this line is wrong. In Lotus Validate is implemented for TipSetSelector instead of *TipSetSelector.

Comment on lines 51 to 54
anyhow::bail!(
"exactly one tipset selection criteria must be specified, found: {criteria}"
)
}
Copy link
Member

Choose a reason for hiding this comment

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

ensure!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

No longer applicable

/// Validate ensures that the TipSetSelector is valid. It checks that only one of
/// the selection criteria is specified. If no criteria are specified, it returns
/// nil, indicating that the default selection criteria should be used as defined
/// by the Lotus API Specification.
Copy link
Member

Choose a reason for hiding this comment

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

Unit tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

/// the selection criteria is specified. If no criteria are specified, it returns
/// nil, indicating that the default selection criteria should be used as defined
/// by the Lotus API Specification.
pub fn validate(&self) -> anyhow::Result<()> {
Copy link
Member

Choose a reason for hiding this comment

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

The logic is a bit wasteful - if there's key AND there's tag then it's just wasteful to to height validation; we could break early with an error.

I guess a match would be a more idiomatic choice for this kind of logic.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Rewrote the logic in a more Rustic way

Comment on lines 110 to 114
if self.key.0.is_some() && self.tag.is_some() {
anyhow::bail!("invalid tipset anchor: at most one of key or tag must be specified");
}
// Zero-valued anchor is valid, and considered to be an equivalent to whatever the API decides the default to be.
Ok(())
Copy link
Member

Choose a reason for hiding this comment

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

either ensure! or perhaps match (it's more idiomatic Rust than conditionals here)

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

Choose a reason for hiding this comment

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

Let's have some coverage for the logic in this file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.


const HEAD_CHANNEL_CAPACITY: usize = 10;

// SafeHeightDistance is the distance from the latest tipset, i.e. heaviest, that
Copy link
Member

Choose a reason for hiding this comment

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

Again, let's not just copy over Lotus docs.

Suggested change
// SafeHeightDistance is the distance from the latest tipset, i.e. heaviest, that
// `SAFE_HEIGHT_DISTANCE` is the distance from the latest tipset, i.e. heaviest, that

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

let ts = ctx.chain_index().load_required_tipset(tsk)?;
Ok(ts)
} else {
// Error message here matches lotus
Copy link
Member

Choose a reason for hiding this comment

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

Do we need to match the Lotus error? This would actually be a very confusing message for me.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Updated, but still keep Lotus error message in parentheses to make RPC parity test easier.

@hanabi1224 hanabi1224 marked this pull request as draft November 16, 2025 03:57
@hanabi1224 hanabi1224 marked this pull request as ready for review December 2, 2025 11:24
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: 0

🧹 Nitpick comments (3)
src/tool/subcommands/api_cmd/api_compare_tests.rs (1)

462-474: Consider more explicit offline validation strategy.

The function always returns true in offline mode, which effectively skips validation. While this makes sense since F3 finality isn't available offline, consider adding a comment explaining why offline tests for tagged tipsets (Safe/Finalized) can't be properly validated, or consider testing that the offline server returns an appropriate error instead of skipping validation entirely.

Apply this diff to add clarifying documentation:

 fn validate_tagged_tipset_v2(req: rpc::Request<Option<Tipset>>, offline: bool) -> RpcTest {
     RpcTest::validate(req, move |forest, lotus| match (forest, lotus) {
         (None, None) => true,
         (Some(forest), Some(lotus)) => {
             if offline {
+                // Offline mode: F3 is unavailable, so we can't verify exact finality epochs.
+                // We accept any non-None result as valid for offline testing.
                 true
             } else {
                 (forest.epoch() - lotus.epoch()).abs() <= 2
             }
         }
         _ => false,
     })
 }
src/rpc/methods/chain.rs (1)

1116-1142: Consider making unreachable error more explicit.

The error at line 1141 should be unreachable if selector.validate() properly ensures at least one selection criterion is present. Consider using anyhow::bail! with a message indicating this is an internal invariant violation, or add a debug_assert to document this expectation.

Apply this diff:

         if let Some(tag) = &selector.tag {
             let ts = Self::get_tipset_by_tag(&ctx, *tag).await?;
             return Ok(ts);
         }
-        Err(anyhow::anyhow!("no tipset found for selector").into())
+        // Unreachable: validate() should ensure at least one criterion is set
+        debug_assert!(false, "selector.validate() should prevent reaching this point");
+        Err(anyhow::anyhow!("internal error: no valid selector criteria after validation").into())
     }
 }
src/rpc/methods/chain/types/tests.rs (1)

1-100: Good baseline coverage, consider expanding edge cases.

The tests cover the fundamental validation rules well (single vs. multiple criteria). Consider adding tests for:

  • Different TipsetTag variants (Safe, Latest, not just Finalized)
  • TipsetHeight with anchor set to various values
  • Boundary conditions for the at field in TipsetHeight

These would provide more comprehensive validation coverage.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a6cc02 and 839368a.

📒 Files selected for processing (6)
  • src/blocks/tipset.rs (1 hunks)
  • src/chain/store/index.rs (1 hunks)
  • src/rpc/methods/chain.rs (3 hunks)
  • src/rpc/methods/chain/types.rs (1 hunks)
  • src/rpc/methods/chain/types/tests.rs (1 hunks)
  • src/tool/subcommands/api_cmd/api_compare_tests.rs (13 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/chain/store/index.rs
  • src/rpc/methods/chain/types.rs
🧰 Additional context used
🧠 Learnings (6)
📓 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: 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/rpc/methods/chain/types/tests.rs
  • src/rpc/methods/chain.rs
📚 Learning: 2025-09-16T12:55:26.955Z
Learnt from: hanabi1224
Repo: ChainSafe/forest PR: 6079
File: src/chain_sync/metrics.rs:6-7
Timestamp: 2025-09-16T12:55:26.955Z
Learning: HEAD_EPOCH references in shell scripts (like scripts/tests/calibnet_eth_mapping_check.sh) that extract data from `forest-cli info show` are unrelated to Rust metrics constants with the same name and should not be flagged when metrics cleanup is performed.

Applied to files:

  • src/tool/subcommands/api_cmd/api_compare_tests.rs
📚 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:

  • src/tool/subcommands/api_cmd/api_compare_tests.rs
📚 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/tool/subcommands/api_cmd/api_compare_tests.rs
📚 Learning: 2025-08-18T03:09:47.932Z
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.

Applied to files:

  • src/rpc/methods/chain.rs
🧬 Code graph analysis (2)
src/rpc/methods/chain/types/tests.rs (1)
src/blocks/tipset.rs (1)
  • default (146-148)
src/tool/subcommands/api_cmd/api_compare_tests.rs (2)
src/rpc/reflect/mod.rs (1)
  • path (166-172)
src/rpc/segregation_layer.rs (2)
  • req (99-99)
  • req (110-110)
⏰ 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). (14)
  • GitHub Check: Build forest binaries on Linux AMD64
  • GitHub Check: tests-release
  • GitHub Check: tests
  • GitHub Check: Bootstrap checks - Lotus
  • GitHub Check: Calibnet RPC checks
  • GitHub Check: Devnet checks
  • GitHub Check: Calibnet kademlia checks
  • GitHub Check: Diff snapshot export checks
  • GitHub Check: V2 snapshot export checks
  • GitHub Check: Calibnet eth mapping check
  • GitHub Check: Wallet tests
  • GitHub Check: Calibnet api test-stateful check
  • GitHub Check: Forest CLI checks
  • GitHub Check: Calibnet check
🔇 Additional comments (7)
src/tool/subcommands/api_cmd/api_compare_tests.rs (3)

147-195: LGTM! TestDump structure enhanced with API path tracking.

The addition of the path field and its display in the output is well-integrated and provides valuable debugging context.


2342-2346: LGTM! API path filtering correctly implemented.

The filtering logic properly checks API path membership and skips tests that don't match the requested version filter.


460-465: Key + tag combination should fail validation.

The test at lines 460–464 correctly validates that constructing a TipsetSelector with both key and tag set is rejected. The TipsetSelector::validate() method in src/rpc/methods/chain/types.rs enforces that exactly one selection criterion (key, tag, or height) must be specified; providing multiple criteria triggers an error. The PassWithQuasiIdenticalError policy appropriately handles this rejection.

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

53-66: LGTM! Well-documented experimental constant.

The SAFE_HEIGHT_DISTANCE constant is clearly documented with appropriate caveats about its experimental nature. The reference to the tracking issue for probabilistic analysis is helpful.


979-1005: LGTM! V1 API now properly validates empty tipset keys.

The updated error handling for empty tipset keys is appropriate, and including the Lotus error message ensures RPC parity test compatibility.


1061-1088: Well-designed F3/EC finality fallback logic.

The implementation properly handles the transition between F3 and EC finality, falling back when F3 is unavailable or too far behind. The epoch comparison at line 1073 ensures we don't use stale F3 finality.

src/blocks/tipset.rs (1)

144-149: LGTM! Test-only Default implementation is appropriate.

The Default implementation for TipsetKey in test mode provides a convenient helper for test setup without affecting production code.

Copy link
Member

@LesnyRumcajs LesnyRumcajs left a comment

Choose a reason for hiding this comment

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

LGTM

@LesnyRumcajs LesnyRumcajs added this pull request to the merge queue Dec 2, 2025
Merged via the queue into main with commit c6bd18c Dec 2, 2025
80 of 81 checks passed
@LesnyRumcajs LesnyRumcajs deleted the hm/ChainGetTipSetV2 branch December 2, 2025 18:04
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.

Update the RPC testing framework to support multiple API versions

3 participants