Skip to content

Conversation

lklimek
Copy link
Contributor

@lklimek lklimek commented Aug 4, 2025

Issue being fixed or feature implemented

What was done?

How Has This Been Tested?

Breaking Changes

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

  • New Features

    • RS‑DAPI: new Rust DAPI service offering gRPC + JSON‑RPC endpoints, streaming (blocks/txs/masternodes), WebSocket/ZMQ subscriptions, caching, access logs, Prometheus metrics, CLI, example client and migration tracker.
  • Infrastructure

    • Docker/Compose and CI: rs‑dapi build/runtime image and compose service/profile added; release workflow job; tooling/version bumps and non‑interactive/privacy install flags.
  • Documentation

    • READMEs, DESIGN, TODO and dashmate docs updated with rs‑dapi configuration and examples.
  • Tests

    • New unit/integration tests and e2e adjustments to include rs‑dapi image builds.
  • Chores

    • Workspace/package version bumps, config schema & migrations, and misc housekeeping.

Copy link
Contributor

coderabbitai bot commented Aug 4, 2025

Walkthrough

Adds a new Rust DAPI (rs-dapi) service and rs-dash-event-bus crate, integrates rs-dapi across build/CI/docker/dashmate, adds clients/services/streaming/logging/metrics/caching/configs/migrations/docs/tests, and performs many version bumps and workspace updates.

Changes

Cohort / File(s) Change Summary
rs-dapi crate (new)
packages/rs-dapi/Cargo.toml, packages/rs-dapi/src/*, packages/rs-dapi/*.md, packages/rs-dapi/examples/*, packages/rs-dapi/.env.example
New Rust DAPI: config loader, CLI, Core/Drive/Tenderdash clients, gRPC + JSON‑RPC servers, JsonRpcTranslator, Platform/Core/Streaming services, streaming (ZMQ, subscriptions, masternode sync), caching (LruResponseCache), logging (access logs + middleware), Prometheus metrics + middleware, Workers, utils, tests, examples, docs, many public types/modules.
Event bus crate (new)
packages/rs-dash-event-bus/src/*, packages/rs-dash-event-bus/Cargo.toml, packages/rs-dash-event-bus/src/lib.rs
New in-process EventBus with Filter trait, SubscriptionHandle, add/remove subscriptions, publish/notify semantics, optional metrics, and tests; public API re-exported.
Build / Docker / CI
.devcontainer/Dockerfile, Dockerfile, README.md, .github/workflows/*, packages/dashmate/docker-compose.build.rs-dapi.yml
Add rs-dapi build/runtime stages and compose snippet; bumped wasm-bindgen-cli (0.2.100→0.2.103), cargo-chef, RocksDB; make cargo-binstall non-interactive and disable telemetry; add release job for rs-dapi image and CI matrix updates; README install bump.
Workspace & versions
Cargo.toml, .github/package-filters/rs-packages.yml, many packages/*/Cargo.toml, many package.json
Add workspace members packages/rs-dapi and packages/rs-dash-event-bus; bump many package versions to 2.1.0-pr.2716.1; update dependency revisions and feature lists across crates.
Dashmate config & compose
packages/dashmate/src/config/*, packages/dashmate/docker-compose*.yml, packages/dashmate/docs/*, packages/dashmate/src/listr/tasks/*, scripts/configure_dashmate.sh, packages/dashmate/test/*
Add platform.dapi.rsDapi schema/defaults and deprecated flag, migrations, env generation and path handling, profile selection (rs vs deprecated JS DAPI), include rs_dapi compose service and build snippet, access log mounts, metrics port offsets, and e2e toggles.
Protocol translation & JSON‑RPC
packages/rs-dapi/src/protocol/jsonrpc_translator/*
New JSON‑RPC types, translator, params parsing, and error mapping from DapiError to JSON‑RPC envelopes.
Clients, services & streaming
packages/rs-dapi/src/clients/*, packages/rs-dapi/src/services/*, packages/rs-dapi/src/services/streaming_service/*
New Core/Drive/Tenderdash clients, Platform/Core/Streaming service implementations, streaming flows (transactions, block headers, masternode list), masternode list sync, ZMQ listener, SubscriberManager and extensive streaming logic (live + historical, bloom matching, merkle proofs).
Config, logging, metrics, utils & errors
packages/rs-dapi/src/config/*, packages/rs-dapi/src/logging/*, packages/rs-dapi/src/metrics.rs, packages/rs-dapi/src/error.rs, packages/rs-dapi/src/utils.rs
New config schema and loaders, flexible deserializers, access log formatting + middleware, logging init, Prometheus metrics subsystem + middleware, unified DapiError with conversions, and utility deserializers/helpers.
Caching
packages/rs-dapi/src/cache.rs
New LruResponseCache, CacheKey, serialization helpers, TTL-aware get/get_or_try_insert and tests.
Platform service features
packages/rs-dapi/src/services/platform_service/*
PlatformServiceImpl with cached GetStatus (health + TTL), broadcast_state_transition with duplicate handling, wait_for_state_transition_result, Tenderdash error mapping, and many drive_method! delegations.
Streaming plumbing & helpers
packages/rs-dapi/src/services/streaming_service/*
Bloom filter matching, transaction matching, merkle/proof workflows, masternode list sync, transaction/block header streams, subscriber plumbing, ZMQ processing and worker orchestration, plus tests.
Dashmate & JS repo wiring
packages/wallet-lib/*, packages/dashmate/src/test/constants/services.js, packages/dashmate/docker-compose.yml
JS changes: import/use tweaks, enhanced logging, parseRawInstantLocks now skips invalid entries, rename/adjust test constants for rs_dapi, add rs_dapi service and adjust DAPI profiles in docker-compose.
Misc / wasm / benches / formatting
packages/rs-dpp/*, packages/wasm-*/*, packages/wasm-sdk/*, bench files, small JS tweaks
Qualified getrandom calls, dependency version/feature formatting, wasm-bindgen bumps, bench updates, small test assertions and formatting tweaks.
Changelog & metadata
CHANGELOG.md, top-level package.json, many manifests
New changelog entry and many manifest/version bumps and minor metadata edits.

Sequence Diagram(s)

%%{init: {"themeVariables": {"primaryColor":"#8FB9A8", "secondaryColor":"#DCEFE0"}}}%%
sequenceDiagram
    participant Client
    participant JSONRPC as JSON‑RPC HTTP
    participant Translator as JsonRpcTranslator
    participant Platform as PlatformServiceImpl
    participant Drive as DriveClient
    participant Core as CoreClient
    participant Tender as TenderdashClient

    Client->>JSONRPC: POST JSON‑RPC request
    JSONRPC->>Translator: parse & translate -> JsonRpcCall
    Translator->>Platform: invoke JsonRpcCall
    alt needs Drive
        Platform->>Drive: Drive RPC (cached)
        Drive-->>Platform: Drive response
    end
    alt needs Core
        Platform->>Core: Core RPC (cached)
        Core-->>Platform: Core response
    end
    alt needs Tenderdash
        Platform->>Tender: Tenderdash RPC
        Tender-->>Platform: Tenderdash response
    end
    Platform-->>Translator: assemble result
    Translator->>JSONRPC: JSON‑RPC response
    JSONRPC-->>Client: HTTP response
Loading
%%{init: {"themeVariables": {"primaryColor":"#F2C1C1", "noteBackground":"#FFFBE6"}}}%%
sequenceDiagram
    participant CoreNode as Dash Core (ZMQ)
    participant ZMQ as ZmqListener
    participant Bus as SubscriberManager/EventBus
    participant Stream as StreamingService
    participant Client

    CoreNode->>ZMQ: publish raw events (tx/block/locks)
    ZMQ->>Bus: broadcast StreamingEvent
    Client->>Stream: subscribe(filter)
    Stream->>Bus: add_subscription(filter)
    Bus-->>Stream: SubscriptionHandle
    Bus-->>Client: deliver matching events
Loading

Estimated code review effort

🎯 5 (Critical) | ⏱️ ~120+ minutes

Possibly related PRs

Suggested reviewers

  • QuantumExplorer

Poem

"🐇 I hopped through code and found new ground,
Rust DAPI rose where bindings abound.
Caches keep crumbs, ZMQ sings along,
Metrics and logs hum a steady song.
A carrot of code — compact, brave, and sound!"

Pre-merge checks and finishing touches

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The pull request title "refactor(dapi): rewrite dapi in Rust as rs-dapi" directly and clearly describes the primary change in the changeset. The pull request involves a comprehensive rewrite of the DAPI (Distributed API) service from JavaScript to Rust, introducing a new rs-dapi Rust implementation with supporting modules, integration into build systems, Docker configurations, dashmate setup, and deprecation of the legacy JS DAPI. The title is specific, uses conventional commit format, and clearly communicates the essential intent without vague terminology.
Docstring Coverage ✅ Passed Docstring coverage is 81.82% 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 refactor/dapi-rewrite-to-rust

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

github-actions bot commented Aug 4, 2025

✅ gRPC Query Coverage Report

================================================================================
gRPC Query Coverage Report - NEW QUERIES ONLY
================================================================================

Total queries in proto: 47
Previously known queries: 47
New queries found: 0


================================================================================
Summary:
--------------------------------------------------------------------------------
No new queries found

Total known queries: 47
  - Implemented: 44
  - Not implemented: 2
  - Excluded: 1

Not implemented queries:
  - getConsensusParams
  - getTokenPreProgrammedDistributions

Copy link

github-actions bot commented Sep 15, 2025

✅ DashSDKFFI.xcframework built for this PR.

SwiftPM (host the zip at a stable URL, then use):

.binaryTarget(
  name: "DashSDKFFI",
  url: "https://your.cdn.example/DashSDKFFI.xcframework.zip",
  checksum: "c71ab82138b16feb0b42bdb3b1997a68263177dc2c66e801690a0c71a40885e2"
)

Xcode manual integration:

  • Download 'DashSDKFFI.xcframework' artifact from the run link above.
  • Drag it into your app target (Frameworks, Libraries & Embedded Content) and set Embed & Sign.
  • If using the Swift wrapper package, point its binaryTarget to the xcframework location or add the package and place the xcframework at the expected path.

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)
packages/rs-dapi/src/clients/tenderdash_client.rs (3)

318-377: Consider per-request timeout for flexibility (optional).

The post method correctly uses .json(request) to avoid manual serialization and leverages the global timeout configured in the client builder (lines 390-391). Error handling is comprehensive with appropriate logging levels.

However, if certain RPC calls need different timeout behavior, consider adding a per-request timeout parameter:

 async fn post<T, R>(&self, request: &R) -> DAPIResult<T>

If needed, you could add an optional timeout parameter:

async fn post_with_timeout<T, R>(&self, request: &R, timeout: Option<Duration>) -> DAPIResult<T>
where
    T: serde::de::DeserializeOwned + Debug,
    R: Serialize + Debug,
{
    let mut req = self.client.post(&self.base_url)
        .header("Content-Type", "application/json")
        .json(request);
    
    if let Some(t) = timeout {
        req = req.timeout(t);
    }
    
    // ... rest of the method
}

This is optional since the global timeout should handle most cases.


454-476: Consider the implications of error masking in net_info.

The net_info method returns default values when the RPC call fails, masking technical failures from the caller. While the error is logged, this could hide connectivity or configuration issues from upstream code that might want to handle them differently.

Consider one of these approaches:

  1. Propagate the error and let callers decide whether to use defaults:
-pub async fn net_info(&self) -> DAPIResult<NetInfoResponse> {
-    match self.net_info_internal().await {
-        Ok(netinfo) => {
-            trace!("Successfully retrieved Tenderdash net_info");
-            Ok(netinfo)
-        }
-        Err(e) => {
-            error!(
-                error = ?e,
-                "Failed to get Tenderdash net_info - technical failure, returning defaults"
-            );
-            Ok(NetInfoResponse::default())
-        }
-    }
-}
+pub async fn net_info(&self) -> DAPIResult<NetInfoResponse> {
+    self.net_info_internal().await
+}
  1. Add a separate method for error-tolerant behavior:
pub async fn net_info_or_default(&self) -> NetInfoResponse {
    self.net_info().await.unwrap_or_default()
}

If the current behavior (returning defaults on failure) is intentional for specific operational reasons, consider documenting why this design choice was made in the method's doc comment.


379-419: Clarify WebSocket listener spawning location.

TenderdashClient::new only constructs the client; the retrying WebSocket listener loop is started in PlatformServiceImpl::new (packages/rs-dapi/src/services/platform_service/mod.rs:123).
Optionally validate that ws_uri begins with ws:// or wss:// before creating the TenderdashWebSocketClient.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4a9d89c and 093f711.

📒 Files selected for processing (2)
  • packages/rs-dapi/src/clients/tenderdash_client.rs (1 hunks)
  • packages/rs-dapi/src/services/platform_service/mod.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/rs-dapi/src/services/platform_service/mod.rs
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/rs-dapi/src/clients/tenderdash_client.rs
packages/rs-*/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

packages/rs-*/**/*.rs: Use rustfmt defaults for Rust code (format via cargo fmt --all)
Keep Rust code clippy-clean (cargo clippy)
Name Rust modules in snake_case
Use PascalCase for Rust types
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-dapi/src/clients/tenderdash_client.rs
🧠 Learnings (3)
📓 Common learnings
Learnt from: shumkov
PR: dashpay/platform#2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:69-125
Timestamp: 2024-10-24T05:07:35.892Z
Learning: Future development plans involve rewriting DAPI into Rust, as the rest of the project has already migrated.
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/dashmate/src/test/constants/services.js:4-4
Timestamp: 2025-10-15T14:45:30.824Z
Learning: In the dashmate codebase (packages/dashmate), during the DAPI Rust migration (rs-dapi), the old service keys `dapi_api` and `dapi_core_streams` are intentionally kept in `generateEnvsFactory.js` for backward compatibility even though the test constants in `src/test/constants/services.js` have been updated to use `rs_dapi`. These deprecated keys will be removed in a future PR after the transition is complete.
📚 Learning: 2025-10-09T15:59:33.162Z
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/rs-dapi/src/clients/tenderdash_client.rs:0-0
Timestamp: 2025-10-09T15:59:33.162Z
Learning: In the rs-dapi codebase, the `Workers::spawn` method (in `packages/rs-dapi/src/sync.rs`) accepts futures that return `Result<O, E>`, not `()`. Its signature is `fn spawn<F, O, E>(&self, fut: F) where F: Future<Output = Result<O, E>> + Send + 'static`. The method handles error logging internally, so spawned tasks should return Results directly without additional error handling wrappers.

Applied to files:

  • packages/rs-dapi/src/clients/tenderdash_client.rs
📚 Learning: 2025-10-09T15:59:41.943Z
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/rs-dapi/src/clients/tenderdash_client.rs:0-0
Timestamp: 2025-10-09T15:59:41.943Z
Learning: In packages/rs-dapi, the Workers::spawn method accepts futures that return Result<O, E> where E: Into<DapiError>. It handles error logging internally, so spawned tasks should return Result types rather than handling errors inside the task. The Workers implementation automatically logs worker failures.

