Skip to content

Conversation

@lok52
Copy link
Contributor

@lok52 lok52 commented Nov 19, 2025

Summary by CodeRabbit

  • New Features

    • New "check redirect" API to detect if a search query redirects to a block, transaction, or address (includes chain info).
    • Search improved to parse hashes, addresses, and block numbers for more accurate redirect resolution.
    • Server and API docs updated to expose the new redirect check endpoint.
  • Chores

    • Added a new dependency to support parsing/utilities.

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

@lok52 lok52 added the feat New feature label Nov 19, 2025
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 19, 2025

Walkthrough

This PR adds a redirect-check feature to the multichain aggregator. Changes include: new protobuf RPC and messages (CheckRedirectRequest, CheckRedirectResponse) and HTTP route; new Redirect and RedirectType types with conversion to proto; search-term parsing helpers (try_parse_hash, try_parse_address, try_parse_block_number, parse_redirect_search_term) and a try_to_redirect flow; a SearchContext helper and Cluster::check_redirect integration; server-side RPC handler; and strum added as a workspace dependency. No public exported type deletions observed.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Heterogeneous changes across proto, server, logic, and type modules.
  • New public APIs and type conversions require cross-file verification.

Areas requiring extra attention:

  • quick_search.rs: parsing helpers and try_to_redirect correctness and edge-case handling.
  • types/search_results.rs: Redirect/RedirectType semantics and From<Redirect> conversion to proto.
  • cluster.rs and server handler: SearchContext usage and end-to-end flow from request -> cluster -> response.
  • Cargo.toml updates: workspace strum addition and feature flags.

Possibly related PRs

Poem

🐰
I hopped through search fields, keen and bright,
Found hashes, addresses, blocks in sight,
I parsed and nudged a redirect true,
Sent travelers onward down the queue,
A tiny rabbit cheers — hop, search, delight! 🥕🔍

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 7.14% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ 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 a new check redirect endpoint across multiple services.
✨ 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 lok52/multi-search-redirect

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: 0

🧹 Nitpick comments (3)
multichain-aggregator/multichain-aggregator-logic/src/types/search_results.rs (1)

190-223: Redirect model + conversion to CheckRedirectResponse look correct and frontend‑friendly

Using #[derive(strum::Display)] with #[strum(serialize_all = "lowercase")] on RedirectType ensures the type string matches the expected "block" | "transaction" | "address" shape, and the From<Redirect> impl always sets redirect = true with optional parameter/chain_id, leaving the “no redirect” case to the default response.

If you anticipate logging or reusing Redirect/RedirectType in tests, consider adding Debug/Clone derives to both types for convenience; otherwise this minimal API is sufficient. Please also confirm that consumers expecting lowercase type strings (e.g., frontend proxyResponse types) are aligned with this serialization.

multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs (1)

119-126: Centralizing SearchContext construction for quick search and redirects is a solid cleanup

The new search_context(&self, is_aggregated) helper cleanly encapsulates SearchContext wiring (cluster reference, cloned DB wrapped in Arc, and domain_primary_chain_id), and reusing it in both quick_search and check_redirect keeps those flows consistent and avoids duplicating setup logic.

If SearchContext usage expands further, you could consider storing Arc<DatabaseConnection> directly on Cluster to avoid repeated Arc::new(self.db.clone()), but that’s a micro-optimization and not required now.

Also applies to: 855-876

multichain-aggregator/multichain-aggregator-logic/src/services/quick_search.rs (1)

254-260: Use limit=1 for efficiency in Domain redirect search.

The Domain search uses QUICK_SEARCH_NUM_ITEMS (50) but only needs the first result via .next(). This fetches unnecessary data.

Apply this diff to improve efficiency:

             SearchTerm::Domain(query) => search_context
                 .cluster
                 .search_domains_cached(
                     query,
                     vec![search_context.domain_primary_chain_id],
-                    QUICK_SEARCH_NUM_ITEMS,
+                    1,
                     None,
                 )
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 7338d5a and 0377265.