Applied to files:

  • packages/rs-dapi/src/clients/tenderdash_client.rs
🧬 Code graph analysis (1)
packages/rs-dapi/src/clients/tenderdash_client.rs (5)
packages/rs-dapi/src/utils.rs (3)
  • deserialize_string_number_or_null (147-163)
  • deserialize_string_or_number (23-86)
  • generate_jsonrpc_id (12-21)
packages/rs-dapi/src/config/mod.rs (7)
  • std (225-225)
  • default (47-54)
  • default (136-145)
  • default (149-153)
  • default (157-162)
  • default (166-174)
  • default (198-205)
packages/rs-dapi/src/clients/tenderdash_websocket.rs (1)
  • new (78-88)
packages/rs-dapi/src/server/mod.rs (1)
  • new (29-77)
packages/rs-dapi/src/error.rs (2)
  • from_tenderdash_error (170-172)
  • client (201-203)
⏰ 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). (79)
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
🔇 Additional comments (5)
packages/rs-dapi/src/clients/tenderdash_client.rs (5)

1-34: LGTM! Well-documented client structure.

The imports are clean, and the TenderdashClient struct is properly documented with clear explanations of tracing behavior and error handling architecture. The use of ClientWithMiddleware for tracing and Option<Arc<TenderdashWebSocketClient>> for optional WebSocket support is appropriate.


36-85: LGTM! Clean JSON-RPC request/response types.

The generic TenderdashResponse<T> and JsonRpcRequest<T> structures correctly implement JSON-RPC 2.0 protocol. The use of lifetime parameters in parameter structs (e.g., BroadcastTxParams<'a>) avoids unnecessary allocations.


87-316: LGTM! Comprehensive data models with proper deserialization.

The data models correctly handle Tenderdash's varied JSON formats using custom deserializers (deserialize_string_or_number, deserialize_string_number_or_null). The #[serde(default)] annotations ensure resilience to missing fields. The ExecTxResult::is_empty() helper method is a useful addition for detecting absent results.


478-512: LGTM! Consistent RPC wrapper implementations.

All RPC methods (broadcast_tx, check_tx, unconfirmed_tx, tx) follow a consistent pattern with proper parameter structures and logging. The implementations are clean and straightforward.


513-541: LGTM! Graceful WebSocket subscription handling.

The subscription methods (subscribe_to_transactions, subscribe_to_blocks) handle the absence of a WebSocket client gracefully by returning a receiver that will never receive messages. This allows callers to subscribe without explicitly checking WebSocket availability, and provides is_websocket_connected() for explicit state checking when needed.

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)
packages/rs-dapi/src/main.rs (3)

45-50: Consider whether full README is appropriate for CLI help.

Including the entire README as long_about may produce very long help text when users run rs-dapi --help. Typically, CLI tools provide a concise description in the help output and refer users to external documentation for details.

Consider either:

  • Extracting a shorter "About" section from the README for CLI help
  • Creating a separate short description specifically for the CLI
  • Keeping only the first paragraph of the README

139-157: Past review comment properly addressed; consider improving error pattern matching.

The incorrect --force flag references have been successfully removed and replaced with appropriate guidance to check upstream services. Well done!

However, Line 145 uses msg.contains("Failed to connect") which is fragile as it depends on exact error message text. Consider having the DapiError::Client variant carry structured error types instead of strings, or add a specific DapiError::ConnectionFailed variant for connection failures.

Example refactor for more robust error handling:

// In error.rs, add a specific variant:
ConnectionFailed(String),

// Then match more precisely:
DapiError::Client(msg) => {
    error!(error = %msg, "Client initialization failed. Check drive-abci and tenderdash and try again.");
    return Err(format!("Client error: {}", e));
}
DapiError::ConnectionFailed(msg) => {
    error!(error = %msg, "Client connection failed. Check drive-abci and tenderdash and try again.");
    return Err(format!("Connection error: {}", e));
}

264-281: Consider making worker thread count configurable.

The main function correctly initializes the Tokio runtime and handles CLI execution. However, the worker thread count is hardcoded to 4 (line 267). For a server application, you might want to make this configurable or use Tokio's default (which matches available CPU cores).

Consider one of these approaches:

  • Use .worker_threads(num_cpus::get()) to match CPU count
  • Add a CLI flag or environment variable to configure thread count
  • Remove the .worker_threads(4) call to use Tokio's default behavior

Otherwise, the structure is clean and follows Rust CLI best practices.