⛔ Files ignored due to path filters (1)
  • multichain-aggregator/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (9)
  • multichain-aggregator/Cargo.toml (1 hunks)
  • multichain-aggregator/multichain-aggregator-logic/Cargo.toml (1 hunks)
  • multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs (6 hunks)
  • multichain-aggregator/multichain-aggregator-logic/src/services/quick_search.rs (4 hunks)
  • multichain-aggregator/multichain-aggregator-logic/src/types/search_results.rs (1 hunks)
  • multichain-aggregator/multichain-aggregator-proto/proto/v1/api_config_http.yaml (1 hunks)
  • multichain-aggregator/multichain-aggregator-proto/proto/v1/cluster-explorer.proto (2 hunks)
  • multichain-aggregator/multichain-aggregator-proto/swagger/v1/multichain-aggregator.swagger.yaml (2 hunks)
  • multichain-aggregator/multichain-aggregator-server/src/services/cluster_explorer.rs (1 hunks)
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2024-12-10T16:24:23.028Z
Learnt from: bragov4ik
Repo: blockscout/blockscout-rs PR: 1137
File: stats/stats/Cargo.toml:17-17
Timestamp: 2024-12-10T16:24:23.028Z
Learning: When a dependency like `trait-variant` is correctly defined under `[workspace.dependencies]` in the root `Cargo.toml`, it should not be flagged as improperly defined in workspace crates.

Applied to files:

  • multichain-aggregator/multichain-aggregator-logic/Cargo.toml
📚 Learning: 2025-09-25T16:24:01.081Z
Learnt from: lok52
Repo: blockscout/blockscout-rs PR: 1518
File: multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs:664-670
Timestamp: 2025-09-25T16:24:01.081Z
Learning: In multichain-aggregator token search caching, the cluster name (self.name) provides cluster-level cache isolation but does not prevent intra-cluster cache collisions when different chain_ids subsets are used with identical query parameters.

Applied to files:

  • multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs
🧬 Code graph analysis (4)
multichain-aggregator/multichain-aggregator-server/src/services/cluster_explorer.rs (3)
multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs (2)
  • check_redirect (872-876)
  • new (74-110)
multichain-aggregator/multichain-aggregator-logic/src/services/quick_search.rs (1)
  • check_redirect (68-78)
multichain-aggregator/multichain-aggregator-logic/src/types/search_results.rs (1)
  • new (205-211)
multichain-aggregator/multichain-aggregator-logic/src/types/search_results.rs (1)
multichain-search/frontend/types/proxyResponse.ts (3)
  • Block (52-57)
  • Transaction (59-63)
  • Address (45-50)
multichain-aggregator/multichain-aggregator-logic/src/services/quick_search.rs (3)
multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs (5)
  • check_redirect (872-876)
  • search_context (119-126)
  • active_chain_ids (129-141)
  • active_chain_ids (152-152)
  • new (74-110)
multichain-aggregator/multichain-aggregator-logic/src/types/search_results.rs (2)
  • address (109-120)
  • new (205-211)
multichain-aggregator/multichain-aggregator-logic/src/services/filecoin.rs (1)
  • try_filecoin_address_to_evm_address (6-31)
multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs (1)
multichain-aggregator/multichain-aggregator-logic/src/services/quick_search.rs (3)
  • quick_search (24-66)
  • try_parse_address (278-282)
  • check_redirect (68-78)
⏰ 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). (2)
  • GitHub Check: Linting / lint
  • GitHub Check: Unit, doc and integration tests
🔇 Additional comments (13)
multichain-aggregator/Cargo.toml (1)

79-79: strum workspace dependency and features look correctly wired

Defining strum = { version = "0.27", default-features = false, features = ["derive"] } at the workspace level matches the usage pattern in the logic crate (derive macros via strum) and keeps default features off while enabling the proc-macro exports.

If you haven’t already, please run cargo tree -d strum to confirm there’s a single strum version and feature set in the workspace.

multichain-aggregator/multichain-aggregator-logic/Cargo.toml (1)

34-34: Logic crate’s use of workspace strum with extra std feature is appropriate

Opting into strum = { workspace = true, features = ["std"] } here correctly augments the workspace-level strum definition with derive so the Display derive in search_results.rs works under a unified feature set, without re-specifying version or defaults. Based on learnings.

When you run CI or cargo build -p multichain-aggregator-logic, please confirm there are no MSRV or feature-compat issues with strum 0.27.

multichain-aggregator/multichain-aggregator-proto/proto/v1/api_config_http.yaml (1)

104-106: HTTP rule for CheckRedirect matches proto and existing conventions

The selector and path (/api/v1/clusters/{cluster_id}/search:check-redirect) are consistent with the ClusterExplorerService proto and mirror the existing search:quick mapping; q will correctly flow as a query parameter from the request message.

multichain-aggregator/multichain-aggregator-server/src/services/cluster_explorer.rs (1)

354-369: check_redirect handler correctly normalizes Option<Redirect> into the response

Delegating to cluster.check_redirect(&inner.q) and using .map(|r| r.into()).unwrap_or_default() cleanly maps Some to a populated CheckRedirectResponse and None to the default “no redirect” payload, while reusing the existing ServiceErrorStatus conversion.

multichain-aggregator/multichain-aggregator-proto/proto/v1/cluster-explorer.proto (1)

34-35: CheckRedirect RPC and its request/response types align with server and logic layers

The new CheckRedirect(CheckRedirectRequest) returns (CheckRedirectResponse) method and message shapes (cluster_id/q in the request; redirect flag plus optional type/parameter/chain_id in the response) match the logic layer’s Redirect conversion and the server’s ClusterExplorer::check_redirect implementation.

Also applies to: 327-337

multichain-aggregator/multichain-aggregator-proto/swagger/v1/multichain-aggregator.swagger.yaml (1)

666-688: Swagger path and v1CheckRedirectResponse schema are consistent with the proto

The /api/v1/clusters/{cluster_id}/search:check-redirect operation (with cluster_id path and optional q query) and the v1CheckRedirectResponse definition accurately reflect the CheckRedirectRequest/CheckRedirectResponse proto messages and the server handler’s behavior.

Also applies to: 1471-1481

multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs (1)

578-626: Using SearchTerm::try_parse_address unifies address parsing across search flows

Switching prepare_addresses_query to SearchTerm::try_parse_address(&query) ensures address detection for address/domain/contract-name searches matches the same heuristics used by quick search and redirect resolution, while preserving the existing domain-with-TLD and contract-name fallback behavior.

multichain-aggregator/multichain-aggregator-logic/src/services/quick_search.rs (6)

8-13: LGTM! Imports updated correctly for redirect functionality.

The new imports for Redirect and RedirectType are necessary for the redirect-check capability introduced in this PR.


68-78: LGTM! Clean implementation of redirect-check capability.

The function correctly delegates parsing and redirect resolution to helper methods, with appropriate error handling.


237-239: Verify the optimistic redirect behavior for AddressHash.

Unlike Hash and Domain cases, AddressHash creates a redirect without verifying the address exists in the cluster. This could redirect to non-existent addresses.

If this optimistic behavior is intentional (e.g., addresses conceptually always exist), consider adding a comment explaining the design decision. Otherwise, consider checking address existence similar to the other cases.


274-286: LGTM! Good extraction of parsing utilities.

The new public parsing helpers improve code reusability and maintain existing functionality (including Filecoin address support). The try_* naming convention clearly indicates fallible operations.


289-307: Verify the Domain catch-all behavior and BlockNumber exclusion.

This function treats any query ≥ MIN_QUERY_LENGTH that's not a hash or address as a Domain. This means:

  1. Numeric queries like "1234" are treated as domains for redirects (not block numbers)
  2. BlockNumber is excluded from redirect logic entirely

This differs from parse_search_terms (Line 324) which would parse "1234" as a BlockNumber. Confirm this is the intended redirect behavior.

If intentional, consider adding a doc comment explaining that redirects only support Hash, Address, and Domain types.


309-337: LGTM! Good refactoring to use parsing helpers.

The function now reuses the extracted parsing utilities, improving maintainability while preserving existing behavior.

Copy link
Contributor

@bragov4ik bragov4ik left a comment

Choose a reason for hiding this comment

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

I'm not really in the context of what's the meaning of redirect and checking, but LGTM :)

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 (2)
multichain-aggregator/multichain-aggregator-proto/swagger/v1/multichain-aggregator.swagger.yaml (2)

701-723: Add enum constraint to the type field and document response fields.

The endpoint definition looks structurally sound. However, the response schema needs refinement:

  1. type field should define valid enum values (Block, Transaction, Address per the PR summary) rather than leaving it as a bare string. This clarifies the API contract for consumers.

  2. Missing descriptions: All response fields lack descriptions. Add brief docs explaining what each field represents and when it's populated (e.g., whether type/parameter/chain_id are only present when redirect=true).

  /api/v1/clusters/{cluster_id}/search:check-redirect:
    get:
      operationId: ClusterExplorerService_CheckRedirect
      responses:
        "200":
          description: A successful response.
          schema:
            $ref: '#/definitions/v1CheckRedirectResponse'

1518-1528: Define enum constraint for type field and add field descriptions.

The response schema definition should document each field and constrain the type field to valid redirect type values:

  v1CheckRedirectResponse:
    type: object
    properties:
      redirect:
        type: boolean
+       description: Whether the search query should redirect to a specific entity.
      type:
        type: string