Example to use CPU count:

 fn main() -> Result<(), ExitCode> {
     let rt = tokio::runtime::Builder::new_multi_thread()
-        .worker_threads(4)
+        .worker_threads(num_cpus::get())
         .enable_all()
         .build()
         .expect("Failed to create Tokio runtime");

Or simply use Tokio's default:

 fn main() -> Result<(), ExitCode> {
     let rt = tokio::runtime::Builder::new_multi_thread()
-        .worker_threads(4)
         .enable_all()
         .build()
         .expect("Failed to create Tokio runtime");
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 093f711 and d512a69.

📒 Files selected for processing (1)
  • packages/rs-dapi/src/main.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/rs-dapi/src/main.rs
packages/rs-*/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

packages/rs-*/**/*.rs: Use rustfmt defaults for Rust code (format via cargo fmt --all)
Keep Rust code clippy-clean (cargo clippy)
Name Rust modules in snake_case
Use PascalCase for Rust types
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-dapi/src/main.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: shumkov
PR: dashpay/platform#2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:69-125
Timestamp: 2024-10-24T05:07:35.892Z
Learning: Future development plans involve rewriting DAPI into Rust, as the rest of the project has already migrated.
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/dashmate/src/test/constants/services.js:4-4
Timestamp: 2025-10-15T14:45:30.856Z
Learning: In the dashmate codebase (packages/dashmate), during the DAPI Rust migration (rs-dapi), the old service keys `dapi_api` and `dapi_core_streams` are intentionally kept in `generateEnvsFactory.js` for backward compatibility even though the test constants in `src/test/constants/services.js` have been updated to use `rs_dapi`. These deprecated keys will be removed in a future PR after the transition is complete.
🧬 Code graph analysis (1)
packages/rs-dapi/src/main.rs (5)
packages/rs-dapi/src/config/mod.rs (2)
  • std (225-225)
  • load_from_dotenv (224-226)
packages/rs-dapi/src/logging/mod.rs (1)
  • init_logging (18-43)
packages/rs-dapi/src/error.rs (1)
  • server (236-238)
packages/rs-dapi/src/server/mod.rs (2)
  • run (82-109)
  • new (29-77)
packages/rs-dapi/src/logging/access_log.rs (1)
  • new (261-272)
⏰ 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). (170)
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Formatting
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Formatting
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Formatting
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Formatting
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Formatting
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Formatting
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Formatting
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Formatting
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Formatting
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Formatting
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
🔇 Additional comments (5)
packages/rs-dapi/src/main.rs (5)

1-10: LGTM!

Imports are well-organized and all necessary dependencies are present.


12-39: LGTM!

The Commands enum is well-documented with clear descriptions. The warning about sensitive data in the Config subcommand is particularly important for security awareness.


176-199: LGTM!

Both helper functions follow standard CLI patterns. Using process::exit(1) for configuration loading failures is appropriate for command-line applications, and the logging configuration logic is clean.


201-238: LGTM!

These helper functions are well-implemented:

  • run_server correctly wraps the config in an Arc for sharing across components
  • dump_config appropriately warns about sensitive data before outputting
  • print_version provides clear version information

240-262: LGTM!

The shutdown_signal function correctly implements cross-platform graceful shutdown handling using tokio signals. The platform-specific implementations for Unix (SIGTERM/SIGINT) and non-Unix (Ctrl+C) are standard best practices.

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

♻️ Duplicate comments (3)
packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs (2)

42-54: Deserialization fallback issue persists.

The fallback behavior flagged in a previous review has not been addressed. When transaction deserialization fails, the code falls back to bloom.contains(raw_tx) (line 48), which:

  1. Silently degrades behavior and masks encoding/decoding bugs
  2. Uses semantically incorrect matching (raw bytes instead of structured transaction data)

The previous review recommended returning false for malformed transactions or propagating errors. This issue remains unresolved.

Apply this diff to return false on deserialization errors:

                Err(e) => {
-                    debug!(
+                    tracing::error!(
                        error = %e,
-                        "Failed to deserialize core transaction for bloom filter matching, falling back to contains()"
+                        "Failed to deserialize core transaction for bloom filter matching"
                    );
-                    match bloom.read() {
-                        Ok(guard) => guard.contains(raw_tx),
-                        Err(_) => {
-                            debug!("Failed to acquire read lock for bloom filter");
-                            false
-                        }
-                    }
+                    // Malformed transactions should not match
+                    false
                }

246-325: Failing test will break CI.

The test comment states "expected to FAIL with the current implementation" (lines 248-249), but the test lacks #[ignore] or #[should_panic] attributes. This will cause CI failures.

A previous review recommended adding #[ignore] with a TODO comment. This issue remains unresolved.

Apply this diff to prevent CI breakage:

 #[tokio::test]
+#[ignore] // TODO: Enable once filter persistence is implemented (track in issue)
 async fn test_bloom_update_persistence_across_messages() {
packages/rs-dapi/src/cache.rs (1)

237-261: Fix compile error: must wrap return value in Some().

At line 253, the function returns value (type T) but the signature specifies Option<T>. This will not compile.

Apply this diff:

     if inserted_at.elapsed() <= ttl {
         metrics::cache_hit(self.label.as_ref(), &method_label);

-        return value;
+        return Some(value);
     }

Note: This issue was previously flagged and marked as addressed in commits 7ec8fad to 11a8f1a, but appears to have been reintroduced or not fully applied.

🧹 Nitpick comments (5)
packages/platform-test-suite/lib/wait.js (1)

6-6: Consider conditional logging to reduce verbosity.

The console.debug call executes unconditionally for every wait, even when no description is provided (where it just logs the duration). While console.debug is typically filtered in CI/production, you might consider only logging when a description is explicitly provided to reduce noise:

-  console.debug(`Waiting for ${details}`);
+  if (description) {
+    console.debug(`Waiting for ${details}`);
+  }

This would make descriptive waits stand out more clearly in test logs.

packages/rs-dapi/src/server/metrics.rs (4)

166-173: Consider logging errors from the response builder.

The unwrap_or_else fallback at line 172 silently returns an empty body if the response builder fails. For observability, consider logging the error before returning the fallback response.

Apply this diff:

 async fn handle_metrics() -> axum::response::Response {
     let (body, content_type) = crate::metrics::gather_prometheus();
     axum::response::Response::builder()
         .status(200)
         .header(axum::http::header::CONTENT_TYPE, content_type)
         .body(axum::body::Body::from(body))
-        .unwrap_or_else(|_| axum::response::Response::new(axum::body::Body::from("")))
+        .unwrap_or_else(|e| {
+            tracing::error!("Failed to build metrics response: {}", e);
+            axum::response::Response::new(axum::body::Body::from(""))
+        })
 }

221-252: Consider adding explicit handling for FailedPrecondition.

The DapiError::FailedPrecondition variant exists (see error.rs:311 in the From<dashcore_rpc::Error> implementation) but falls through to the catch-all "internal error" label. For more accurate health reporting, consider adding an explicit case.

Apply this diff:

     match err {
         Configuration(_) => "configuration error",
         StreamingService(_) => "streaming service error",
         Client(_) | ClientGone(_) => "client error",
         ServerUnavailable(_, _) | Unavailable(_) | ServiceUnavailable(_) => "service unavailable",
         Server(_) => "server error",
         Serialization(_) | InvalidData(_) | NoValidTxProof(_) => "invalid data",
         Transport(_) | Http(_) | WebSocket(_) | Request(_) => "transport error",
         TenderdashClientError(_) => "tenderdash error",
         Status(_) => "upstream returned error",
         TaskJoin(_) => "internal task error",
         Io(_) => "io error",
         UrlParse(_) => "invalid url",
         Base64Decode(_) => "invalid base64 data",
         TransactionHashNotFound => "transaction hash missing",
         NotFound(_) => "not found",
         AlreadyExists(_) => "already exists",
         InvalidRequest(_) => "invalid request",
         InvalidArgument(_) => "invalid argument",
         ResourceExhausted(_) => "resource exhausted",
+        FailedPrecondition(_) => "failed precondition",
         Aborted(_) => "aborted",
         Timeout(_) => "timeout",
         Internal(_) => "internal error",
         ConnectionClosed => "connection closed",
         MethodNotFound(_) => "method not found",
         ZmqConnection(_) => "zmq connection error",
         _ => "internal error",
     }

47-47: Optionally make the health check timeout configurable.

The 3-second timeout is hardcoded. Depending on deployment environments (local dev vs. production with network latency), this duration might need adjustment. Consider adding a configuration option.


154-154: Optionally use ISO 8601 timestamp for better readability.

Unix timestamps (i64) are compact but less human-readable in JSON responses. Consider using an ISO 8601 string (e.g., chrono::Utc::now().to_rfc3339()) for easier debugging and log correlation.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d512a69 and 820d85d.

📒 Files selected for processing (12)
  • packages/platform-test-suite/lib/test/waitForBalanceToChange.js (1 hunks)
  • packages/platform-test-suite/lib/wait.js (1 hunks)
  • packages/platform-test-suite/lib/waitForBlocks.js (1 hunks)
  • packages/platform-test-suite/lib/waitForSTPropagated.js (1 hunks)
  • packages/platform-test-suite/test/e2e/withdrawals.spec.js (2 hunks)
  • packages/platform-test-suite/test/functional/core/getTransaction.spec.js (2 hunks)
  • packages/platform-test-suite/test/functional/dapi/subscribeToBlockHeadersWithChainLocksHandlerFactory.spec.js (3 hunks)
  • packages/rs-dapi/src/cache.rs (1 hunks)
  • packages/rs-dapi/src/clients/drive_client.rs (1 hunks)
  • packages/rs-dapi/src/server/metrics.rs (1 hunks)
  • packages/rs-dapi/src/services/platform_service/get_status.rs (1 hunks)
  • packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/rs-dapi/src/services/platform_service/get_status.rs
🧰 Additional context used
📓 Path-based instructions (4)
packages/platform-test-suite/**

📄 CodeRabbit inference engine (AGENTS.md)

packages/platform-test-suite/**: Keep end-to-end tests and helpers in packages/platform-test-suite
Keep all E2E tests exclusively in packages/platform-test-suite

Files:

  • packages/platform-test-suite/lib/waitForBlocks.js
  • packages/platform-test-suite/lib/waitForSTPropagated.js
  • packages/platform-test-suite/test/functional/dapi/subscribeToBlockHeadersWithChainLocksHandlerFactory.spec.js
  • packages/platform-test-suite/test/e2e/withdrawals.spec.js
  • packages/platform-test-suite/test/functional/core/getTransaction.spec.js
  • packages/platform-test-suite/lib/wait.js
  • packages/platform-test-suite/lib/test/waitForBalanceToChange.js
packages/**/**/*.{js,ts,jsx,tsx}

📄 CodeRabbit inference engine (AGENTS.md)

packages/**/**/*.{js,ts,jsx,tsx}: Adhere to ESLint with Airbnb/TypeScript configs for JS/TS code
Use camelCase for JS/TS variables and functions
Use PascalCase for JS/TS classes
Prefer kebab-case filenames within JS packages

Files:

  • packages/platform-test-suite/lib/waitForBlocks.js
  • packages/platform-test-suite/lib/waitForSTPropagated.js
  • packages/platform-test-suite/test/functional/dapi/subscribeToBlockHeadersWithChainLocksHandlerFactory.spec.js
  • packages/platform-test-suite/test/e2e/withdrawals.spec.js
  • packages/platform-test-suite/test/functional/core/getTransaction.spec.js
  • packages/platform-test-suite/lib/wait.js
  • packages/platform-test-suite/lib/test/waitForBalanceToChange.js
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/rs-dapi/src/server/metrics.rs
  • packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs
  • packages/rs-dapi/src/cache.rs
  • packages/rs-dapi/src/clients/drive_client.rs
packages/rs-*/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

packages/rs-*/**/*.rs: Use rustfmt defaults for Rust code (format via cargo fmt --all)
Keep Rust code clippy-clean (cargo clippy)
Name Rust modules in snake_case
Use PascalCase for Rust types
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-dapi/src/server/metrics.rs
  • packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs
  • packages/rs-dapi/src/cache.rs
  • packages/rs-dapi/src/clients/drive_client.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: shumkov
PR: dashpay/platform#2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:69-125
Timestamp: 2024-10-24T05:07:35.892Z
Learning: Future development plans involve rewriting DAPI into Rust, as the rest of the project has already migrated.
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/dashmate/src/test/constants/services.js:4-4
Timestamp: 2025-10-15T14:45:30.856Z
Learning: In the dashmate codebase (packages/dashmate), during the DAPI Rust migration (rs-dapi), the old service keys `dapi_api` and `dapi_core_streams` are intentionally kept in `generateEnvsFactory.js` for backward compatibility even though the test constants in `src/test/constants/services.js` have been updated to use `rs_dapi`. These deprecated keys will be removed in a future PR after the transition is complete.
🧬 Code graph analysis (7)
packages/platform-test-suite/test/functional/dapi/subscribeToBlockHeadersWithChainLocksHandlerFactory.spec.js (5)
packages/platform-test-suite/lib/test/waitForBalanceToChange.js (1)
  • wait (1-1)
packages/platform-test-suite/lib/waitForBlocks.js (1)
  • wait (1-1)
packages/platform-test-suite/lib/waitForSTPropagated.js (1)
  • wait (1-1)
packages/platform-test-suite/test/e2e/withdrawals.spec.js (2)
  • wait (3-3)
  • require (1-1)
packages/platform-test-suite/test/functional/core/getTransaction.spec.js (1)
  • wait (3-3)
packages/rs-dapi/src/server/metrics.rs (6)
packages/rs-dapi/src/logging/middleware.rs (1)
  • new (27-29)
packages/rs-dapi/src/metrics.rs (2)
  • new (400-402)
  • gather_prometheus (383-392)
packages/rs-dapi/src/error.rs (5)
  • timeout (251-253)
  • from (128-130)
  • from (135-137)
  • from (142-144)
  • from (302-333)
packages/rs-dapi/src/server/mod.rs (1)
  • new (29-77)
packages/rs-dapi/src/services/core_service.rs (1)
  • new (37-47)
packages/rs-dapi/src/services/platform_service/get_status.rs (1)
  • is_healthy (42-44)
packages/platform-test-suite/test/e2e/withdrawals.spec.js (5)
packages/platform-test-suite/lib/test/waitForBalanceToChange.js (1)
  • wait (1-1)
packages/platform-test-suite/lib/waitForBlocks.js (1)
  • wait (1-1)
packages/platform-test-suite/lib/waitForSTPropagated.js (1)
  • wait (1-1)
packages/platform-test-suite/test/functional/core/getTransaction.spec.js (1)
  • wait (3-3)
packages/platform-test-suite/test/functional/dapi/subscribeToBlockHeadersWithChainLocksHandlerFactory.spec.js (1)
  • wait (16-16)
packages/platform-test-suite/lib/wait.js (6)
packages/platform-test-suite/lib/test/waitForBalanceToChange.js (1)
  • wait (1-1)
packages/platform-test-suite/lib/waitForBlocks.js (1)
  • wait (1-1)
packages/platform-test-suite/lib/waitForSTPropagated.js (1)
  • wait (1-1)
packages/platform-test-suite/test/e2e/withdrawals.spec.js (1)
  • wait (3-3)
packages/platform-test-suite/test/functional/core/getTransaction.spec.js (1)
  • wait (3-3)
packages/platform-test-suite/test/functional/dapi/subscribeToBlockHeadersWithChainLocksHandlerFactory.spec.js (1)
  • wait (16-16)
packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs (3)
packages/rs-dapi/src/services/streaming_service/mod.rs (1)
  • summarize_streaming_event (87-129)
packages/rs-dapi/src/services/streaming_service/bloom.rs (1)
  • matches_transaction (55-101)
packages/rs-dash-event-bus/src/event_bus.rs (4)
  • id (234-236)
  • matches (16-16)
  • matches (429-431)
  • subscription_count (185-187)
packages/rs-dapi/src/cache.rs (4)
packages/rs-dapi/src/sync.rs (3)
  • fmt (61-64)
  • new (23-27)
  • default (112-114)
packages/rs-dapi/src/metrics.rs (7)
  • fmt (39-41)
  • new (400-402)
  • cache_hit (333-335)
  • cache_miss (338-340)
  • cache_memory_usage_bytes (348-352)
  • cache_memory_capacity_bytes (355-359)
  • cache_entries (362-366)
packages/rs-dapi/src/services/platform_service/mod.rs (1)
  • new (110-166)
packages/rs-dapi/src/clients/core_client.rs (6)
  • new (27-40)
  • new (465-469)
  • cache (135-137)
  • cache (182-184)
  • cache (245-247)
  • cache (324-326)
packages/rs-dapi/src/clients/drive_client.rs (4)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (2)
  • GetStatusRequest (5482-5497)
  • Version (5599-5618)
packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts (1)
  • PlatformClient (509-936)
packages/rs-dapi/src/services/platform_service/mod.rs (1)
  • new (110-166)
packages/rs-dapi/src/services/streaming_service/mod.rs (1)
  • new (168-187)
⏰ 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). (168)
  • GitHub Check: Rust packages (dpns-contract) / Tests
  • GitHub Check: Rust packages (dpns-contract) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Formatting
  • GitHub Check: Rust packages (dpns-contract) / Linting
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Check each feature
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (dpns-contract) / Tests
  • GitHub Check: Rust packages (dpns-contract) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Formatting
  • GitHub Check: Rust packages (dpns-contract) / Linting
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Check each feature
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (dpns-contract) / Tests
  • GitHub Check: Rust packages (dpns-contract) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Formatting
  • GitHub Check: Rust packages (dpns-contract) / Linting
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Check each feature
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (dpns-contract) / Tests
  • GitHub Check: Rust packages (dpns-contract) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Formatting
  • GitHub Check: Rust packages (dpns-contract) / Linting
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Check each feature
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (dpns-contract) / Tests
  • GitHub Check: Rust packages (dpns-contract) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Formatting
  • GitHub Check: Rust packages (dpns-contract) / Linting
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Check each feature
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (dpns-contract) / Tests
  • GitHub Check: Rust packages (dpns-contract) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Formatting
  • GitHub Check: Rust packages (dpns-contract) / Linting
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Check each feature
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (dpns-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Formatting
  • GitHub Check: Rust packages (dpns-contract) / Linting
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Check each feature
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (dpns-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Formatting
  • GitHub Check: Rust packages (dpns-contract) / Linting
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Check each feature
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (dpns-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Formatting
  • GitHub Check: Rust packages (dpns-contract) / Linting
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Check each feature
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (dpns-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Unused dependencies
  • GitHub Check: Rust packages (dpns-contract) / Formatting
  • GitHub Check: Rust packages (dpns-contract) / Linting
  • GitHub Check: Rust packages (wallet-utils-contract) / Tests
  • GitHub Check: Rust packages (wallet-utils-contract) / Unused dependencies
  • GitHub Check: Rust packages (wallet-utils-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Check each feature
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
🔇 Additional comments (22)
packages/platform-test-suite/lib/test/waitForBalanceToChange.js (1)

18-23: LGTM!

The enhanced wait message with attempt counter provides clear diagnostic context for balance change polling. The 1-indexed attempt counter is user-friendly.

packages/platform-test-suite/lib/waitForSTPropagated.js (1)

13-13: LGTM!

The descriptive message clearly indicates the purpose of this wait period.

packages/platform-test-suite/test/functional/core/getTransaction.spec.js (1)

31-31: LGTM!

The descriptive wait messages enhance test observability. Including the transaction ID in the propagation message is particularly helpful for debugging.

Also applies to: 40-40

packages/platform-test-suite/test/e2e/withdrawals.spec.js (1)

3-3: LGTM!

The local import path is consistent with other test files, and the descriptive wait message provides clear context for the polling loop.

Also applies to: 258-258

packages/platform-test-suite/lib/waitForBlocks.js (1)

13-14: LGTM!

The attempt counter and descriptive wait message provide excellent diagnostic context for block height polling, clearly showing progress toward the target height.

Also applies to: 19-23

packages/platform-test-suite/test/functional/dapi/subscribeToBlockHeadersWithChainLocksHandlerFactory.spec.js (3)

16-16: LGTM!

The import path change aligns with the standardized wait module usage across the test suite.


129-129: LGTM!

The iteration counter and descriptive wait message improve observability for the historical block header streaming test.

Also applies to: 135-140


222-222: LGTM!

The iteration counter and descriptive wait message provide clear diagnostic context for tracking fresh block delivery and chain lock reception.

Also applies to: 228-233

packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs (2)

77-79: Verify intentional forwarding of all blocks/locks to bloom filter subscribers.

Bloom filter subscribers receive all CoreRawBlock, CoreInstantLock, and CoreChainLock events without filtering (always return true), while only CoreRawTransaction events are filtered via matches_core_transaction.

Is this intentional? If subscribers need full chain context (blocks, locks), this is correct. Otherwise, consider whether these events should be filtered or use separate subscription types.


204-244: Test validates problematic fallback behavior.

This test explicitly validates the contains(raw_tx) fallback that was flagged as semantically incorrect in previous reviews. The test name and implementation suggest this fallback is intentional, but it conflicts with the bloom filter's design (matching structured transaction data, not raw bytes).

If the fallback behavior is removed per the previous review recommendation, this test should also be removed or updated to verify the new behavior (returning false for non-deserializable data).

packages/rs-dapi/src/server/metrics.rs (2)

16-42: LGTM! Metrics server startup is well-structured.

The early return when metrics are disabled, clear logging, optional access-log layer, and clean Axum router setup all follow best practices. The past review concern about error leakage on /health has been addressed by the health_error_label redaction function used in the health handler.


46-163: Health check implementation is sound.

The parallel execution with timeout, comprehensive error handling, and aggregated status logic (ok/degraded/error) are all correct. The use of health_error_label ensures that internal error details are properly redacted before being exposed over HTTP, addressing the previous security concern.

packages/rs-dapi/src/cache.rs (10)

1-14: LGTM!

Imports and constants are appropriate for the LRU cache implementation.


16-23: LGTM!

The LruResponseCache struct design is sound: wrapping the underlying cache in Arc enables cheap cloning, the label supports metrics, and the Workers handle background invalidation. The Debug impl provides useful diagnostics.

Also applies to: 27-45


47-75: LGTM!

The CacheKey design elegantly handles serialization failures by making the digest optional, causing all lookups to miss when key serialization fails. This prevents panics while maintaining type safety.


76-117: LGTM!

The CachedValue implementation properly handles both serialization and deserialization errors without panics. The switch from bincode to rmp_serde is well-documented and addresses a real bug encountered during testing.


119-129: LGTM!

The weighter correctly accounts for both structural overhead and payload size, with a sensible minimum weight of 1 byte.


131-189: LGTM!

The dual constructor design is appropriate: with_capacity for immutable data (e.g., blocks by hash) and new with background invalidation for mutable data. The background worker pattern is clean and the memory observation is consistently applied.


191-235: LGTM!

The get_and_parse helper correctly treats deserialization failures as cache misses and removes corrupted entries. The get method properly records hit/miss metrics.


263-298: LGTM!

Both remove and put handle edge cases gracefully: remove returns a clear success indicator and put skips caching when serialization fails, avoiding panics while logging the issue.


300-375: LGTM!

The get_or_try_insert implementation correctly handles all error paths without panics: serialization failures return errors, deserialization failures remove corrupted entries and propagate errors, and all paths record appropriate metrics. The async design prevents the producer from executing on cache hits.


377-631: LGTM!

The observe_memory helper consistently tracks cache metrics, and make_cache_key produces stable digests while handling serialization failures gracefully. The test suite is comprehensive, covering all cache methods, error handling, TTL expiration, and specifically validates the workaround for the bincode deserialization bug.

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

♻️ Duplicate comments (4)
packages/rs-dapi/src/clients/drive_client.rs (1)

171-174: Clone the request instead of dereferencing it

Line 173 dereferences &GetStatusRequest, attempting to move a non-Copy type and breaking compilation. Clone the payload (or wrap it in tonic::Request) before calling get_status.

-        let drive_response = self.get_client().get_status(*request).await?.into_inner();
+        let drive_response = self
+            .get_client()
+            .get_status(request.clone())
+            .await?
+            .into_inner();
packages/rs-dapi/src/server/grpc.rs (3)

105-111: Hardcoded streaming methods list remains fragile.

This was flagged in a previous review but not yet addressed. Maintaining a hardcoded list is error-prone—new streaming methods won't receive the correct timeout unless manually updated here.

Consider using a naming convention to detect streaming methods dynamically:

-    // All known streaming methods in Core service (all use "stream" return type)
-    const STREAMING_METHODS: &[&str] = &[
-        "/org.dash.platform.dapi.v0.Core/subscribeToBlockHeadersWithChainLocks",
-        "/org.dash.platform.dapi.v0.Core/subscribeToTransactionsWithProofs",
-        "/org.dash.platform.dapi.v0.Core/subscribeToMasternodeList",
-        "/org.dash.platform.dapi.v0.Platform/waitForStateTransitionResult",
-        "/org.dash.platform.dapi.v0.Platform/subscribePlatformEvents",
-    ];
-
-    // Check if this is a known streaming method
-    if STREAMING_METHODS.contains(&path) {
+    // Streaming methods follow naming convention: subscribe* or waitFor*
+    if path.contains("/subscribe") || path.contains("/waitFor") {

115-117: Fix tracing field to log the path value.

tracing::trace!(path, ...) records a boolean field named path rather than logging the actual path string.

Apply this diff:

             tracing::trace!(
-                path,
+                path = %path,
                 "Detected streaming gRPC method, applying streaming timeout"
             );

171-182: Fix tracing fields to log path values.

Lines 172 and 179 use bare path identifiers, which record boolean fields instead of logging the actual path strings.

Apply this diff:

         if timeout_from_header.is_some() {
             trace!(
-                path,
+                path = %path,
                 header_timeout = timeout_from_header.unwrap_or_default().as_secs_f32(),
                 timeout = effective_timeout.as_secs_f32(),
                 "Applying gRPC timeout from header"
             );
         } else {
             tracing::trace!(
-                path,
+                path = %path,
                 timeout = effective_timeout.as_secs_f32(),
                 "Applying default gRPC timeout"
             );
🧹 Nitpick comments (2)
packages/rs-dapi/src/clients/tenderdash_client.rs (1)

328-337: Consider eliminating double serialization.

The request is serialized twice: once at line 328 for tracing and again at line 337 for the actual HTTP request. Since .json() performs serialization internally, the first serialization is redundant.

You could eliminate the separate request_value and trace the request object directly, or serialize once and reuse:

-        let request_value = serde_json::to_value(request).map_err(|e| {
-            error!("Failed to serialize Tenderdash request: {}", e);
-            DapiError::Client(format!("Failed to serialize request: {}", e))
-        })?;
-
         let response_body = self
             .client
             .post(&self.base_url)
             .header("Content-Type", "application/json")
             .json(request)
             .send()
             .await

Then update the tracing to use the request object directly:

         tracing::trace!(
             elapsed = ?start.elapsed(),
-            request = ?request_value,
+            request = ?request,
             response = ?response,
             "tenderdash_client request executed");

This avoids the overhead of serializing to Value just for tracing.

packages/rs-dapi/src/server/grpc.rs (1)

164-168: Log warning for client deadline shorter than safety margin

The grpc-timeout header may be less than GRPC_REQUEST_TIME_SAFETY_MARGIN, causing checked_sub to return None and fall back to a much larger default timeout—potentially exceeding the client’s deadline. Add a warning when this occurs:

 let timeout_from_header = parse_grpc_timeout_header(req.headers());
+if let Some(raw_deadline) = timeout_from_header {
+    if raw_deadline < GRPC_REQUEST_TIME_SAFETY_MARGIN {
+        warn!(
+            method = %path,
+            client_deadline_ms = raw_deadline.as_millis(),
+            safety_margin_ms = GRPC_REQUEST_TIME_SAFETY_MARGIN.as_millis(),
+            "Client deadline shorter than safety margin, using default timeout"
+        );
+    }
+}
 let effective_timeout = timeout_from_header
     .and_then(|d| d.checked_sub(GRPC_REQUEST_TIME_SAFETY_MARGIN))
     .unwrap_or(default_timeout)
     .min(default_timeout);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 820d85d and 0196945.

📒 Files selected for processing (4)
  • packages/rs-dapi/src/clients/drive_client.rs (1 hunks)
  • packages/rs-dapi/src/clients/tenderdash_client.rs (1 hunks)
  • packages/rs-dapi/src/server/grpc.rs (1 hunks)
  • packages/rs-dapi/src/server/metrics.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/rs-dapi/src/clients/drive_client.rs
  • packages/rs-dapi/src/clients/tenderdash_client.rs
  • packages/rs-dapi/src/server/metrics.rs
  • packages/rs-dapi/src/server/grpc.rs
packages/rs-*/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

packages/rs-*/**/*.rs: Use rustfmt defaults for Rust code (format via cargo fmt --all)
Keep Rust code clippy-clean (cargo clippy)
Name Rust modules in snake_case
Use PascalCase for Rust types
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-dapi/src/clients/drive_client.rs
  • packages/rs-dapi/src/clients/tenderdash_client.rs
  • packages/rs-dapi/src/server/metrics.rs
  • packages/rs-dapi/src/server/grpc.rs
🧠 Learnings (3)
📓 Common learnings
Learnt from: shumkov
PR: dashpay/platform#2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:69-125
Timestamp: 2024-10-24T05:07:35.892Z
Learning: Future development plans involve rewriting DAPI into Rust, as the rest of the project has already migrated.
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/dashmate/src/test/constants/services.js:4-4
Timestamp: 2025-10-15T14:45:30.856Z
Learning: In the dashmate codebase (packages/dashmate), during the DAPI Rust migration (rs-dapi), the old service keys `dapi_api` and `dapi_core_streams` are intentionally kept in `generateEnvsFactory.js` for backward compatibility even though the test constants in `src/test/constants/services.js` have been updated to use `rs_dapi`. These deprecated keys will be removed in a future PR after the transition is complete.
📚 Learning: 2025-10-09T15:59:33.162Z
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/rs-dapi/src/clients/tenderdash_client.rs:0-0
Timestamp: 2025-10-09T15:59:33.162Z
Learning: In the rs-dapi codebase, the `Workers::spawn` method (in `packages/rs-dapi/src/sync.rs`) accepts futures that return `Result<O, E>`, not `()`. Its signature is `fn spawn<F, O, E>(&self, fut: F) where F: Future<Output = Result<O, E>> + Send + 'static`. The method handles error logging internally, so spawned tasks should return Results directly without additional error handling wrappers.

Applied to files:

  • packages/rs-dapi/src/clients/tenderdash_client.rs
📚 Learning: 2025-10-09T15:59:41.943Z
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/rs-dapi/src/clients/tenderdash_client.rs:0-0
Timestamp: 2025-10-09T15:59:41.943Z
Learning: In packages/rs-dapi, the Workers::spawn method accepts futures that return Result<O, E> where E: Into<DapiError>. It handles error logging internally, so spawned tasks should return Result types rather than handling errors inside the task. The Workers implementation automatically logs worker failures.

Applied to files:

  • packages/rs-dapi/src/clients/tenderdash_client.rs
🧬 Code graph analysis (4)
packages/rs-dapi/src/clients/drive_client.rs (6)
packages/dapi-grpc/clients/drive/v0/web/drive_pb_service.d.ts (1)
  • DriveInternalClient (49-62)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (2)
  • GetStatusRequest (5482-5497)
  • Version (5599-5618)
packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts (1)
  • PlatformClient (509-936)
packages/rs-dapi/src/clients/tenderdash_client.rs (2)
  • new (53-60)
  • new (383-422)
packages/rs-dapi/src/services/platform_service/mod.rs (1)
  • new (110-166)
packages/rs-dapi/src/services/streaming_service/mod.rs (1)
  • new (168-187)
packages/rs-dapi/src/clients/tenderdash_client.rs (4)
packages/rs-dapi/src/utils.rs (3)
  • deserialize_string_number_or_null (147-163)
  • deserialize_string_or_number (23-86)
  • generate_jsonrpc_id (12-21)
packages/rs-dapi/src/clients/tenderdash_websocket.rs (2)
  • new (78-88)
  • test_connection (106-125)
packages/rs-dapi/src/server/mod.rs (1)
  • new (29-77)
packages/rs-dapi/src/error.rs (2)
  • from_tenderdash_error (170-172)
  • client (201-203)
packages/rs-dapi/src/server/metrics.rs (6)
packages/rs-dapi/src/logging/middleware.rs (1)
  • new (27-29)
packages/rs-dapi/src/metrics.rs (2)
  • new (400-402)
  • gather_prometheus (383-392)
packages/rs-dapi/src/error.rs (4)
  • from (128-130)
  • from (135-137)
  • from (142-144)
  • from (302-333)
packages/rs-dapi/src/services/platform_service/mod.rs (1)
  • new (110-166)
packages/rs-dapi/src/server/mod.rs (1)
  • new (29-77)
packages/rs-dapi/src/services/platform_service/get_status.rs (1)
  • is_healthy (42-44)
packages/rs-dapi/src/server/grpc.rs (4)
packages/rs-dapi/src/logging/middleware.rs (7)
  • layer (35-41)
  • new (27-29)
  • poll_ready (62-65)
  • call (68-189)
  • req (292-292)
  • req (296-296)
  • as_str (309-309)
packages/rs-dapi/src/metrics.rs (7)
  • layer (413-415)
  • new (400-402)
  • poll_ready (430-432)
  • call (434-498)
  • req (438-438)
  • as_str (33-35)
  • as_str (144-149)
packages/rs-dapi/src/server/mod.rs (1)
  • new (29-77)
packages/rs-dapi/src/logging/access_log.rs (1)
  • new (261-272)
⏰ 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). (167)
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Formatting
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Formatting
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Formatting
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Unused dependencies
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Formatting
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Unused dependencies
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Formatting
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Unused dependencies
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Formatting
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Unused dependencies
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Formatting
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Unused dependencies
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Formatting
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Unused dependencies
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Formatting
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Unused dependencies
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Rust packages (drive) / Formatting
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Unused dependencies
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Linting
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
🔇 Additional comments (14)
packages/rs-dapi/src/clients/tenderdash_client.rs (6)

1-34: LGTM!

The imports are well-organized, and the struct documentation clearly explains the tracing behavior and error handling architecture. The client design with optional WebSocket support is sound.


36-316: LGTM!

The JSON-RPC request/response structures and data models are well-designed:

  • Proper use of custom deserializers (deserialize_string_or_number, deserialize_string_number_or_null) to handle JSON-RPC type variations
  • Comprehensive #[serde(default)] attributes for resilience
  • The ExecTxResult::is_empty() helper is a useful addition for detecting absent results
  • Clear type aliases improve readability

379-447: LGTM!

The constructor properly addresses past review concerns:

  • HTTP client timeouts are configured (connect_timeout and request timeout)
  • TracingMiddleware is correctly wired into the client builder
  • Both HTTP and WebSocket connections are validated before returning
  • Comprehensive error handling and logging throughout

The defensive validation approach (testing both HTTP and WebSocket connectivity) ensures the client is fully operational before use.


481-515: LGTM!

The RPC wrapper methods (broadcast_tx, check_tx, unconfirmed_tx, tx) are cleanly implemented with appropriate parameter structures and proper delegation to the generic post method.


537-544: LGTM!

The is_websocket_connected helper provides a clean way to check WebSocket connectivity status.


457-472: Fallback behavior documented; no changes needed The net_info doc comment explicitly states it falls back to defaults on transport errors, confirming the error-masking is intentional.

packages/rs-dapi/src/server/grpc.rs (3)

26-82: LGTM: Well-structured server initialization.

The unified gRPC server setup correctly configures timeouts, layers, message limits, and service registration. The layer execution order is properly documented.


205-223: LGTM: Correct RFC 8681 timeout parsing.

The header parsing correctly handles all gRPC timeout units with appropriate overflow protection via saturating_mul.


252-275: LGTM: Comprehensive timeout test coverage.

The test correctly validates that timeouts produce DeadlineExceeded status with the timeout duration in the message.

packages/rs-dapi/src/server/metrics.rs (5)

16-42: LGTM: Clean metrics server initialization.

The method properly handles disabled metrics with early return, sets up routes, and optionally applies access logging.


123-181: LGTM: Correct overall health status calculation.

The core RPC health check properly redacts errors, and the overall status logic appropriately categorizes health based on failure count (0=ok, 1=degraded, 2+=error).


184-191: LGTM: Straightforward Prometheus metrics endpoint.

The metrics handler correctly gathers and formats Prometheus metrics with appropriate content-type headers.


193-272: LGTM: Well-structured health response models and error redaction.

The data structures properly use serde annotations for JSON formatting, and health_error_label provides comprehensive redaction of internal error details.


274-301: LGTM: ComponentCheck helpers are correctly implemented.

The from_option and from_bool helpers appropriately convert status values to ComponentCheck structs. Note that from_option passes error strings through unchanged, so callers must ensure proper redaction (see comment on lines 76-86).

Comment on lines 516 to 535
/// Subscribe to streaming Tenderdash transaction events if WebSocket is available.
pub fn subscribe_to_transactions(&self) -> broadcast::Receiver<TransactionEvent> {
if let Some(ws_client) = &self.websocket_client {
ws_client.subscribe()
} else {
// Return a receiver that will never receive messages
let (_, rx) = broadcast::channel(1);
rx
}
}
/// Subscribe to block events from Tenderdash via WebSocket.
pub fn subscribe_to_blocks(&self) -> broadcast::Receiver<BlockEvent> {
if let Some(ws_client) = &self.websocket_client {
ws_client.subscribe_blocks()
} else {
// Return a receiver that will never receive messages
let (_, rx) = broadcast::channel(1);
rx
}
}
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

Document the fallback behavior for subscription methods.

Both subscription methods return a dead channel (via broadcast::channel(1)) when WebSocket is unavailable, which could be surprising to callers. While the is_websocket_connected helper exists, the subscription methods don't document this fallback behavior.

Add doc comments to clarify the behavior:

+    /// Subscribe to streaming Tenderdash transaction events if WebSocket is available.
+    ///
+    /// Returns a broadcast receiver for transaction events. If WebSocket is not connected,
+    /// returns a receiver that will never produce events. Check `is_websocket_connected()`
+    /// to verify connectivity before subscribing.
     pub fn subscribe_to_transactions(&self) -> broadcast::Receiver<TransactionEvent> {
+    /// Subscribe to block events from Tenderdash via WebSocket.
+    ///
+    /// Returns a broadcast receiver for block events. If WebSocket is not connected,
+    /// returns a receiver that will never produce events. Check `is_websocket_connected()`
+    /// to verify connectivity before subscribing.
     pub fn subscribe_to_blocks(&self) -> broadcast::Receiver<BlockEvent> {

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

🤖 Prompt for AI Agents
In packages/rs-dapi/src/clients/tenderdash_client.rs around lines 516 to 535,
the two subscription methods return a dead broadcast receiver (created with
broadcast::channel(1)) when the websocket_client is None but do not document
this fallback; update the doc comments for subscribe_to_transactions and
subscribe_to_blocks to clearly state that when WebSocket is unavailable the
method returns a receiver that will never receive messages, mention the
existence of is_websocket_connected so callers can check connection state
beforehand, and add a brief usage note advising callers to either check
is_websocket_connected or handle the no-message case (e.g., timeouts or
alternative flows).

Comment on lines +76 to +86
drive: Some(ComponentCheck::from_option(health.drive_error.clone())),
tenderdash_websocket: Some(ComponentCheck::from_bool(
websocket_connected,
"disconnected",
)),
tenderdash_status: Some(ComponentCheck::from_option(
health.tenderdash_status_error.clone(),
)),
tenderdash_net_info: Some(ComponentCheck::from_option(
health.tenderdash_netinfo_error.clone(),
)),
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

Redact component-level error messages to prevent info leakage.

While top-level errors are redacted via health_error_label (line 96), component-level errors (drive_error, tenderdash_status_error, tenderdash_netinfo_error) are passed directly to ComponentCheck::from_option without redaction. This could leak internal error details through the public health endpoint.

Apply health_error_label to component errors as well:

                 drive: Some(ComponentCheck::from_option(health.drive_error.clone())),
+                drive: Some(ComponentCheck::from_option(
+                    health.drive_error.as_ref().map(|_| health_error_label(
+                        &DapiError::Client(health.drive_error.clone().unwrap_or_default())
+                    ).to_string())
+                )),
                 tenderdash_websocket: Some(ComponentCheck::from_bool(
                     websocket_connected,
                     "disconnected",
                 )),
-                tenderdash_status: Some(ComponentCheck::from_option(
-                    health.tenderdash_status_error.clone(),
-                )),
-                tenderdash_net_info: Some(ComponentCheck::from_option(
-                    health.tenderdash_netinfo_error.clone(),
-                )),
+                tenderdash_status: Some(ComponentCheck::from_option(
+                    health.tenderdash_status_error.as_ref().map(|_| "tenderdash error".to_string())
+                )),
+                tenderdash_net_info: Some(ComponentCheck::from_option(
+                    health.tenderdash_netinfo_error.as_ref().map(|_| "tenderdash error".to_string())
+                )),

Alternatively, extend ComponentCheck::from_option to accept a redaction function or create a from_option_redacted variant.

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

🤖 Prompt for AI Agents
In packages/rs-dapi/src/server/metrics.rs around lines 76 to 86, component-level
error fields (drive_error, tenderdash_status_error, tenderdash_netinfo_error)
are passed into ComponentCheck::from_option unredacted and may leak internal
error details; update these calls to wrap the error option with the existing
health_error_label redaction before calling ComponentCheck::from_option (or, if
preferred, add a ComponentCheck::from_option_redacted that applies
health_error_label internally and use that) so the component error strings
exposed by the health endpoint are redacted.

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)
packages/rs-dapi/src/sync.rs (1)

1-12: Consider adding module-level documentation.

While the code is well-commented, a module-level doc comment explaining the worker pool architecture (command pattern, manager task, lazy AbortHandle resolution) would help future maintainers quickly understand the design.

Example:

+//! Async worker pool for managing background tasks.
+//!
+//! The pool uses a command pattern: `Workers` handles send spawn requests
+//! to a `WorkerManager` task that owns a `JoinSet`. The manager continuously
+//! drains completed tasks and returns `AbortHandle`s to callers via oneshot channels.
+
 use std::fmt::Debug;
packages/rs-dapi/src/clients/tenderdash_client.rs (2)

458-472: Consider documenting net_info's error-masking behavior.

Unlike other RPC methods, net_info() catches transport errors and returns default values instead of propagating them. While this may be intentional (preventing network peer stats from blocking other operations), it silently masks failures that callers might want to know about.

Consider:

  1. Adding a doc comment explaining why errors are masked
  2. Or exposing both net_info() (with masking) and net_info_internal() (without masking) publicly

Apply this diff to document the behavior:

+    /// Retrieve network peer statistics, falling back to defaults on transport errors.
+    ///
+    /// This method masks technical failures (network errors, timeouts) by returning
+    /// default values, ensuring peer stats don't block other operations. For strict
+    /// error handling, use `net_info_internal()`.
     pub async fn net_info(&self) -> DAPIResult<NetInfoResponse> {

516-523: Clarify subscription behavior when WebSocket is unavailable.

The doc comments mention "if WebSocket is available" but don't explain what happens when it's not. Based on past review comments, these methods return a broadcast receiver that won't produce events when WebSocket is disconnected.

Consider enhancing the documentation:

Apply this diff:

-    /// Subscribe to streaming Tenderdash transaction events if WebSocket is available.
+    /// Subscribe to streaming Tenderdash transaction events.
+    ///
+    /// Returns a broadcast receiver for transaction events. When WebSocket is not connected,
+    /// the receiver will not produce events. Use `is_websocket_connected()` to check connectivity.
     pub fn subscribe_to_transactions(&self) -> broadcast::Receiver<TransactionEvent> {
         self.websocket_client.subscribe()
     }
-    /// Subscribe to block events from Tenderdash via WebSocket.
+    /// Subscribe to block events from Tenderdash via WebSocket.
+    ///
+    /// Returns a broadcast receiver for block events. When WebSocket is not connected,
+    /// the receiver will not produce events. Use `is_websocket_connected()` to check connectivity.
     pub fn subscribe_to_blocks(&self) -> broadcast::Receiver<BlockEvent> {
         self.websocket_client.subscribe_blocks()
     }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0196945 and 1c59b2d.

📒 Files selected for processing (3)
  • packages/rs-dapi/src/clients/tenderdash_client.rs (1 hunks)
  • packages/rs-dapi/src/services/platform_service/mod.rs (1 hunks)
  • packages/rs-dapi/src/sync.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/rs-dapi/src/sync.rs
  • packages/rs-dapi/src/services/platform_service/mod.rs
  • packages/rs-dapi/src/clients/tenderdash_client.rs
packages/rs-*/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

packages/rs-*/**/*.rs: Use rustfmt defaults for Rust code (format via cargo fmt --all)
Keep Rust code clippy-clean (cargo clippy)
Name Rust modules in snake_case
Use PascalCase for Rust types
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-dapi/src/sync.rs
  • packages/rs-dapi/src/services/platform_service/mod.rs
  • packages/rs-dapi/src/clients/tenderdash_client.rs
🧠 Learnings (4)
📓 Common learnings
Learnt from: shumkov
PR: dashpay/platform#2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:69-125
Timestamp: 2024-10-24T05:07:35.892Z
Learning: Future development plans involve rewriting DAPI into Rust, as the rest of the project has already migrated.
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/dashmate/src/test/constants/services.js:4-4
Timestamp: 2025-10-15T14:45:30.856Z
Learning: In the dashmate codebase (packages/dashmate), during the DAPI Rust migration (rs-dapi), the old service keys `dapi_api` and `dapi_core_streams` are intentionally kept in `generateEnvsFactory.js` for backward compatibility even though the test constants in `src/test/constants/services.js` have been updated to use `rs_dapi`. These deprecated keys will be removed in a future PR after the transition is complete.
📚 Learning: 2025-10-09T15:59:33.162Z
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/rs-dapi/src/clients/tenderdash_client.rs:0-0
Timestamp: 2025-10-09T15:59:33.162Z
Learning: In the rs-dapi codebase, the `Workers::spawn` method (in `packages/rs-dapi/src/sync.rs`) accepts futures that return `Result<O, E>`, not `()`. Its signature is `fn spawn<F, O, E>(&self, fut: F) where F: Future<Output = Result<O, E>> + Send + 'static`. The method handles error logging internally, so spawned tasks should return Results directly without additional error handling wrappers.

Applied to files:

  • packages/rs-dapi/src/sync.rs
  • packages/rs-dapi/src/clients/tenderdash_client.rs
📚 Learning: 2025-10-09T15:59:41.943Z
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/rs-dapi/src/clients/tenderdash_client.rs:0-0
Timestamp: 2025-10-09T15:59:41.943Z
Learning: In packages/rs-dapi, the Workers::spawn method accepts futures that return Result<O, E> where E: Into<DapiError>. It handles error logging internally, so spawned tasks should return Result types rather than handling errors inside the task. The Workers implementation automatically logs worker failures.

Applied to files:

  • packages/rs-dapi/src/sync.rs
  • packages/rs-dapi/src/clients/tenderdash_client.rs
📚 Learning: 2024-10-10T10:30:24.653Z
Learnt from: lklimek
PR: dashpay/platform#2232
File: packages/rs-sdk/src/sync.rs:68-71
Timestamp: 2024-10-10T10:30:24.653Z
Learning: In synchronous code within a Tokio runtime, we cannot await spawned task handles (`JoinHandle`), so it's acceptable to check if the task is finished and abort it if necessary.

Applied to files:

  • packages/rs-dapi/src/sync.rs
🧬 Code graph analysis (3)
packages/rs-dapi/src/sync.rs (4)
packages/rs-dapi/src/cache.rs (3)
  • new (58-60)
  • new (96-109)
  • new (148-171)
packages/rs-dapi/src/metrics.rs (3)
  • new (400-402)
  • workers_active_inc (562-564)
  • workers_active_dec (567-569)
packages/rs-dapi/src/services/platform_service/mod.rs (1)
  • new (110-163)
packages/rs-dapi/src/services/streaming_service/masternode_list_sync.rs (1)
  • new (32-41)
packages/rs-dapi/src/services/platform_service/mod.rs (5)
packages/rs-dapi/src/cache.rs (16)
  • cache (474-475)
  • cache (484-485)
  • cache (494-495)
  • cache (518-519)
  • cache (536-537)
  • cache (542-543)
  • cache (577-578)
  • cache (603-604)
  • cache (623-624)
  • make_cache_key (388-401)
  • method (63-65)
  • get (220-235)
  • new (58-60)
  • new (96-109)
  • new (148-171)
  • put (281-298)
packages/rs-dapi/src/clients/drive_client.rs (2)
  • get_client (230-232)
  • new (95-128)
packages/rs-dapi/src/clients/tenderdash_client.rs (4)
  • new (53-60)
  • new (383-422)
  • status (450-455)
  • websocket_client (531-533)
packages/rs-dapi/src/services/platform_service/error_mapping.rs (1)
  • new (20-35)
packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs (1)
  • build_wait_for_state_transition_error_response (289-312)
packages/rs-dapi/src/clients/tenderdash_client.rs (5)
packages/rs-dapi/src/utils.rs (3)
  • deserialize_string_number_or_null (147-163)
  • deserialize_string_or_number (23-86)
  • generate_jsonrpc_id (12-21)
packages/rs-dapi/src/services/platform_service/mod.rs (1)
  • new (110-163)
packages/rs-dapi/src/clients/tenderdash_websocket.rs (2)
  • new (78-88)
  • test_connection (106-125)
packages/rs-dapi/src/server/mod.rs (1)
  • new (29-77)
packages/rs-dapi/src/error.rs (3)
  • from_tenderdash_error (170-172)
  • client (201-203)
  • server_unavailable (231-233)
⏰ 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). (30)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
🔇 Additional comments (7)
packages/rs-dapi/src/sync.rs (2)

1-257: Excellent worker pool implementation; previous concerns fully addressed.

The implementation is well-architected and correctly handles the issues raised in prior reviews:

  1. Memory leak fixed: The WorkerManager now continuously drains the JoinSet via join_next() in the select! loop (lines 227-231) and performs a final drain on shutdown (lines 236-238), preventing accumulation of completed tasks.

  2. AbortHandle handling is correct: The previous review suggesting futures::abortable was mistaken—JoinSet::spawn returns AbortHandle directly per Tokio 1.47.0 docs. The current design properly:

    • Spawns tasks into the JoinSet and obtains AbortHandle (lines 211-212, 221-222)
    • Returns AbortHandle to the caller via oneshot channel
    • Provides async abort via WorkerTaskHandle (lines 150-154)

Additional strengths:

  • Clean RAII-based metrics tracking via WorkerMetricsGuard
  • Proper error logging in handle_result (lines 242-255)
  • Lazy AbortHandle resolution using OnceCell+Notify pattern
  • Comprehensive test coverage

Based on learnings and retrieved documentation.


258-357: Well-designed test suite.

The tests comprehensively cover:

  • Task execution and cleanup
  • Abort cancellation with drop verification (using DropGuard)
  • Error handling and metric cleanup

The wait_for_active_count helper appropriately handles async timing, and all tests verify the critical invariant that task_count returns to zero after task completion.

packages/rs-dapi/src/services/platform_service/mod.rs (3)

58-59: Past issue resolved: Cache.get now uses type inference.

The invalid cast as Option<$response_type> has been corrected. The current code properly uses Rust's type inference with cache.get(&key), which will infer T as $response_type from the context.


102-104: Past issue resolved: Workers abstraction ensures proper cleanup.

The background task cleanup concern has been addressed by using the Workers abstraction. The #[allow(dead_code)] comment correctly notes that dropping Workers will cancel spawned tasks, ensuring proper resource cleanup when PlatformServiceImpl is dropped.


110-163: LGTM: PlatformServiceImpl initialization is well-structured.

The constructor properly:

  • Initializes the Workers abstraction for background task management
  • Spawns the WebSocket listener with automatic retry logic (10s delay)
  • Wires cache invalidation to block events via PlatformAllBlocks subscription
  • Returns appropriate Result<(), DapiError> from spawned tasks (as per learnings)

The infinite loop with retry logic is appropriate for a persistent background connection, and the #[allow(unreachable_code)] annotation correctly acknowledges the unreachable Ok(()).

packages/rs-dapi/src/clients/tenderdash_client.rs (2)

390-401: Past issue resolved: HTTP client now has proper timeouts and tracing.

The HTTP client initialization has been updated to include:

  • Connection timeout via connect_timeout(CONNECT_TIMEOUT)
  • Request timeout via timeout(REQUEST_TIMEOUT)
  • Tracing middleware via TracingMiddleware::default()

This addresses the previous concerns about missing timeouts and unattached tracing.


337-337: Past issue resolved: Using RequestBuilder::json() for clean serialization.

The code now uses .json(request) instead of manual JSON stringification, which is cleaner and handles serialization automatically. The request timeout is already configured at the client level (line 392), so no additional per-request timeout is needed here.

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

♻️ Duplicate comments (3)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (1)

927-945: Do not fallback to raw-bytes contains() when tx deserialization fails

Raw-byte checks misrepresent bloom semantics and hide encoding issues. Treat as non-match instead.

Based on learnings.

packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs (2)

37-58: Do not fallback to raw-bytes contains() when tx deserialization fails

Treat malformed data as non-matching rather than falling back to raw-bytes check. This fallback misrepresents bloom filter semantics and can mask encoding bugs.


246-325: Mark test with #[ignore] to avoid CI failures

This test documents desired behavior that is not yet implemented (filter persistence). It should be marked with #[ignore] to prevent CI failures.

🧹 Nitpick comments (1)
packages/rs-dapi/src/services/platform_service/mod.rs (1)

52-73: Consider explicit type parameter for cache lookup

For clarity, specify the type parameter explicitly in the cache lookup.

-                    if let Some(decoded) = cache.get(&key) {
+                    if let Some(decoded) = cache.get::<$response_type>(&key) {
                         return Ok((Response::new(decoded), 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 1c59b2d and cd45073.

📒 Files selected for processing (3)
  • packages/rs-dapi/src/services/platform_service/mod.rs (1 hunks)
  • packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs (1 hunks)
  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
  • packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs
  • packages/rs-dapi/src/services/platform_service/mod.rs
packages/rs-*/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

packages/rs-*/**/*.rs: Use rustfmt defaults for Rust code (format via cargo fmt --all)
Keep Rust code clippy-clean (cargo clippy)
Name Rust modules in snake_case
Use PascalCase for Rust types
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
  • packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs
  • packages/rs-dapi/src/services/platform_service/mod.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: shumkov
PR: dashpay/platform#2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:69-125
Timestamp: 2024-10-24T05:07:35.892Z
Learning: Future development plans involve rewriting DAPI into Rust, as the rest of the project has already migrated.
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/dashmate/src/test/constants/services.js:4-4
Timestamp: 2025-10-15T14:45:30.856Z
Learning: In the dashmate codebase (packages/dashmate), during the DAPI Rust migration (rs-dapi), the old service keys `dapi_api` and `dapi_core_streams` are intentionally kept in `generateEnvsFactory.js` for backward compatibility even though the test constants in `src/test/constants/services.js` have been updated to use `rs_dapi`. These deprecated keys will be removed in a future PR after the transition is complete.
🧬 Code graph analysis (3)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (2)
packages/rs-dapi/src/services/streaming_service/bloom.rs (2)
  • bloom_flags_from_int (103-114)
  • matches_transaction (55-101)
packages/rs-dapi/src/services/streaming_service/mod.rs (8)
  • txid_bytes_from_bytes (57-65)
  • txid_hex_from_bytes (48-54)
  • block_hash_hex_from_block_bytes (68-74)
  • summarize_streaming_event (87-129)
  • deserialize (51-51)
  • deserialize (62-62)
  • deserialize (71-71)
  • short_hex (77-84)
packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs (4)
packages/rs-dapi/src/services/streaming_service/mod.rs (2)
  • summarize_streaming_event (87-129)
  • new (168-187)
packages/rs-dapi/src/services/streaming_service/bloom.rs (1)
  • matches_transaction (55-101)
packages/rs-dash-event-bus/src/event_bus.rs (4)
  • id (234-236)
  • matches (16-16)
  • matches (429-431)
  • subscription_count (185-187)
packages/rs-dapi/src/clients/tenderdash_websocket.rs (1)
  • new (78-88)
packages/rs-dapi/src/services/platform_service/mod.rs (5)
packages/rs-drive-abci/src/query/service.rs (4)
  • broadcast_state_transition (257-262)
  • get_status (578-588)
  • wait_for_state_transition_result (420-425)
  • new (75-77)
packages/rs-dapi/src/cache.rs (16)
  • cache (474-475)
  • cache (484-485)
  • cache (494-495)
  • cache (518-519)
  • cache (536-537)
  • cache (542-543)
  • cache (577-578)
  • cache (603-604)
  • cache (623-624)
  • make_cache_key (388-401)
  • method (63-65)
  • get (220-235)
  • new (58-60)
  • new (96-109)
  • new (148-171)
  • put (281-298)
packages/rs-dapi/src/clients/drive_client.rs (1)
  • get_client (230-232)
packages/rs-dapi/src/clients/tenderdash_client.rs (4)
  • new (53-60)
  • new (383-422)
  • status (450-455)
  • websocket_client (531-533)
packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs (1)
  • build_wait_for_state_transition_error_response (289-312)
⏰ 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). (3)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Swift SDK and Example build (warnings as errors)

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

♻️ Duplicate comments (2)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (2)

929-947: Critical: Raw-bytes bloom fallback still present despite past fix.

Lines 943-947 still contain the problematic raw-bytes contains() fallback that was flagged and marked as addressed in previous reviews. This misrepresents bloom semantics and masks encoding errors. Treat deserialization failures as non-matches instead:

                             Err(e) => {
-                                debug!(height, error = %e, "transactions_with_proofs=tx_deserialize_failed, checking raw-bytes contains()");
-                                let guard = bloom.read().unwrap();
-                                guard.contains(tx_bytes)
+                                debug!(height, error = %e, "transactions_with_proofs=tx_deserialize_failed; treating as non-match");
+                                false
                             }

Based on learnings.


943-947: Handle RwLock poisoning instead of panicking.

Line 945's .unwrap() will panic if the lock is poisoned (e.g., a thread panicked while holding the write lock). Return false or log and continue instead:

                             Err(e) => {
-                                debug!(height, error = %e, "transactions_with_proofs=tx_deserialize_failed, checking raw-bytes contains()");
-                                let guard = bloom.read().unwrap();
-                                guard.contains(tx_bytes)
+                                debug!(height, error = %e, "transactions_with_proofs=tx_deserialize_failed");
+                                match bloom.read() {
+                                    Ok(guard) => guard.contains(tx_bytes),
+                                    Err(e) => {
+                                        debug!(height, error = %e, "bloom_lock_poisoned");
+                                        false
+                                    }
+                                }
                             }

(Note: This suggestion assumes you keep the raw-bytes fallback; the previous comment recommends removing it entirely.)

🧹 Nitpick comments (2)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (2)

477-494: Consider removing unnecessary response clone.

At line 480, resp.clone() is called before sending, but the original resp is not used afterward. The clone can be removed:

-                    if tx_sender.send(Ok(resp.clone())).await.is_err() {
+                    if tx_sender.send(Ok(resp)).await.is_err() {

This eliminates an allocation for every forwarded event.


515-584: Consider extracting common merkle-block logic.

The CoreAllTxs (lines 524-544) and CoreBloomFilter (lines 545-577) branches share significant structure—both deserialize the block, compute match flags, build merkle bytes, and fall back to raw block on error. Extract the shared path into a helper to reduce duplication:

fn build_merkle_with_flags(
    raw_block: &[u8],
    match_flags: Vec<bool>,
    handle_id: &str,
) -> TransactionsWithProofsResponse {
    // deserialize, build, fallback logic
}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between cd45073 and b828999.

📒 Files selected for processing (1)
  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
packages/rs-*/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

packages/rs-*/**/*.rs: Use rustfmt defaults for Rust code (format via cargo fmt --all)
Keep Rust code clippy-clean (cargo clippy)
Name Rust modules in snake_case
Use PascalCase for Rust types
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: shumkov
PR: dashpay/platform#2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:69-125
Timestamp: 2024-10-24T05:07:35.892Z
Learning: Future development plans involve rewriting DAPI into Rust, as the rest of the project has already migrated.
🧬 Code graph analysis (1)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (2)
packages/rs-dapi/src/services/streaming_service/bloom.rs (2)
  • bloom_flags_from_int (103-114)
  • matches_transaction (55-101)
packages/rs-dapi/src/services/streaming_service/mod.rs (8)
  • txid_bytes_from_bytes (57-65)
  • txid_hex_from_bytes (48-54)
  • block_hash_hex_from_block_bytes (68-74)
  • summarize_streaming_event (87-129)
  • deserialize (51-51)
  • deserialize (62-62)
  • deserialize (71-71)
  • short_hex (77-84)
⏰ 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). (158)
  • GitHub Check: Rust packages (token-history-contract) / Detect immutable structure changes
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (token-history-contract) / Detect immutable structure changes
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
🔇 Additional comments (6)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (6)

1-41: LGTM!

Type aliases and constants are well-defined. The 3-minute gate timeout (GATE_MAX_TIMEOUT) is generous but reasonable for slow historical replay scenarios.


43-148: LGTM!

The TransactionStreamState design is sound. The gate mechanism correctly coordinates historical replay with live streaming, and the delivered-sets prevent duplicates across transaction and instant-lock sources.


150-193: LGTM!

Clean entry point with appropriate mode routing. The bloom filter setup and error handling are correct.


586-784: LGTM!

The orchestration of live and historical streams is well-structured. The gate mechanism correctly ensures historical events are delivered before live events, and error propagation to the client is handled properly.


786-868: LGTM!

The mempool worker correctly filters, deduplicates, and batches matching transactions. The integration with the delivery-tracking state prevents duplicates.


1025-1096: LGTM!

Helper functions are well-implemented with appropriate validation. The merkle tree construction validates inputs, bloom filter parsing checks for invalid parameters, and txid formatting correctly reverses byte order for display.

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

♻️ Duplicate comments (1)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (1)

929-933: Raw-bytes bloom filter fallback still present despite past resolution.

This code segment was previously flagged and marked as addressed, but the problematic fallback to guard.contains(tx_bytes) when deserialization fails is still present. Raw-byte checks misrepresent bloom semantics and hide encoding issues.

Additionally, line 931 uses unwrap() on the RwLock which will panic if the lock is poisoned. Apply this diff to address both issues:

                             Err(e) => {
-                                debug!(height, error = %e, "transactions_with_proofs=tx_deserialize_failed, checking raw-bytes contains()");
-                                let guard = bloom.read().unwrap();
-                                guard.contains(tx_bytes)
+                                debug!(height, error = %e, "transactions_with_proofs=tx_deserialize_failed; treating as non-match");
+                                false
                             }

Based on learnings and past review feedback.

🧹 Nitpick comments (3)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (3)

421-421: Simplify or document complex boolean condition.

The condition combines three negations which can be hard to reason about. Consider refactoring for clarity:

-                if !bloom_matched && !already_delivered && !matches!(filter, FilterType::CoreAllTxs) {
+                let should_skip = !bloom_matched 
+                    && !already_delivered 
+                    && !matches!(filter, FilterType::CoreAllTxs);
+                if should_skip {

Or add a comment explaining the logic: "Skip if not matched by bloom, not previously delivered, and not in all-txs mode."


538-543: Extract duplicated "include delivered tx in merkle block" logic.

The logic for checking if a transaction has been previously delivered and including it in the merkle block (regardless of bloom match) appears in both build_transaction_merkle_response and process_transactions_from_height.

Consider extracting this pattern into a helper method:

async fn should_include_in_merkle(
    bloom_matched: bool,
    tx_bytes: &[u8],
    state: Option<&TransactionStreamState>,
) -> bool {
    if bloom_matched {
        return true;
    }
    if let Some(state) = state {
        if let Some(txid_bytes) = Self::txid_bytes_from_bytes(tx_bytes) {
            return state.has_transaction_been_delivered(&txid_bytes).await;
        }
    }
    false
}

Then use it in both locations to improve maintainability.

Also applies to: 940-946


1112-1142: Expand test coverage for critical streaming logic.

The file has extensive business logic (bloom filtering, deduplication, gate mechanism, historical vs. live streaming) but only one unit test. Consider adding tests for:

  • Bloom filter matching with various transaction types
  • Deduplication across delivered sets (txs, blocks, instant locks)
  • Gate mechanism timing and pending event flushing
  • Merkle block construction with different match patterns
  • Error handling for deserialization failures

This would improve confidence in the correctness of the streaming implementation, especially for edge cases.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between b828999 and 60d2a98.

📒 Files selected for processing (1)
  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
packages/rs-*/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

packages/rs-*/**/*.rs: Use rustfmt defaults for Rust code (format via cargo fmt --all)
Keep Rust code clippy-clean (cargo clippy)
Name Rust modules in snake_case
Use PascalCase for Rust types
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: shumkov
PR: dashpay/platform#2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:69-125
Timestamp: 2024-10-24T05:07:35.892Z
Learning: Future development plans involve rewriting DAPI into Rust, as the rest of the project has already migrated.
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/dashmate/src/test/constants/services.js:4-4
Timestamp: 2025-10-15T14:45:30.856Z
Learning: In the dashmate codebase (packages/dashmate), during the DAPI Rust migration (rs-dapi), the old service keys `dapi_api` and `dapi_core_streams` are intentionally kept in `generateEnvsFactory.js` for backward compatibility even though the test constants in `src/test/constants/services.js` have been updated to use `rs_dapi`. These deprecated keys will be removed in a future PR after the transition is complete.
🧬 Code graph analysis (1)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (2)
packages/rs-dapi/src/services/streaming_service/bloom.rs (2)
  • bloom_flags_from_int (103-114)
  • matches_transaction (55-101)
packages/rs-dapi/src/services/streaming_service/mod.rs (8)
  • txid_bytes_from_bytes (57-65)
  • txid_hex_from_bytes (48-54)
  • block_hash_hex_from_block_bytes (68-74)
  • summarize_streaming_event (87-129)
  • deserialize (51-51)
  • deserialize (62-62)
  • deserialize (71-71)
  • short_hex (77-84)
⏰ 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). (127)
  • GitHub Check: Rust packages (wasm-dpp) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (wasm-dpp) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (wasm-dpp) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Rust packages (wasm-dpp) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Rust packages (wasm-dpp) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Rust packages (wasm-dpp) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Rust packages (wasm-dpp) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Rust packages (wasm-dpp) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Rust packages (wasm-dpp) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Rust packages (wasm-dpp) / Unused dependencies
  • GitHub Check: Rust packages (wasm-dpp) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (drive) / Unused dependencies
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
🔇 Additional comments (2)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (2)

92-98: Verify forced gate opening doesn't cause data races.

Forcibly opening the gate on timeout could allow live events to be processed while historical sync is still ongoing, potentially causing duplicates or ordering issues if the historical worker hasn't completed marking transactions as delivered.

Consider adding a check or warning if historical sync is still active when the timeout fires, or validate that the deduplication logic is robust enough to handle this scenario.


1031-1075: LGTM! Comprehensive bloom filter validation.

The bloom filter parsing includes appropriate validation for empty data and zero hash functions, with clear error messages. The use of bloom_flags_from_int helper and proper error propagation is well-implemented.

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

♻️ Duplicate comments (1)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (1)

915-933: Raw-bytes fallback still present despite past review.

Lines 929-933 still perform raw-bytes bloom.contains(tx_bytes) when transaction deserialization fails. This pattern was previously flagged and marked as addressed, but the problematic code remains. Treat deserialization failures as non-matches instead of falling back to semantically incorrect raw-bytes checks.

Apply this diff:

                         match deserialize::<CoreTx>(tx_bytes.as_slice()) {
                             Ok(tx) => {
                                 let matches = super::bloom::matches_transaction(
                                     Arc::clone(bloom),
                                     &tx,
                                     *flags,
                                 );
                                 trace!(height,matches, txid = %tx.txid(), "transactions_with_proofs=bloom_match");
                                 matches
                             }
                             Err(e) => {
-                                debug!(height, error = %e, "transactions_with_proofs=tx_deserialize_failed, checking raw-bytes contains()");
-                                let guard = bloom.read().unwrap();
-                                guard.contains(tx_bytes)
+                                debug!(height, error = %e, "transactions_with_proofs=tx_deserialize_failed; treating as non-match");
+                                false
                             }
                         }

Based on learnings.

🧹 Nitpick comments (2)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (2)

357-373: Handle Option directly instead of sentinel string.

Using "n/a" as a sentinel and then string-comparing is fragile. Refactor to handle the Option<String> result from block_hash_hex_from_block_bytes directly.

Apply this diff:

             StreamingEvent::CoreRawBlock { data } => {
-                let block_hash =
-                    super::StreamingServiceImpl::block_hash_hex_from_block_bytes(&data)
-                        .unwrap_or_else(|| "n/a".to_string());
-
-                if block_hash != "n/a"
-                    && let Ok(hash_bytes) = hex::decode(&block_hash)
-                    && !state.mark_block_delivered(&hash_bytes).await
-                {
+                let block_hash_opt = super::StreamingServiceImpl::block_hash_hex_from_block_bytes(&data);
+                
+                if let Some(block_hash) = &block_hash_opt {
+                    if let Ok(hash_bytes) = hex::decode(block_hash) {
+                        if !state.mark_block_delivered(&hash_bytes).await {
-                    trace!(
-                        subscriber_id,
-                        handle_id,
-                        block_hash = %block_hash,
-                        "transactions_with_proofs=skip_duplicate_merkle_block"
-                    );
-                    return true;
+                            trace!(
+                                subscriber_id,
+                                handle_id,
+                                block_hash = %block_hash,
+                                "transactions_with_proofs=skip_duplicate_merkle_block"
+                            );
+                            return true;
+                        }
+                    }
                 }
 
                 trace!(
                     subscriber_id,
                     handle_id,
-                    block_hash = %block_hash,
+                    block_hash = %block_hash_opt.unwrap_or_else(|| "unknown".to_string()),
                     payload_size = data.len(),
                     "transactions_with_proofs=forward_merkle_block"
                 );

1088-1092: Use _ prefix for unused error binding.

Line 1091 binds err but never uses it. Rust convention is to prefix with _ to indicate intentional non-use.

Apply this diff:

         Ok(tx) => match InstantLock::consensus_decode(&mut cursor) {
             Ok(instant_lock) => (Some(tx), Some(instant_lock)),
-            Err(err) => (Some(tx), None),
+            Err(_) => (Some(tx), 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 60d2a98 and d6e7e0d.

📒 Files selected for processing (1)
  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
packages/rs-*/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

packages/rs-*/**/*.rs: Use rustfmt defaults for Rust code (format via cargo fmt --all)
Keep Rust code clippy-clean (cargo clippy)
Name Rust modules in snake_case
Use PascalCase for Rust types
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/dashmate/src/test/constants/services.js:4-4
Timestamp: 2025-10-15T14:45:30.856Z
Learning: In the dashmate codebase (packages/dashmate), during the DAPI Rust migration (rs-dapi), the old service keys `dapi_api` and `dapi_core_streams` are intentionally kept in `generateEnvsFactory.js` for backward compatibility even though the test constants in `src/test/constants/services.js` have been updated to use `rs_dapi`. These deprecated keys will be removed in a future PR after the transition is complete.
Learnt from: shumkov
PR: dashpay/platform#2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:69-125
Timestamp: 2024-10-24T05:07:35.892Z
Learning: Future development plans involve rewriting DAPI into Rust, as the rest of the project has already migrated.
🧬 Code graph analysis (1)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (3)
packages/rs-dapi/src/services/streaming_service/bloom.rs (2)
  • bloom_flags_from_int (103-114)
  • matches_transaction (55-101)
packages/rs-dapi/src/services/streaming_service/mod.rs (8)
  • txid_bytes_from_bytes (57-65)
  • txid_hex_from_bytes (48-54)
  • block_hash_hex_from_block_bytes (68-74)
  • summarize_streaming_event (87-129)
  • deserialize (51-51)
  • deserialize (62-62)
  • deserialize (71-71)
  • short_hex (77-84)
packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs (2)
  • matches (97-99)
  • deserialize (39-39)
⏰ 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). (158)
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Formatting
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Formatting
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (dpp) / Formatting
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (dpp) / Formatting
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (dpp) / Formatting
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (dpp) / Formatting
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (dpp) / Formatting
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (dpp) / Formatting
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (dpp) / Formatting
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (drive) / Tests
  • GitHub Check: Rust packages (drive) / Linting
  • GitHub Check: Rust packages (dpp) / Check each feature
  • GitHub Check: Rust packages (dpp) / Linting
  • GitHub Check: Rust packages (dpp) / Formatting
  • GitHub Check: Rust packages (dpp) / Unused dependencies
  • GitHub Check: Rust packages (dpp) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image

Comment on lines +736 to +738
if start > best_height.saturating_add(1) {
return Err(Status::not_found(format!("Block {} not found", start)));
}
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 | 🔴 Critical

🧩 Analysis chain

Verify height bounds check allows future block.

The check start > best_height.saturating_add(1) permits requesting best_height + 1, which is a block that doesn't exist yet. Confirm this is intentional behavior for handling edge cases where a new block might arrive between calls.

Run this verification:


🏁 Script executed:

#!/bin/bash
# Check if other parts of the codebase have similar height validation patterns

rg -nP --type=rust -C3 'best.*height.*saturating_add\(1\)' 

Length of output: 2896


Based on the script output, I've identified a critical inconsistency that confirms the review comment's concern.

Fix the height bounds check to use >= instead of > for consistency.

The script output reveals an inconsistency between two streaming services:

  • transaction_stream.rs:736: if start > best_height.saturating_add(1) (allows best_height + 1)
  • block_header_stream.rs:491: if start_height >= best_height.saturating_add(1) (denies best_height + 1)

The > operator in transaction_stream.rs permits requesting best_height + 1, a block that doesn't yet exist. While this may compute available = 1 through saturating arithmetic, this differs from block_header_stream's stricter >= check. The two files should use the same bounds validation logic for consistency and correctness.

Change line 736 from > to >= to align with block_header_stream.rs and prevent requests beyond the known blockchain height.

🤖 Prompt for AI Agents
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs around
lines 736-738: the height bounds check currently uses `if start >
best_height.saturating_add(1)` which permits `best_height + 1` while
block_header_stream.rs denies it; change the operator to `>=` so the line reads
`if start >= best_height.saturating_add(1)` to align validation with
block_header_stream.rs and prevent requesting a non-existent block height.

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

♻️ Duplicate comments (1)
packages/rs-dapi/src/services/streaming_service/zmq_listener.rs (1)

465-490: Health check mechanism may be unreliable and could cause resource issues.

This is the same concern raised in the previous review. The health check subscribes to a "ping" topic every 10 seconds, which:

  1. May not be idempotent—repeated subscriptions could create internal state in the ZeroMQ socket.
  2. Tests a non-existent topic rather than verifying receipt of real Dash Core messages.
  3. Uses subscribe() success/failure as a proxy for connection health, which may not catch all failure modes.

The previous review suggested alternatives like tracking time since last message or using a lightweight socket health check API if available.

🧹 Nitpick comments (3)
packages/rs-dapi/src/services/streaming_service/zmq_listener.rs (3)

34-34: Consider removing unused rawtxlock field.

The rawtxlock field is defined but never included in to_vec() (line 62 uses rawtxlocksig instead), and parse_zmq_message explicitly ignores rawtxlock messages (lines 402-403). If rawtxlock is intentionally unused in favor of rawtxlocksig, consider removing this field or adding a comment explaining why it's kept for future use.


309-346: Infinite retry loop lacks explicit cancellation check.

The loop on line 309 runs indefinitely with no explicit check for cancel_parent.is_cancelled(). While cancellation is handled implicitly through with_cancel wrapper and ZmqConnection::new accepting a cancel token, the loop will continue to retry even after cancellation is requested, only exiting when the task is aborted.

Consider adding an explicit cancellation check:

 loop {
+    if cancel_parent.is_cancelled() {
+        return Err(DapiError::ConnectionClosed);
+    }
+
     // We don't want to cancel parent task by mistake
     let cancel = cancel_parent.child_token();

This makes the cancellation behavior more explicit and avoids unnecessary work after cancellation.


507-523: Consider expanding test coverage.

The current tests only cover basic initialization. Consider adding tests for:

  • Message parsing (parse_zmq_message with various frame combinations)
  • Topic vector generation (to_vec() completeness)
  • Error handling (connection failures, malformed messages)
  • Cancellation behavior
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d6e7e0d and bce5a46.

📒 Files selected for processing (1)
  • packages/rs-dapi/src/services/streaming_service/zmq_listener.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/rs-dapi/src/services/streaming_service/zmq_listener.rs
packages/rs-*/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

packages/rs-*/**/*.rs: Use rustfmt defaults for Rust code (format via cargo fmt --all)
Keep Rust code clippy-clean (cargo clippy)
Name Rust modules in snake_case
Use PascalCase for Rust types
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-dapi/src/services/streaming_service/zmq_listener.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/dashmate/src/test/constants/services.js:4-4
Timestamp: 2025-10-15T14:45:30.856Z
Learning: In the dashmate codebase (packages/dashmate), during the DAPI Rust migration (rs-dapi), the old service keys `dapi_api` and `dapi_core_streams` are intentionally kept in `generateEnvsFactory.js` for backward compatibility even though the test constants in `src/test/constants/services.js` have been updated to use `rs_dapi`. These deprecated keys will be removed in a future PR after the transition is complete.
Learnt from: shumkov
PR: dashpay/platform#2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:69-125
Timestamp: 2024-10-24T05:07:35.892Z
Learning: Future development plans involve rewriting DAPI into Rust, as the rest of the project has already migrated.
🧬 Code graph analysis (1)
packages/rs-dapi/src/services/streaming_service/zmq_listener.rs (2)
packages/rs-dapi/src/config/mod.rs (7)
  • std (225-225)
  • default (47-54)
  • default (136-145)
  • default (149-153)
  • default (157-162)
  • default (166-174)
  • default (198-205)
packages/rs-dapi/src/services/streaming_service/mod.rs (2)
  • new (168-187)
  • summarize_zmq_event (132-166)
⏰ 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). (162)
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Unused dependencies
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Linting
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Build Docker images (RS-DAPI, rs-dapi, rs-dapi) / Build RS-DAPI image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
🔇 Additional comments (12)
packages/rs-dapi/src/services/streaming_service/zmq_listener.rs (12)

1-23: LGTM!

The imports are well-organized and include all necessary dependencies for async ZMQ handling, cancellation, and tracing.


70-83: LGTM!

The ZmqEvent enum is well-structured with clear variants for each Dash Core ZMQ topic. The use of Vec<u8> for raw data is appropriate.


85-99: LGTM!

The ZmqConnection struct properly manages shared state with Arc and atomic types, and the Drop implementation ensures cancellation on cleanup.


197-206: Acknowledged limitation: Disconnected event unreliable.

The comment correctly notes that the Disconnected event is never received, which is why the health check workaround in tick_event_10s exists. This is a known limitation of the zeromq library.


225-241: LGTM!

The SocketRecv implementation correctly handles channel closure and explicitly drops the lock before processing the result.


252-263: LGTM!

The new() constructor properly initializes the listener and establishes the initial connection. The broadcast channel size of 1000 is reasonable for buffering ZMQ events.


265-288: LGTM!

The connection setup properly uses child tokens to allow connection retries within the task without cancelling the task itself. The error handling correctly cancels the parent task when the listener fails.


349-387: LGTM!

The message processing loop correctly handles different error cases and gracefully continues when broadcast fails (which is expected when no subscribers are listening).


389-413: LGTM!

The message parsing correctly handles all expected Dash Core ZMQ topics and gracefully ignores unknown topics with logging.


424-429: LGTM!

The spawn method correctly sets up the dispatcher worker with cancellation support.


433-463: LGTM!

The dispatcher worker correctly handles both message reception and periodic health checks, with appropriate error handling and cancellation.


493-505: LGTM!

The with_cancel helper is a clean abstraction for adding cancellation support to futures.

Comment on lines +137 to +142
for topic in topics {
socket
.subscribe(topic)
.await
.map_err(DapiError::ZmqConnection)?;
}
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

Subscription failures may leave socket in inconsistent state.

If subscription fails for a topic after some topics have already been subscribed (e.g., topic 3 fails but topics 1-2 succeeded), the socket remains connected with partial subscriptions, and the error propagates up. This could lead to missing events for the failed topic while still receiving others.

Consider either:

  1. Collecting subscription errors and unsubscribing from already-subscribed topics before returning an error.
  2. Documenting that partial subscription failures are acceptable and will be retried on the next connection attempt.
 // Subscribe to topics
+let mut subscribed_topics = Vec::new();
 for topic in topics {
-    socket
+    if let Err(e) = socket
         .subscribe(topic)
         .await
-        .map_err(DapiError::ZmqConnection)?;
+    {
+        // Cleanup partial subscriptions
+        for sub in subscribed_topics {
+            let _ = socket.unsubscribe(&sub).await;
+        }
+        return Err(DapiError::ZmqConnection(e));
+    }
+    subscribed_topics.push(topic.clone());
 }
🤖 Prompt for AI Agents
In packages/rs-dapi/src/services/streaming_service/zmq_listener.rs around lines
137 to 142, the loop subscribes topics one-by-one but if a subscribe call fails
after some prior successes the socket is left in a partially-subscribed state;
change the logic to track successfully subscribed topics and on any subscription
error iterate over that list to unsubscribe them (awaiting each and logging or
swallowing unsubscribe errors) before returning the original
DapiError::ZmqConnection; ensure the unsubscribe calls use the same async socket
API and preserve the original error for return so callers see the root failure.

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

♻️ Duplicate comments (11)
packages/rs-dapi/src/services/streaming_service/zmq_listener.rs (3)

301-304: Rename applied correctly

is_running() now reflects cancellation state, not socket connectivity. Good.


142-149: Prevent partial-subscription state on failure

If one topic subscribe fails after earlier successes, the socket remains partially subscribed. Roll back successful subscriptions before returning the error.

-        // Subscribe to topics
-        for topic in topics {
-            socket
-                .subscribe(topic)
-                .await
-                .map_err(DapiError::ZmqConnection)?;
-        }
+        // Subscribe to topics with rollback on failure
+        let mut subscribed: Vec<String> = Vec::new();
+        for topic in topics {
+            if let Err(e) = socket.subscribe(topic).await {
+                // best-effort cleanup
+                for sub in &subscribed {
+                    let _ = socket.unsubscribe(sub).await;
+                }
+                return Err(DapiError::ZmqConnection(e));
+            }
+            subscribed.push(topic.clone());
+        }

499-524: Health check via subscribe('ping') is unreliable; track last-message instead

Repeatedly subscribing to a dummy topic can be non‑idempotent and doesn’t prove data flow. Track last received message time and declare unhealthy after prolonged silence.

Sketch:

 struct ZmqDispatcher {
   socket: SubSocket,
   zmq_tx: mpsc::Sender<ZmqMessage>,
   cancel: CancellationToken,
   connected: Arc<AtomicBool>,
+  last_msg_at: std::sync::Arc<std::sync::atomic::AtomicU64>, // unix_secs
 }

@@
-                Ok(msg) => if let Err(e) = self.zmq_tx.send(msg).await {
+                Ok(msg) => {
+                    self.last_msg_at.store(
+                        std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as u64,
+                        Ordering::SeqCst
+                    );
+                    if let Err(e) = self.zmq_tx.send(msg).await {
                         ...
-                        },
+                    }
+                }
@@
-    async fn tick_event_10s(&mut self) {
-        // Health check of zmq connection (hack)
-        let current_status = self.socket.subscribe("ping").await.is_ok();
-        self.socket.unsubscribe("ping").await.inspect_err(|e| { ... }).ok();
-        let previous_status = self.connected.swap(current_status, Ordering::SeqCst);
+    async fn tick_event_10s(&mut self) {
+        let now = std::time::SystemTime::now().duration_since(std::time::UNIX_EPOCH).unwrap().as_secs() as u64;
+        let last = self.last_msg_at.load(Ordering::SeqCst);
+        let current_status = now.saturating_sub(last) <= 60;
+        let previous_status = self.connected.swap(current_status, Ordering::SeqCst);
         if current_status != previous_status {
             if current_status {
                 debug!("ZMQ connection recovered");
             } else {
                 debug!("ZMQ connection is lost, connection will be restarted");
                 self.cancel.cancel();
             }
         }
     }
packages/rs-dapi/src/services/streaming_service/mod.rs (3)

446-448: Use structured field for lag count; lower severity

Record the numeric count and log at debug to avoid noisy error logs during pressure.

-                Err(RecvError::Lagged(skipped)) => {
-                    tracing::error!(skipped, "ZMQ event reader lagged, skipped events");
-                }
+                Err(RecvError::Lagged(skipped)) => {
+                    debug!(skipped = skipped, "ZMQ receiver lagged; skipping");
+                    continue;
+                }

284-289: Standardize lag logging (structured fields)

Prefer structured fields over string formatting for skipped.

-                    debug!(
-                        "Tenderdash event receiver lagged, skipped {} events",
-                        skipped
-                    );
+                    debug!(skipped = skipped, "Tenderdash tx receiver lagged");
-                    debug!(
-                        skipped,
-                        "Tenderdash block event receiver lagged, skipped events",
-                    );
+                    debug!(skipped = skipped, "Tenderdash block receiver lagged");

Also applies to: 326-331


361-365: Good: backoff reset after successful processing

Backoff resets to 1s after processing ends; aligns with earlier guidance.

packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (2)

941-960: Remove raw-bytes bloom fallback; avoid unwrap on lock

Falling back to contains(raw_bytes) misrepresents bloom semantics and masks encoding issues; .unwrap() can panic.

-                    FilterType::CoreBloomFilter(bloom, flags) => {
-                        match deserialize::<CoreTx>(tx_bytes.as_slice()) {
-                            Ok(tx) => {
-                                let matches = super::bloom::matches_transaction(
-                                    Arc::clone(bloom),
-                                    &tx,
-                                    *flags,
-                                );
-                                trace!(height,matches, txid = %tx.txid(), "transactions_with_proofs=bloom_match");
-                                matches
-                            }
-                            Err(e) => {
-                                debug!(height, error = %e, "transactions_with_proofs=tx_deserialize_failed, checking raw-bytes contains()");
-                                let guard = bloom.read().unwrap();
-                                guard.contains(tx_bytes)
-                            }
-                        }
-                    }
+                    FilterType::CoreBloomFilter(bloom, flags) => match deserialize::<CoreTx>(tx_bytes.as_slice()) {
+                        Ok(tx) => {
+                            let matches = super::bloom::matches_transaction(Arc::clone(bloom), &tx, *flags);
+                            trace!(height, matches, txid = %tx.txid(), "transactions_with_proofs=bloom_match");
+                            matches
+                        }
+                        Err(e) => {
+                            debug!(height, error = %e, "transactions_with_proofs=tx_deserialize_failed; treating as non-match");
+                            false
+                        }
+                    }

756-766: Align height bounds check with other streams (deny best_height + 1)

Use >= to avoid allowing a non-existent future block and to keep consistency with block_header_stream.

-                if start > best_height.saturating_add(1) {
+                if start >= best_height.saturating_add(1) {
                     return Err(Status::not_found(format!("Block {} not found", start)));
                 }
packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs (3)

38-59: Do not fallback to raw-bytes bloom.contains(); treat as non-match

Fallback hides encoding bugs and breaks bloom semantics. Log and return false.

-            FilterType::CoreBloomFilter(bloom, flags) => match deserialize::<CoreTx>(raw_tx) {
-                Ok(tx) => super::bloom::matches_transaction(Arc::clone(bloom), &tx, *flags),
-
-                Err(e) => {
-                    debug!(
-                        error = %e,
-                        "Failed to deserialize core transaction for bloom filter matching, falling back to contains()"
-                    );
-                    match bloom.read() {
-                        Ok(guard) => guard.contains(raw_tx),
-                        Err(_) => {
-                            debug!("Failed to acquire read lock for bloom filter");
-                            false
-                        }
-                    }
-                }
-            },
+            FilterType::CoreBloomFilter(bloom, flags) => match deserialize::<CoreTx>(raw_tx) {
+                Ok(tx) => super::bloom::matches_transaction(Arc::clone(bloom), &tx, *flags),
+                Err(e) => {
+                    debug!(error = %e, "deserialize failed; treating as non-match");
+                    false
+                }
+            },

219-259: Update test to reflect non-fallback semantics

After removing fallback, non‑TX bytes should not match. Assert no message is received within timeout.

-    async fn test_non_tx_bytes_fallbacks_to_contains() {
+    async fn test_non_tx_bytes_do_not_match() {
@@
-        // We should receive one transaction message with the same bytes
-        let msg = timeout(Duration::from_millis(200), handle.recv())
-            .await
-            .expect("timed out")
-            .expect("channel closed");
-
-        match msg {
-            StreamingEvent::CoreRawTransaction { data } => {
-                assert_eq!(data, payload);
-            }
-            other => panic!("unexpected message: {:?}", other),
-        }
+        // Expect no message within timeout
+        let res = timeout(Duration::from_millis(200), handle.recv()).await;
+        assert!(res.is_err(), "unexpected match for non-transaction bytes");

261-341: Ignore the known failing persistence test to keep CI green

Mark the test with #[ignore] and reference a tracking issue.

-    #[tokio::test]
+    #[tokio::test]
+    #[ignore] // TODO(dapi#2795): enable once bloom update persistence across messages is implemented
     async fn test_bloom_update_persistence_across_messages() {
🧹 Nitpick comments (1)
packages/rs-dapi/src/services/streaming_service/mod.rs (1)

382-389: Increment counter only on successful receive

Avoid counting lag/closed as processed events.

-        loop {
-            let event = zmq_events.recv().await;
-
-            processed_events = processed_events.saturating_add(1);
-            match event {
+        loop {
+            match zmq_events.recv().await {
                 Ok(ZmqEvent::RawTransaction { data }) => {
+                    processed_events = processed_events.saturating_add(1);
                     ...
                 }
                 Ok(ZmqEvent::RawBlock { data }) => {
+                    processed_events = processed_events.saturating_add(1);
                     ...
                 }
                 Ok(ZmqEvent::RawTransactionLock { tx_bytes, lock_bytes }) => {
+                    processed_events = processed_events.saturating_add(1);
                     ...
                 }
                 Ok(ZmqEvent::RawChainLock { data }) => {
+                    processed_events = processed_events.saturating_add(1);
                     ...
                 }
                 Ok(ZmqEvent::HashBlock { hash }) => {
+                    processed_events = processed_events.saturating_add(1);
                     ...
                 }
                 Err(RecvError::Closed) => break,
                 Err(RecvError::Lagged(skipped)) => { ... }
             }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bce5a46 and 656763f.

📒 Files selected for processing (4)
  • packages/rs-dapi/src/services/streaming_service/mod.rs (1 hunks)
  • packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs (1 hunks)
  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (1 hunks)
  • packages/rs-dapi/src/services/streaming_service/zmq_listener.rs (1 hunks)
🧰 Additional context used
📓 Path-based instructions (2)
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

**/*.rs: Format Rust code with cargo fmt
Run Clippy linter for Rust code

Files:

  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
  • packages/rs-dapi/src/services/streaming_service/mod.rs
  • packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs
  • packages/rs-dapi/src/services/streaming_service/zmq_listener.rs
packages/rs-*/**/*.rs

📄 CodeRabbit inference engine (AGENTS.md)

packages/rs-*/**/*.rs: Use rustfmt defaults for Rust code (format via cargo fmt --all)
Keep Rust code clippy-clean (cargo clippy)
Name Rust modules in snake_case
Use PascalCase for Rust types
Use SCREAMING_SNAKE_CASE for Rust constants

Files:

  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
  • packages/rs-dapi/src/services/streaming_service/mod.rs
  • packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs
  • packages/rs-dapi/src/services/streaming_service/zmq_listener.rs
🧠 Learnings (1)
📓 Common learnings
Learnt from: lklimek
PR: dashpay/platform#2716
File: packages/dashmate/src/test/constants/services.js:4-4
Timestamp: 2025-10-15T14:45:30.856Z
Learning: In the dashmate codebase (packages/dashmate), during the DAPI Rust migration (rs-dapi), the old service keys `dapi_api` and `dapi_core_streams` are intentionally kept in `generateEnvsFactory.js` for backward compatibility even though the test constants in `src/test/constants/services.js` have been updated to use `rs_dapi`. These deprecated keys will be removed in a future PR after the transition is complete.
Learnt from: shumkov
PR: dashpay/platform#2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:69-125
Timestamp: 2024-10-24T05:07:35.892Z
Learning: Future development plans involve rewriting DAPI into Rust, as the rest of the project has already migrated.
🧬 Code graph analysis (4)
packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (2)
packages/rs-dapi/src/services/streaming_service/bloom.rs (2)
  • bloom_flags_from_int (103-114)
  • matches_transaction (55-101)
packages/rs-dapi/src/services/streaming_service/mod.rs (8)
  • txid_bytes_from_bytes (57-65)
  • txid_hex_from_bytes (48-54)
  • block_hash_hex_from_block_bytes (68-74)
  • summarize_streaming_event (87-133)
  • deserialize (51-51)
  • deserialize (62-62)
  • deserialize (71-71)
  • short_hex (77-84)
packages/rs-dapi/src/services/streaming_service/mod.rs (3)
packages/rs-dapi/src/services/streaming_service/zmq_listener.rs (2)
  • new (111-152)
  • new (258-269)
packages/rs-dapi/src/services/streaming_service/masternode_list_sync.rs (1)
  • new (32-41)
packages/rs-dapi/src/clients/tenderdash_websocket.rs (1)
  • new (78-88)
packages/rs-dapi/src/services/streaming_service/subscriber_manager.rs (3)
packages/rs-dapi/src/services/streaming_service/mod.rs (1)
  • summarize_streaming_event (87-133)
packages/rs-dapi/src/services/streaming_service/bloom.rs (1)
  • matches_transaction (55-101)
packages/rs-dash-event-bus/src/event_bus.rs (6)
  • clone (36-43)
  • clone (218-225)
  • id (234-236)
  • matches (16-16)
  • matches (429-431)
  • subscription_count (185-187)
packages/rs-dapi/src/services/streaming_service/zmq_listener.rs (2)
packages/rs-dapi/src/config/mod.rs (7)
  • std (225-225)
  • default (47-54)
  • default (136-145)
  • default (149-153)
  • default (157-162)
  • default (166-174)
  • default (198-205)
packages/rs-dapi/src/services/streaming_service/mod.rs (2)
  • new (176-195)
  • summarize_zmq_event (136-174)
⏰ 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). (147)
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Rust packages (dashpay-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Rust packages (dashpay-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Rust packages (dashpay-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Rust packages (dashpay-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Rust packages (dashpay-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Rust packages (dashpay-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Rust packages (dashpay-contract) / Tests
  • GitHub Check: Rust packages (dashpay-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Rust packages (dashpay-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Rust packages (dashpay-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Linting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Tests
  • GitHub Check: Rust packages (json-schema-compatibility-validator) / Formatting
  • GitHub Check: Rust packages (masternode-reward-shares-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Linting
  • GitHub Check: Rust packages (dashpay-contract) / Formatting
  • GitHub Check: Rust packages (dashpay-contract) / Tests
  • GitHub Check: Rust packages (withdrawals-contract) / Unused dependencies
  • GitHub Check: Rust packages (token-history-contract) / Unused dependencies
  • GitHub Check: Rust packages (withdrawals-contract) / Formatting
  • GitHub Check: Rust packages (token-history-contract) / Tests
  • GitHub Check: Build Docker images (DAPI, dapi, dapi) / Build DAPI image
  • GitHub Check: Build Docker images (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build Docker images (Dashmate helper, dashmate-helper, dashmate-helper) / Build Dashmate helper image

Comment on lines +358 to +373
let block_hash =
super::StreamingServiceImpl::block_hash_hex_from_block_bytes(&data)
.unwrap_or_else(|| "n/a".to_string());

if block_hash != "n/a"
&& let Ok(hash_bytes) = hex::decode(&block_hash)
&& !state.mark_block_delivered(&hash_bytes).await
{
trace!(
subscriber_id,
handle_id,
block_hash = %block_hash,
"transactions_with_proofs=skip_duplicate_merkle_block"
);
return true;
}
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

Fix block-hash dedupe: byte-order inconsistency causes missed duplicates

Here you decode the displayed hex (big‑endian) to bytes, but elsewhere you store BlockHash bytes via AsRef/to_byte_array() (little‑endian). Use the same representation in both paths.

-                let block_hash =
-                    super::StreamingServiceImpl::block_hash_hex_from_block_bytes(&data)
-                        .unwrap_or_else(|| "n/a".to_string());
-
-                if block_hash != "n/a"
-                    && let Ok(hash_bytes) = hex::decode(&block_hash)
-                    && !state.mark_block_delivered(&hash_bytes).await
-                {
+                let block_hash =
+                    super::StreamingServiceImpl::block_hash_hex_from_block_bytes(&data)
+                        .unwrap_or_else(|| "n/a".to_string());
+
+                // Normalize to internal byte order for dedupe
+                if let Ok(block) = dashcore_rpc::dashcore::consensus::encode::deserialize::<Block>(&data) {
+                    let hash_bytes = block.block_hash().to_byte_array().to_vec();
+                    if !state.mark_block_delivered(&hash_bytes).await {
                         trace!(
                             subscriber_id,
                             handle_id,
-                            block_hash = %block_hash,
+                            block_hash = %block_hash,
                             "transactions_with_proofs=skip_duplicate_merkle_block"
                         );
                         return true;
-                }
+                    }
+                }
🤖 Prompt for AI Agents
In packages/rs-dapi/src/services/streaming_service/transaction_stream.rs around
lines 358 to 373, the code decodes the displayed hex (big-endian) to bytes but
compares/stores BlockHash elsewhere as little-endian, causing missed duplicates;
after decoding hex::decode(&block_hash) convert the decoded byte vector to the
same little-endian representation used by mark_block_delivered (e.g., reverse
the byte order or call the same to_byte_array()/AsRef conversion used when
storing) before calling state.mark_block_delivered(&hash_bytes). Ensure the
comparison uses the identical byte-ordering path as the rest of the codebase so
deduplication works correctly.

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.

2 participants