+       description: The type of entity to redirect to (Block, Transaction, or Address). Only present if redirect is true.
+       enum:
+         - Block
+         - Transaction
+         - Address
      parameter:
        type: string
+       description: The parsed parameter value (e.g., block number, transaction hash, or address). Only present if redirect is true.
      chain_id:
        type: string
+       description: The chain ID for the redirect target. Only present if redirect is true.
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0377265 and a60e2df.

⛔ Files ignored due to path filters (1)
  • multichain-aggregator/Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (5)
  • multichain-aggregator/Cargo.toml (1 hunks)
  • multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs (6 hunks)
  • multichain-aggregator/multichain-aggregator-proto/proto/v1/api_config_http.yaml (1 hunks)
  • multichain-aggregator/multichain-aggregator-proto/swagger/v1/multichain-aggregator.swagger.yaml (2 hunks)
  • multichain-aggregator/multichain-aggregator-server/src/services/cluster_explorer.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • multichain-aggregator/multichain-aggregator-proto/proto/v1/api_config_http.yaml
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-09-25T16:24:01.081Z
Learnt from: lok52
Repo: blockscout/blockscout-rs PR: 1518
File: multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs:664-670
Timestamp: 2025-09-25T16:24:01.081Z
Learning: In multichain-aggregator token search caching, the cluster name (self.name) provides cluster-level cache isolation but does not prevent intra-cluster cache collisions when different chain_ids subsets are used with identical query parameters.

Applied to files:

  • multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs
🧬 Code graph analysis (2)
multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs (2)
multichain-aggregator/multichain-aggregator-logic/src/services/quick_search.rs (3)
  • quick_search (24-66)
  • try_parse_address (278-282)
  • check_redirect (68-78)
multichain-aggregator/multichain-aggregator-logic/src/types/search_results.rs (2)
  • new (205-211)
  • address (109-120)
multichain-aggregator/multichain-aggregator-server/src/services/cluster_explorer.rs (3)
multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs (2)
  • check_redirect (873-877)
  • new (75-111)
multichain-aggregator/multichain-aggregator-logic/src/services/quick_search.rs (1)
  • check_redirect (68-78)
multichain-aggregator/multichain-aggregator-logic/src/types/search_results.rs (1)
  • new (205-211)
⏰ 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). (1)
  • GitHub Check: Docker build and docker push / build-and-push
🔇 Additional comments (7)
multichain-aggregator/Cargo.toml (1)

80-80: The strum dependency addition is well-placed and uses appropriate feature flags. The latest stable version is 0.27.2, so the specified 0.27 constraint is current, and there are no security advisories for strum.

multichain-aggregator/multichain-aggregator-logic/src/services/cluster.rs (5)

18-18: LGTM: Import additions support new redirect functionality.

The new imports (SearchContext, SearchTerm, Redirect) align with the redirect-checking feature introduced in this PR.

Also applies to: 30-30


120-127: LGTM: Helper method reduces duplication.

The search_context helper centralizes SearchContext construction, improving maintainability. The Arc wrapping of the database connection aligns with the SearchContext API requirements shown in the relevant snippets.


589-589: LGTM: Centralized address parsing improves consistency.

Using SearchTerm::try_parse_address consolidates address parsing logic (including Filecoin address support) in one place, as shown in the relevant snippets.


862-862: LGTM: Refactored to use the new search_context helper.

This reduces code duplication and improves maintainability.


873-877: Confirm the intentional design of hardcoded is_aggregated=false in check_redirect.

The method hardcodes is_aggregated=false, ensuring redirects always flatten aggregated addresses. This differs from quick_search, which parameterizes this behavior. Verify this design choice is intentional and document why redirects should not support aggregation modes.

multichain-aggregator/multichain-aggregator-server/src/services/cluster_explorer.rs (1)

353-368: No action needed—input handling and default response semantics are correct.

The query string is properly validated: it's trimmed at both the check_redirect entry point (query.trim()) and within parse_redirect_search_term, which returns None for empty or too-short inputs. This prevents invalid queries from propagating downstream.

The default response semantics are sound: CheckRedirectResponse defaults to redirect: false with optional fields empty, which correctly represents "no redirect available" when Option::None is encountered. The From<Redirect> implementation sets redirect: true and populates the optional type, parameter, and chain_id fields only when a redirect exists.

@lok52 lok52 merged commit 51989e9 into main Dec 10, 2025
6 checks passed
@lok52 lok52 deleted the lok52/multi-search-redirect branch December 10, 2025 10:52
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feat New feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants