Skip to content

Conversation

@lklimek
Copy link
Contributor

@lklimek lklimek commented Oct 2, 2025

Issue being fixed or feature implemented

  • Provide DAPI clients with a supported path to consume Drive’s new platform event bus so they can react to block commits and finalized state transitions without polling (packages/dapi-grpc/protos/
    platform/v0/platform.proto:8, packages/rs-drive-abci/src/abci/handler/finalize_block.rs:1, packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs:1).
  • Align node tooling and SDKs with the new streaming capability, including configurable timeouts and developer ergonomics, so operators and integrators can adopt the feature safely (packages/
    dashmate/templates/platform/gateway/envoy.yaml.dot:1, packages/rs-sdk/src/platform/events.rs:1).

What was done?

  • Added a versioned subscribePlatformEvents RPC plus event filter schema, then emitted block and state-transition events from the ABCI finalize flow via a shared in-process event bus to make Drive
    the authoritative producer (packages/dapi-grpc/protos/platform/v0/platform.proto:8, packages/rs-drive-abci/src/abci/handler/finalize_block.rs:1, packages/rs-dash-event-bus/src/event_bus.rs:1).
  • Proxied the stream through rs-dapi with new Prometheus counters and per-route deadlines so each downstream subscription receives its own upstream channel while remaining observable and bounded
    (packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs:1, packages/rs-dapi/src/metrics.rs:89, packages/rs-dapi/src/server/grpc.rs:21).
  • Taught dashmate to surface the additional timeouts, migrate older configs, and render Envoy settings from the single source of truth so operators don’t need manual edits when enabling platform
    event subscriptions (packages/dashmate/configs/getConfigFileMigrationsFactory.js:1164, packages/dashmate/templates/platform/gateway/envoy.yaml.dot:1, packages/dashmate/docs/config/dapi.md:39).
  • Extended the Rust SDK (and wasm bindings) with a subscription helper, error mapping, sample app, and network test to help client developers consume the new stream and validate the handshake
    semantics (packages/rs-sdk/src/platform/events.rs:1, packages/rs-sdk/tests/fetch/platform_events.rs:1, packages/wasm-sdk/src/error.rs:169).

Note

This is only preliminary implementation, adding necessary scaffolding to emit and deliver events to user.
Implemented events are more a proof-of-concept. Further work is needed to emit meaningful events, like document update, etc.

How Has This Been Tested?

  • Added async network test for the new SDK stream subscription (packages/rs-sdk/tests/fetch/platform_events.rs:1).
  • No automated suite was run in this environment; the new test exercises the end-to-end flow when network-testing is enabled.

Breaking Changes

  • Code-wise - none. The gRPC interface is additive and dashmate migrations backfill the new timeout settings.
  • Some dashmate config settings were altered (especially timeouts).

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

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 2, 2025

Walkthrough

Platform event streaming support added through new Protobuf messages, a gRPC RPC method, event bus infrastructure for publishing events, subscription forwarding in rs-dapi, client library implementations, and associated configuration, tests, and documentation updates.

Changes

Cohort / File(s) Summary
Protocol Buffer Definitions
packages/dapi-grpc/protos/platform/v0/platform.proto
Added versioned subscription/response messages (PlatformSubscriptionRequest, PlatformSubscriptionResponse), event and filter definitions (PlatformEventV0, PlatformFilterV0), and server-streaming RPC method subscribePlatformEvents to Platform service.
rs-dapi Core Implementation
packages/rs-dapi/src/services/platform_service/mod.rs, subscribe_platform_events.rs, wait_for_state_transition_result.rs
Added new subscribe_platform_events_impl method for streaming subscriptions with active session tracking and metrics. Replaced timeout-based loop with gRPC deadline-based approach in wait_for_state_transition_result.
rs-dapi Configuration & Server
packages/rs-dapi/src/config/mod.rs, config/tests.rs, server/grpc.rs, src/main.rs, metrics.rs
Added platform_events_timeout and core_stream_timeout config fields. Refactored TimeoutLayer to support per-method timeouts. Removed legacy PlatformEvents metric variants. Made server future binding immutable.
rs-dapi Documentation
packages/rs-dapi/doc/DESIGN.md, README.md
Updated design docs to reflect direct streaming pattern without multiplexing. Added new environment variable documentation.
rs-dapi Utilities
packages/rs-dapi/src/services/streaming_service/bloom.rs, block_header_stream.rs, mod.rs
Simplified conditional logic in bloom filter and removed unused import in block header stream.
Event Bus Core
packages/rs-dash-event-bus/Cargo.toml, src/event_bus.rs, src/lib.rs
Updated description from multiplexer to utilities. Added synchronous removal fallback path in SubscriptionHandle::Drop with metrics updates.
rs-drive-abci Event Bus Integration
packages/rs-drive-abci/Cargo.toml, src/abci/app/mod.rs, app/consensus.rs, app/full.rs, handler/finalize_block.rs, query/mod.rs, query/service.rs, server.rs
Added EventBus infrastructure to ABCI app, implemented EventBusApplication trait, added event publishing in finalize_block for BlockCommitted and StateTransitionFinalized events, integrated PlatformFilterAdapter for event filtering.
rs-drive-abci Tests
tests/strategy_tests/main.rs
Added event_bus_subscribe_all_and_receive integration test.
rs-sdk Subscription Support
packages/rs-sdk/Cargo.toml, src/error.rs, src/platform.rs, src/platform/events.rs, src/sdk.rs, examples/platform_events.rs
Added subscriptions feature, SubscriptionError variant, subscribe_platform_events method to Sdk, new events module, and example demonstrating subscription usage.
rs-sdk Tests
tests/fetch/mod.rs, fetch/platform_events.rs, fetch/config.rs
Added feature-gated platform_events test module and test for handshake validation.
wasm-sdk Error Handling
packages/wasm-sdk/src/error.rs
Added SubscriptionError mapping to WasmSdkError conversion.
Generated Java Client
packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java
Generated server-streaming RPC bindings for subscribePlatformEvents with method handler and stub implementations.
Generated Python Client
packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py
Generated unary_stream RPC for subscribePlatformEvents with servicer, stub, and experimental API bindings.
Generated Web Client
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts, platform_pb.js, platform_pb_service.d.ts, platform_pb_service.js
Generated TypeScript declarations and JavaScript implementation for subscription and event messages with full serialization support.
Generated NodeJS Client
packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
Generated protobuf JS with constructors, (de)serialization, and oneof handling for subscription, event, and filter messages.
Generated Objective-C Client
packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h, Platform.pbobjc.m, Platform.pbrpc.h, Platform.pbrpc.m
Generated Objective-C message descriptors, class definitions, and gRPC service bindings for subscribePlatformEvents.
Configuration & Documentation
packages/dashmate/configs/defaults/getBaseConfigFactory.js, getConfigFileMigrationsFactory.js, docker-compose.yml, docs/config/gateway.md, docs/config/dapi.md, docs/services/gateway.md, src/config/configJsonSchema.js
Migrated from waitForStResultTimeout to structured timeouts (waitForStateTransitionResult, subscribePlatformEvents, coreStreams), updated env vars, and migrated configuration schema.
gRPC Coverage & Utilities
.github/scripts/check-grpc-coverage.py, packages/dapi-grpc/src/lib.rs, packages/rs-dapi/src/services/streaming_service/bloom.rs
Excluded subscribePlatformEvents from coverage checks and added lint suppression for non-CamelCase types.
Test Utilities
packages/wasm-drive-verify/tests/fuzz_tests.rs
Removed unused import and made query binding immutable via interior mutation.

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant rsDapi as rs-dapi<br/>PlatformService
    participant EventBus as Event Bus<br/>(in-process)
    participant Drive as Drive<br/>(upstream)
    participant ABCI as rs-drive-abci<br/>ConsensusApp

    Client->>rsDapi: PlatformSubscriptionRequest<br/>(filter, keepalive)
    activate rsDapi
    rsDapi->>EventBus: subscribe(filter)
    activate EventBus
    rsDapi->>Drive: subscribe_platform_events(filter)
    activate Drive
    
    ABCI->>EventBus: publish BlockCommitted
    EventBus-->>rsDapi: event via receiver
    rsDapi-->>Client: PlatformSubscriptionResponse<br/>(subscription_id, BlockCommitted)
    
    ABCI->>EventBus: publish StateTransitionFinalized
    EventBus-->>rsDapi: event via receiver
    rsDapi-->>Client: PlatformSubscriptionResponse<br/>(subscription_id, StateTransitionFinalized)
    
    Drive->>rsDapi: upstream stream event
    rsDapi->>EventBus: forward event
    EventBus-->>rsDapi: relayed via channel
    rsDapi-->>Client: PlatformSubscriptionResponse
    
    note over rsDapi: Keepalive timer
    rsDapi-->>Client: PlatformSubscriptionResponse<br/>(subscription_id, Keepalive)
    
    Client->>rsDapi: cancel/stream ends
    deactivate rsDapi
    deactivate EventBus
    deactivate Drive
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Key areas requiring attention:

  • Event bus integration across multiple crates: Changes to rs-drive-abci event publishing logic in finalize_block and new EventBusApplication trait require verification that events are published correctly and metrics are updated properly.
  • Timeout refactoring in rs-dapi: The TimeoutLayer now handles per-method timeouts; verify that all four timeout paths (unary, state_transition, platform_events, core_stream) map correctly and no methods are missed.
  • Configuration migration in dashmate: Complex migration logic for legacy waitForStResultTimeout and upstreams; verify backward compatibility and that all config paths resolve correctly.
  • Client code generation: Verify that all language-specific generated bindings are syntactically correct and follow existing patterns (especially ObjectiveC descriptors and Java gRPC wiring).
  • Subscription stream lifecycle: ActiveSessionGuard, metrics updates, channel closure handling, and keepalive logic should be tested for edge cases.

🐰 Streaming events through the bus so bright,
With filters and timeouts set just right,
Events flow free from Drive's stream,
A subscription platform dream! 🎉

Pre-merge checks and finishing touches

✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The pull request title 'feat(drive-abci): preliminary support for event subscriptions in Platform' accurately describes the primary change in the changeset. The title uses a conventional format with a scope (drive-abci) and clearly indicates the main objective: adding preliminary support for event subscriptions. This aligns well with the extensive changes across multiple packages that introduce event bus infrastructure, streaming APIs, and subscription handling.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
✨ 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 feat/drive-event-bus

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.

@github-actions
Copy link

github-actions bot commented Oct 2, 2025

✅ gRPC Query Coverage Report

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

Total queries in proto: 48
Previously known queries: 47
New queries found: 1

================================================================================

New Query Implementation Status:
--------------------------------------------------------------------------------
⊘ subscribePlatformEvents                       EXCLUDED

================================================================================
Summary:
--------------------------------------------------------------------------------
All new queries are excluded

Total known queries: 48
  - Implemented: 44
  - Not implemented: 2
  - Excluded: 2

Not implemented queries:
  - getConsensusParams
  - getTokenPreProgrammedDistributions

@lklimek
Copy link
Contributor Author

lklimek commented Oct 2, 2025

@coderabbitai review all

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 2, 2025

@lklimek: I'll perform a comprehensive review of all the changes in this PR.

✅ Actions performed

Full review triggered.

@pshenmic
Copy link
Collaborator

pshenmic commented Oct 13, 2025

Client streaming and bi-directional streams are not available via GRPC Web, it is not supported by the Javascript libraries and most likely will not be supported, because all of them uses Fetch as underlying layer for transport.

Server streaming is supported though, it would be great to have a subscription RPC that we could use from Web, and I feel like it is rarely when you want to change your subscription conditions, it is much easier to just cancel an create new subscription, and passing a list of params for subscription should work too.

I recently received a question, how do one subscribe on new documents or transactions to his data contracts, because people would like to build applications like chats, or integrations in their backend already, for example for accepting tokens in payment gateways, so I'm looking forward to it!

@lklimek
Copy link
Contributor Author

lklimek commented Oct 13, 2025

Client streaming and bi-directional streams are not available via GRPC Web, it is not supported by the Javascript libraries and most likely will not be supported, because all of them uses Fetch as underlying layer for transport.

Thanks for that info! I'll refactor to unidirectional grpc-web.

@github-actions
Copy link

github-actions bot commented Oct 21, 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: "c9201581129c144406ed01884ba79abfeac528e52fc6d457be057843a6651760"
)

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.

@lklimek
Copy link
Contributor Author

lklimek commented Oct 22, 2025

@coderabbitai review all

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 22, 2025

@lklimek: I'll perform a comprehensive review of all the changes in this PR.

✅ Actions performed

Full review triggered.

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

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

164-166: Nice refactor using let-chains.

The consolidated conditional using && let Ok(tx_data) = is more concise and idiomatic than nested if-let blocks, with no change in behavior.

packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs (2)

11-27: Good session tracking pattern with one consideration.

The ActiveSessionGuard with Arc and Drop ensures proper metric cleanup. The buffer size of 512 is used but lacks justification in comments.

Consider documenting why 512 was chosen for PLATFORM_EVENTS_STREAM_BUFFER (e.g., based on expected event rate, memory constraints, or latency requirements).


53-79: Forwarding loop is sound, but final return value appears unused.

The message forwarding logic correctly handles both success and error cases with proper metrics. However, the Err::<(), DapiError>(DapiError::ConnectionClosed) at line 78 serves no purpose since the spawned task's result is never awaited or checked.

Consider either:

  • Removing the return value entirely (just let the task complete without returning anything)
  • Or documenting why it's needed if there's a future plan to track task results
                }
                tracing::debug!("Platform events uplink response stream closed");
-               Err::<(), DapiError>(DapiError::ConnectionClosed)
            });
packages/rs-sdk/tests/fetch/platform_events.rs (1)

48-53: Make the “stream stays open” check non-flaky

Relying on “no message within 250ms” can intermittently fail if an event arrives quickly. Treat both “timeout” and “got a message” as success, and only fail on early close or error.

Apply:

-    let wait_result = timeout(Duration::from_millis(250), stream.message()).await;
-    assert!(
-        wait_result.is_err(),
-        "expected to time out waiting for initial platform event"
-    );
+    match timeout(Duration::from_millis(250), stream.message()).await {
+        // No message within window → stream is open; good.
+        Err(_elapsed) => {}
+        // Message arrived quickly → also fine; stream is open.
+        Ok(Ok(Some(_))) => {}
+        // Stream closed unexpectedly.
+        Ok(Ok(None)) => panic!("stream closed unexpectedly"),
+        // Transport error.
+        Ok(Err(status)) => panic!("stream errored early: {status}"),
+    }
packages/rs-drive-abci/src/abci/app/mod.rs (1)

21-27: Reduce cross-crate coupling of EventBusApplication

The trait hard-codes dapi_grpc::platform::v0 types, coupling ABCI app to gRPC schema. Consider a type alias exported from this crate (or make the trait generic) to decouple and ease future proto evolution.

Example:

pub type PlatformEvent = dapi_grpc::platform::v0::PlatformEventV0;
pub trait EventBusApplication {
    fn event_bus(&self) -> &EventBus<PlatformEvent, PlatformFilterAdapter>;
}
packages/rs-drive-abci/src/server.rs (1)

23-30: EventBus initialized and injected correctly; consider tunable capacity

Default per-subscription channel capacity comes from EventBus::new() (256). If high fan‑out or bursty publishers are expected, consider making capacity configurable via PlatformConfig and using with_capacity().

Also applies to: 79-80

packages/rs-dapi/doc/DESIGN.md (1)

267-291: Clarify gRPC‑Web limitation and client lifecycle

Explicitly note gRPC‑Web doesn’t support client/bidi streaming; only server streaming is exposed. Recommend “cancel and recreate” pattern when changing subscription parameters, as it’s simpler than dynamic updates.

packages/rs-sdk/src/sdk.rs (1)

607-625: Avoid panic on contested lock; use async lock for workers

try_lock() can spuriously panic under contention. Use lock().await and drop yield_now(). Also consider honoring Sdk::cancel_token inside spawned tasks to ensure graceful shutdown.

[Based on learnings]
Apply:

-    pub(crate) async fn spawn(
+    pub(crate) async fn spawn(
         &self,
         task: impl std::future::Future<Output = ()> + Send + 'static,
     ) -> tokio::sync::oneshot::Receiver<()> {
         let (done_tx, done_rx) = tokio::sync::oneshot::channel();
-        let mut workers = self
-            .workers
-            .try_lock()
-            .expect("workers lock is poisoned or in use");
-        workers.spawn(async move {
+        let mut workers = self.workers.lock().await;
+        let cancel = self.cancel_token.clone();
+        workers.spawn(async move {
+            tokio::select! {
+                _ = cancel.cancelled() => {},
+                _ = task => {},
+            }
             task.await;
             let _ = done_tx.send(());
         });
-        tokio::task::yield_now().await;
 
         done_rx
     }
packages/rs-sdk/src/platform/events.rs (2)

79-86: Streaming deadline: consider no overall timeout.

Setting timeout: Some(Duration::from_secs(3600)) will terminate long‑lived streams after 1 hour. For subscriptions, “no deadline” is usually preferable; rely on client cancel.

 let settings = self
     .dapi_client_settings
     .override_by(RequestSettings {
         connect_timeout: Some(Duration::from_secs(5)),
-        timeout: Some(Duration::from_secs(3600)),
+        // Streaming subscriptions typically shouldn't have a fixed deadline
+        timeout: None,
         ..Default::default()
     })
     .finalize();

16-28: Comment/typo fixes to avoid confusion.

  • “siginificant” → “significant”.
  • “ofprocess” → “of process”.
  • Display comment says “timepid” but code prints “pid_time”.
-/// ID generator with most siginificant bits based on local process info.
+/// ID generator with most significant bits based on local process info.
@@
-    // 32..47 bits: lower 16 bits ofprocess start time in seconds
+    // 32..47 bits: lower 16 bits of process start time in seconds
@@
-        // Write in format: timepid:counter
+        // Write in format: pid_time:counter

Also applies to: 40-46

packages/rs-drive-abci/src/abci/handler/finalize_block.rs (1)

115-146: DRY: duplicate BlockMetadata computation.

Factor out metadata creation to a helper to reduce duplication and keep event payloads consistent.

@@
-fn publish_block_committed_event(
+fn block_metadata_from(
+    request_finalize_block: &FinalizeBlockCleanedRequest,
+) -> platform_event_v0::BlockMetadata {
+    let header_time = request_finalize_block.block.header.time;
+    let seconds = header_time.seconds as i128;
+    let nanos = header_time.nanos as i128;
+    let time_ms = (seconds * 1000) + (nanos / 1_000_000);
+    platform_event_v0::BlockMetadata {
+        height: request_finalize_block.height,
+        time_ms: time_ms as u64,
+        block_id_hash: request_finalize_block.block_id.hash.to_vec(),
+    }
+}
+
+fn publish_block_committed_event(
     event_bus: &dash_event_bus::event_bus::EventBus<PlatformEventV0, PlatformFilterAdapter>,
     request_finalize_block: &FinalizeBlockCleanedRequest,
 ) -> Result<(), Error> {
-    // Publish BlockCommitted platform event to the global event bus (best-effort)
-    let header_time = request_finalize_block.block.header.time;
-    let seconds = header_time.seconds as i128;
-    let nanos = header_time.nanos as i128;
-    let time_ms = (seconds * 1000) + (nanos / 1_000_000);
-
-    let meta = platform_event_v0::BlockMetadata {
-        height: request_finalize_block.height,
-        time_ms: time_ms as u64,
-        block_id_hash: request_finalize_block.block_id.hash.to_vec(),
-    };
+    // Publish BlockCommitted platform event to the global event bus (best-effort)
+    let meta = block_metadata_from(request_finalize_block);
@@
-fn publish_state_transition_result_events(
+fn publish_state_transition_result_events(
     event_bus: &dash_event_bus::event_bus::EventBus<PlatformEventV0, PlatformFilterAdapter>,
     request_finalize_block: &FinalizeBlockCleanedRequest,
 ) -> Result<(), Error> {
-    // Prepare BlockMetadata once
-    let header_time = request_finalize_block.block.header.time;
-    let seconds = header_time.seconds as i128;
-    let nanos = header_time.nanos as i128;
-    let time_ms = (seconds * 1000) + (nanos / 1_000_000);
-
-    let meta = platform_event_v0::BlockMetadata {
-        height: request_finalize_block.height,
-        time_ms: time_ms as u64,
-        block_id_hash: request_finalize_block.block_id.hash.to_vec(),
-    };
+    // Prepare BlockMetadata once
+    let meta = block_metadata_from(request_finalize_block);

Also applies to: 148-179

packages/rs-sdk/examples/platform_events.rs (1)

87-96: Fail fast on invalid hex to avoid unintended “match all”.

.ok() swallows decode errors, turning an invalid hex filter into no filter (streaming all STRs).

-        let tx_hash_bytes = config
-            .state_transition_tx_hash_hex
-            .as_deref()
-            .and_then(|s| hex::decode(s).ok());
+        let tx_hash_bytes = config
+            .state_transition_tx_hash_hex
+            .as_deref()
+            .map(|s| hex::decode(s).expect("invalid DASH_SDK_STATE_TRANSITION_TX_HASH_HEX"));
packages/rs-drive-abci/src/query/service.rs (1)

271-310: Filter adapter logic looks correct and minimal.

Matching All/BlockCommitted/StateTransitionResult with optional tx_hash is clear and efficient.

Consider logging the filter summary once per subscription for observability.

packages/dapi-grpc/protos/platform/v0/platform.proto (1)

165-167: Clarify RPC streaming semantics in comment.

The comment states "Bi-directional stream" but the RPC signature is actually server-streaming only (request is unary, response is streamed). This is intentional for gRPC-Web compatibility, but the comment should reflect that. Update it to clarify the streaming direction and rationale.

  // Bi-directional stream for multiplexed platform events subscriptions
-  rpc SubscribePlatformEvents(PlatformSubscriptionRequest)
+  // Server-streaming RPC for multiplexed platform events subscriptions
+  // (Unidirectional; gRPC-Web compatible per RFC on client-streaming limitations)
+  rpc SubscribePlatformEvents(PlatformSubscriptionRequest)
       returns (stream PlatformSubscriptionResponse);
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 146643b and 1d7ca2e.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (29)
  • packages/dapi-grpc/protos/platform/v0/platform.proto (2 hunks)
  • packages/rs-dapi/doc/DESIGN.md (2 hunks)
  • packages/rs-dapi/src/main.rs (2 hunks)
  • packages/rs-dapi/src/metrics.rs (0 hunks)
  • packages/rs-dapi/src/services/platform_service/mod.rs (2 hunks)
  • packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs (1 hunks)
  • packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs (1 hunks)
  • packages/rs-dapi/src/services/streaming_service/bloom.rs (1 hunks)
  • packages/rs-dash-event-bus/Cargo.toml (1 hunks)
  • packages/rs-dash-event-bus/src/event_bus.rs (1 hunks)
  • packages/rs-dash-event-bus/src/lib.rs (1 hunks)
  • packages/rs-drive-abci/Cargo.toml (2 hunks)
  • packages/rs-drive-abci/src/abci/app/consensus.rs (3 hunks)
  • packages/rs-drive-abci/src/abci/app/full.rs (4 hunks)
  • packages/rs-drive-abci/src/abci/app/mod.rs (1 hunks)
  • packages/rs-drive-abci/src/abci/handler/finalize_block.rs (4 hunks)
  • packages/rs-drive-abci/src/query/mod.rs (1 hunks)
  • packages/rs-drive-abci/src/query/service.rs (4 hunks)
  • packages/rs-drive-abci/src/server.rs (2 hunks)
  • packages/rs-drive-abci/tests/strategy_tests/main.rs (1 hunks)
  • packages/rs-sdk/Cargo.toml (4 hunks)
  • packages/rs-sdk/examples/platform_events.rs (1 hunks)
  • packages/rs-sdk/src/error.rs (1 hunks)
  • packages/rs-sdk/src/platform.rs (1 hunks)
  • packages/rs-sdk/src/platform/events.rs (1 hunks)
  • packages/rs-sdk/src/sdk.rs (7 hunks)
  • packages/rs-sdk/tests/fetch/mod.rs (1 hunks)
  • packages/rs-sdk/tests/fetch/platform_events.rs (1 hunks)
  • packages/wasm-sdk/src/error.rs (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/rs-dapi/src/metrics.rs
🧰 Additional context used
🧠 Learnings (6)
📚 Learning: 2024-10-22T10:51:16.910Z
Learnt from: shumkov
PR: dashpay/platform#2259
File: packages/rs-dapi-client/src/transport.rs:51-51
Timestamp: 2024-10-22T10:51:16.910Z
Learning: In implementations of `TransportClient`, only `DapiClientError` is used as the `Error` type, and it implements `std::error::Error`.

Applied to files:

  • packages/rs-sdk/src/error.rs
📚 Learning: 2025-09-03T16:37:11.605Z
Learnt from: QuantumExplorer
PR: dashpay/platform#2756
File: packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/update_state_masternode_list/v0/mod.rs:11-11
Timestamp: 2025-09-03T16:37:11.605Z
Learning: In packages/rs-dpp/Cargo.toml, the abci feature already includes core_rpc_client, and core_rpc_client is defined as ["dep:dashcore-rpc"]. This means rs-drive-abci can access dashcore-rpc types through dpp when using the abci feature.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2024-12-05T09:29:38.918Z
Learnt from: shumkov
PR: dashpay/platform#2375
File: packages/rs-drive-abci/Cargo.toml:61-63
Timestamp: 2024-12-05T09:29:38.918Z
Learning: In the `drive-abci` package, avoid adding unused dependencies like `hashbrown` to `Cargo.toml`. The team relies on CI to detect dependency version issues.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2024-10-10T10:30:25.283Z
Learnt from: lklimek
PR: dashpay/platform#2232
File: packages/rs-sdk/src/mock/sdk.rs:129-130
Timestamp: 2024-10-10T10:30:25.283Z
Learning: In the codebase `packages/rs-sdk/src/mock/sdk.rs`, `tokio::sync::Mutex` is used instead of `std::sync::Mutex` because `std::sync::MutexGuard` is not `Send` and cannot be used in async contexts.

Applied to files:

  • packages/rs-sdk/src/sdk.rs
📚 Learning: 2024-10-29T10:42:00.521Z
Learnt from: lklimek
PR: dashpay/platform#2277
File: packages/rs-dapi-client/Cargo.toml:22-22
Timestamp: 2024-10-29T10:42:00.521Z
Learning: In `packages/rs-dapi-client/Cargo.toml`, `backon` will not work without the `tokio-sleep` feature in our setup, so it's unnecessary to declare `tokio-sleep` as a separate feature in the `[features]` section.

Applied to files:

  • packages/rs-sdk/Cargo.toml
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: lklimek
PR: dashpay/platform#2139
File: packages/rs-sdk/Cargo.toml:0-0
Timestamp: 2024-10-09T00:22:57.778Z
Learning: `bincode` is used in the `mocks` feature of the `rs-sdk`.

Applied to files:

  • packages/rs-sdk/Cargo.toml
🔇 Additional comments (27)
packages/rs-dapi/src/services/streaming_service/bloom.rs (1)

14-17: LGTM: Clean refactor using let-chains.

This simplification reduces nesting and is more idiomatic Rust. The logic remains functionally equivalent while improving readability.

packages/rs-drive-abci/src/query/mod.rs (1)

18-18: LGTM!

The public re-export of PlatformFilterAdapter follows the existing pattern and cleanly exposes the adapter for external use in platform event subscriptions.

packages/rs-dash-event-bus/src/lib.rs (1)

1-1: Documentation update aligns with architectural direction.

The simplified description removing the bi-directional gRPC multiplexer reference aligns with the PR discussion about refactoring to unidirectional gRPC-Web streaming for better web client compatibility.

packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs (1)

206-206: Consistent use of let-chains.

The same clean refactoring pattern applied here with let Some maintains consistency throughout the file.

packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs (2)

33-48: Upstream subscription and channel setup looks solid.

The method correctly establishes the upstream subscription before creating the forwarding channel, and errors from the drive client are properly propagated to the caller.


82-83: Correct gRPC streaming response pattern.

The ReceiverStream wrapper properly bridges the mpsc receiver to tonic's streaming response requirements.

packages/rs-sdk/Cargo.toml (3)

77-77: Consider whether preliminary subscriptions feature should be default.

The subscriptions feature is added to the default feature set for a draft PR with "preliminary support." For an incomplete feature, consider requiring opt-in (default = [] without subscriptions) until the feature is production-ready, to avoid exposing unstable APIs by default.

Is the subscriptions feature stable enough to be enabled by default, or should users explicitly opt-in until DAPI integration (PR #2716) is complete?

Also applies to: 102-102


72-73: Note: AI summary inconsistency.

The AI summary claims mocks feature was removed from defaults, but mocks is still present in the default features list (line 73). This appears to be a pre-existing TODO item not addressed in this PR.


55-55: The signal feature is correctly used and necessary.

The examples in packages/rs-sdk/examples/platform_events.rs use tokio::signal::ctrl_c() on line 128, which requires the "signal" feature. The addition is justified.

packages/rs-drive-abci/tests/strategy_tests/main.rs (1)

201-247: LGTM! Well-structured event bus test.

The test effectively validates the in-process event bus subscription and delivery mechanism. The 1-second timeout is appropriate, and the test clearly demonstrates the subscribe-publish-receive flow.

packages/rs-sdk/src/error.rs (1)

41-43: LGTM! Clear error variant addition.

The new SubscriptionError variant follows the existing error pattern conventions and provides a clear error message for subscription-related failures.

packages/rs-sdk/src/platform.rs (1)

21-22: LGTM! Appropriate feature gating.

The events module is correctly exposed only when the subscriptions feature is enabled, following the pattern established elsewhere in the codebase.

packages/wasm-sdk/src/error.rs (1)

172-177: LGTM! Consistent error translation.

The SubscriptionError mapping to WasmSdkError is consistent with other error translations. Using DapiClientError as the kind is reasonable since subscriptions are DAPI-related functionality.

packages/rs-drive-abci/Cargo.toml (1)

65-82: LGTM! Dependencies align with event bus functionality.

The dependency additions and updates are appropriate for the platform event streaming infrastructure:

  • tokio-stream for async streaming constructs
  • rs-dash-event-bus for in-process event bus
  • sha2 for cryptographic hashing in event metadata
  • metrics-exporter-prometheus update is a minor version bump
packages/rs-sdk/tests/fetch/mod.rs (1)

27-28: LGTM! Test module properly feature-gated.

The platform_events test module is correctly included only when the subscriptions feature is enabled, consistent with the feature gating pattern used throughout the test suite.

packages/rs-dapi/src/main.rs (2)

133-163: LGTM! Cleaner conditional flow.

The merged conditional logic using if let Some(result) = outcome && let Err(e) = result is more concise and readable than the previous nested approach.


114-134: The server_future handling is correct as implemented.

The code follows the proper pattern when using tokio::pin!():

  • The binding doesn't need mut because tokio::pin! internally manages the pinning and mutability
  • Polling with &mut server_future in the select! macro is the standard, correct approach for pinned futures
  • This combination is not an inconsistency but the idiomatic Rust pattern for this scenario

The original concern appears to have been based on a misunderstanding of how tokio::pin!() works with mutability.

packages/rs-dash-event-bus/Cargo.toml (1)

6-6: LGTM! Documentation refinement.

The simplified description accurately reflects the package's purpose while being more concise.

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

171-184: Server‑streaming RPC wiring looks correct

Associated stream type and subscribe_platform_events delegate are aligned with gRPC‑Web constraints (server streaming). LGTM.

Please confirm subscribe_platform_events_impl returns ReceiverStream<Result<PlatformSubscriptionResponse, Status>> and sets appropriate compression/limits for large events.

packages/rs-drive-abci/src/abci/app/consensus.rs (1)

31-46: LGTM: EventBus integration is clean

Field injection and EventBusApplication impl expose the bus without extra cloning; fits finalize_block publishers.

Also applies to: 62-66

packages/rs-dash-event-bus/src/event_bus.rs (1)

277-282: Compile blocker: invalid if let condition chaining

if let Ok(mut subs) = bus.subs.try_write() && subs.remove(&id).is_some() is not valid Rust and won’t compile. Split into nested conditionals.

Apply:

-                    if let Ok(mut subs) = bus.subs.try_write()
-                        && subs.remove(&id).is_some()
-                    {
-                        metrics_unsubscribe_inc();
-                        metrics_active_gauge_set(subs.len());
-                    }
+                    if let Ok(mut subs) = bus.subs.try_write() {
+                        if subs.remove(&id).is_some() {
+                            metrics_unsubscribe_inc();
+                            metrics_active_gauge_set(subs.len());
+                            tracing::debug!("event_bus: removed subscription id={} (no runtime)", id);
+                        }
+                    }

Likely an incorrect or invalid review comment.

packages/rs-drive-abci/src/abci/app/full.rs (1)

31-33: EventBus wiring looks good; confirm Send/Sync and clone behavior.

If EventBus clone is cheap (Arc underneath) and Send/Sync, this is fine. If not, consider wrapping in Arc<EventBus<...>> to avoid accidental heavy clones across threads.

Also applies to: 42-43, 59-63

packages/rs-drive-abci/src/query/service.rs (1)

894-901: Confirm unsubscribe semantics on drop.

We rely on dropping subscription to remove it from the bus when the client disconnects. Please confirm EventBus::add_subscription returns a handle with Drop that unsubscribes; otherwise we need an explicit removal path.

packages/rs-drive-abci/src/abci/handler/finalize_block.rs (2)

107-111: Review comment is based on incorrect assumptions about the event bus implementation.

The notify_sync() method is already designed as non-blocking fire-and-forget. It spawns a background Tokio task that invokes the async notify() method, returning immediately without blocking the ABCI handler path. No changes are required—the current implementation already provides the non-blocking behavior the review suggests pursuing.

Likely an incorrect or invalid review comment.


165-176: SHA-256 of raw tx bytes is the canonical state transition hash used consistently throughout the codebase.

Verification confirms this is correct. The code at lines 165-176 uses Sha256::digest(tx) on raw transaction bytes, which matches the canonical approach used elsewhere:

  1. DAPI broadcast layer (rs-dapi/broadcast_state_transition.rs:49) computes the same hash identically
  2. Query/filtering service (rs-drive-abci/query/service.rs:299-301) matches filters directly against this hash
  3. Client filtering (SDK examples, JS DAPI tests) all use the same hash for StateTransitionResult queries
  4. Protocol definition confirms bytes tx_hash is the standard field for both events and filters

No alternative hash function or helper exists; the raw tx bytes → SHA-256 pattern is uniform across all layers (ABCI, DAPI, query, clients). No divergence between platform components or risk of filter mismatch.

packages/dapi-grpc/protos/platform/v0/platform.proto (2)

9-24: Versioned message structure is clean and consistent.

The nested V0 + oneof version pattern aligns well with the rest of the proto file. The client_subscription_id field enables multiplexing multiple subscriptions over a single RPC stream, which is sound. The design will scale well if V1/V2 variants are introduced later.


26-64: Event and filter messages are well-structured; verify alignment with SDK implementations.

The filter design uses oneof (all, block_committed, state_transition_result) for flexibility, and PlatformEventV0 pairs BlockMetadata consistently across event types. A few items to confirm:

  • Optional tx_hash in StateTransitionResultFilter (line 30): Allows filtering by specific state transitions; good for subscribers interested in particular transactions.
  • BlockMetadata nesting (lines 44–48): Shared across BlockCommitted and StateTransitionFinalized, reducing duplication.
  • Extensibility: The oneof pattern in PlatformFilterV0 and PlatformEventV0 supports future event types (e.g., IdentityCreated, DocumentDeleted) without breaking existing subscriptions.

Verify that:

  1. Downstream Rust (rs-drive-abci) and WASM (rs-sdk) implementations correctly adapt these message definitions.
  2. Field semantics (e.g., block_id_hash, time_ms precision) are documented and match consensus layer definitions.

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

Caution

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

⚠️ Outside diff range comments (1)
packages/rs-dapi/src/server/grpc.rs (1)

115-118: Fix tracing fields: path isn’t recorded; log field names + values

Current calls treat path as a boolean field. Use keyed fields with % to record values; also avoid unwrap_or_default() inside the “is_some()” branch.

-            tracing::trace!(
-                path,
-                "Detected streaming gRPC method, applying streaming timeout"
-            );
+            tracing::trace!(path = %path, "Detected long‑lived gRPC method; using streaming timeout");
-            trace!(
-                path,
-                header_timeout = timeout_from_header.unwrap_or_default().as_secs_f32(),
-                timeout = effective_timeout.as_secs_f32(),
-                "Applying gRPC timeout from header"
-            );
+            trace!(
+                path = %path,
+                header_timeout_secs = { timeout_from_header.unwrap().as_secs_f32() },
+                timeout_secs = effective_timeout.as_secs_f32(),
+                "Applying gRPC timeout from header"
+            );
-            tracing::trace!(
-                path,
-                timeout = effective_timeout.as_secs_f32(),
-                "Applying default gRPC timeout"
-            );
+            tracing::trace!(
+                path = %path,
+                timeout_secs = effective_timeout.as_secs_f32(),
+                "Applying default gRPC timeout"
+            );

Also applies to: 171-176, 178-183

♻️ Duplicate comments (1)
packages/rs-drive-abci/src/query/service.rs (1)

71-74: Resource leak: Vec<JoinHandle<()>> accumulates finished tasks.

The workers Vec accumulates JoinHandles but never drains completed tasks during normal operation. In a long-running service, this causes unbounded memory growth as subscription workers finish.

Apply one of these solutions:

Solution 1 (simplest): Spawn detached tasks

-        let worker = tokio::task::spawn(async move {
+        tokio::task::spawn(async move {
             // ... worker logic ...
         });
-        self.workers.lock().unwrap().push(worker);

Then remove the workers field and its Drop implementation since tasks will be automatically cleaned up.

Solution 2: Add a background reaper
Keep the Vec but spawn a separate task that periodically calls retain to remove finished handles:

// In QueryService::new or similar
tokio::spawn({
    let workers = Arc::clone(&self.workers);
    async move {
        loop {
            tokio::time::sleep(Duration::from_secs(60)).await;
            workers.lock().unwrap().retain(|h| !h.is_finished());
        }
    }
});
🧹 Nitpick comments (18)
.github/scripts/check-grpc-coverage.py (1)

17-17: LGTM! Exclusion is appropriate for the streaming RPC.

The addition correctly excludes SubscribePlatformEvents from the SDK implementation check, which is appropriate for a server-streaming RPC that may follow different implementation patterns than standard request-response queries.

Consider enhancing the comment to explain why streaming RPCs are excluded:

-    'SubscribePlatformEvents',  # Streaming RPC, excluded
+    'SubscribePlatformEvents',  # Streaming RPC - excluded because server-streaming RPCs follow different implementation patterns

Alternatively, if multiple streaming RPCs will be added in the future, consider documenting this exclusion pattern at the module or section level for better maintainability.

packages/rs-drive-abci/src/query/service.rs (2)

294-323: Consider removing the Keepalive early-return in matches().

The filter returns true for Keepalive events (lines 298-300), but Keepalive events are generated locally by the worker task (lines 992-998) and never flow through the event bus subscription. This check will never match any events from the bus.

If this is intentional (e.g., future-proofing for bus-generated keepalives), consider adding a comment explaining the rationale. Otherwise, simplify:

 impl EventBusFilter<PlatformEvent> for PlatformFilterAdapter {
     fn matches(&self, event: &PlatformEvent) -> bool {
         use dapi_grpc::platform::v0::platform_event_v0::Event as Evt;
         use dapi_grpc::platform::v0::platform_filter_v0::Kind;
-        if matches!(event.event, Some(Evt::Keepalive(_))) {
-            return true;
-        }
         match self.inner.kind.as_ref() {
             None => false,

904-916: Consider documenting the keepalive bounds rationale.

The keepalive interval validation enforces 25-300 seconds but lacks explanation for these specific bounds.

Add a brief comment:

+        // Keepalive bounds: minimum 25s to avoid excessive pings,
+        // maximum 300s to ensure reasonable connection liveness detection
         let keepalive_duration = if keepalive == 0 {
             None
         } else if keepalive < 25 || keepalive > 300 {
packages/rs-sdk/examples/platform_events.rs (1)

145-193: Use consistent logging approach.

The worker function mixes info!() (lines 157, 178) and println!() (lines 168, 192) for logging events. For consistency and to leverage the configured tracing subscriber, use info!() throughout or explicitly use println!() for all user-facing output.

Apply this diff for consistency:

                                     PlatformEvent::StateTransitionFinalized(r) => {
                                         if let Some(meta) = r.meta {
-                                            println!(
+                                            info!(
                                                 "{label}: id={sub_id} height={} tx_hash=0x{} block_id_hash=0x{}",
                                                 meta.height,
                                                 hex::encode(r.tx_hash),
                                                 hex::encode(meta.block_id_hash)
                                             );
                                         }
                                     }
packages/rs-dapi/src/server/grpc.rs (1)

104-112: List name/comment are misleading (contains unary long‑poll); rename to LONG_TIMEOUT_METHODS

waitForStateTransitionResult is unary, yet intentionally long‑lived. Rename the list and fix the comment to avoid confusion for future edits.

-    /// Determine the appropriate timeout for a given gRPC method path.
+    /// Determine the appropriate timeout for a given gRPC method path.
     fn timeout_for_method(&self, path: &str) -> Duration {
-        // All known streaming methods in Core service (all use "stream" return type)
-        const STREAMING_METHODS: &[&str] = &[
+        // Methods that require long timeouts (true streaming or long‑poll unary)
+        const LONG_TIMEOUT_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) {
+        if LONG_TIMEOUT_METHODS.contains(&path) {
packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js (1)

1909-1947: Harden stream handler: null‑guard and validate event type

Avoid TypeErrors if callbacks fire after cancel/end, and fail fast on invalid event types.

   var client = grpc.invoke(Platform.SubscribePlatformEvents, {
@@
-    onMessage: function (responseMessage) {
-      listeners.data.forEach(function (handler) {
+    onMessage: function (responseMessage) {
+      if (!listeners) return;
+      listeners.data.forEach(function (handler) {
         handler(responseMessage);
       });
     },
-    onEnd: function (status, statusMessage, trailers) {
-      listeners.status.forEach(function (handler) {
+    onEnd: function (status, statusMessage, trailers) {
+      if (!listeners) return;
+      listeners.status.forEach(function (handler) {
         handler({ code: status, details: statusMessage, metadata: trailers });
       });
       listeners.end.forEach(function (handler) {
         handler({ code: status, details: statusMessage, metadata: trailers });
       });
       listeners = null;
     }
   });
   return {
-    on: function (type, handler) {
-      listeners[type].push(handler);
+    on: function (type, handler) {
+      if (!listeners || !listeners[type]) {
+        throw new Error("Unknown or closed listener type: " + type);
+      }
+      listeners[type].push(handler);
       return this;
     },
     cancel: function () {
       listeners = null;
       client.close();
     }
   };
packages/dapi-grpc/protos/platform/v0/platform.proto (1)

13-16: Keepalive field: clarify units and enforce bounds server‑side

Rename to keepalive_secs (explicit units) or document clearly; ensure Drive/DAPI clamp to [25, 300] and handle 0 (disabled).

-    // Interval in seconds between keepalive events (min 25, max 300, 0 disables
-    // keepalive).
-    uint32 keepalive = 2;
+    // Keepalive interval in seconds (min 25, max 300; 0 disables keepalive).
+    uint32 keepalive_secs = 2;

Please confirm server validation is implemented alongside this proto.

packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (4)

31-39: Keepalive field needs unit clarity; prefer Duration or explicit suffix.

A bare number for keepalive is ambiguous for web clients. Recommend:

  • Use google.protobuf.Duration, or
  • Rename to keepaliveMs (or KeepAliveSeconds) and document min/max.

Example proto tweak:

-message PlatformSubscriptionRequestV0 {
-  PlatformFilterV0 filter = 1;
-  uint32 keepalive = 2; // ambiguous units
-}
+import "google/protobuf/duration.proto";
+message PlatformSubscriptionRequestV0 {
+  PlatformFilterV0 filter = 1;
+  google.protobuf.Duration keepalive = 2; // precise, cross-language friendly
+}

85-102: Subscription ID semantics: rename or add a client correlation id.

Response exposes clientSubscriptionId, but the request has no matching field. If the server assigns the id, suggest:

  • Rename to subscriptionId, or
  • Keep as is and add optional clientCorrelationId to the request so the server echoes it back.

Proto sketch:

 message PlatformSubscriptionRequestV0 {
   PlatformFilterV0 filter = 1;
-  uint32 keepalive = 2;
+  uint32 keepalive = 2;
+  string client_correlation_id = 3; // optional, echoed back
 }
 
 message PlatformSubscriptionResponseV0 {
-  string client_subscription_id = 1;
+  string subscription_id = 1; // server-assigned
   PlatformEventV0 event = 2;
 }

141-166: Oneof of booleans is awkward; align filter/event names.

  • Using bools inside a oneof (all, blockCommitted) yields confusing AsObject defaults (false even when unset) and clunky client UX. Prefer:
    • oneof with message wrappers (google.protobuf.Empty) or
    • an explicit enum kind plus an optional message payload per kind.
  • Name mismatch: filter uses stateTransitionResult but the event is StateTransitionFinalized. Pick one term platform‑wide (finalized is clearer for events).

Proto sketch:

message PlatformFilterV0 {
  oneof kind {
    google.protobuf.Empty all = 1;
    google.protobuf.Empty block_committed = 2;
    StateTransitionResultFilter state_transition_finalized = 3; // rename for consistency
  }
}

Also applies to: 168-181


183-208: Event payloads: minor schema polish for web streaming.

  • Consider including a simple outcome/status on StateTransitionFinalized (accepted/rejected) to save a follow‑up call.
  • BlockMetadata.timeMs is string (int64) which is fine; if you want stronger typing, google.protobuf.Timestamp is an option.
  • Keepalive is good; ensure its cadence honors the requested keepalive and document server min/max caps.

If outcome is already decided elsewhere, point to the API consumers that should be used to resolve it.

Also applies to: 217-237, 247-264, 273-292, 301-323

packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (2)

7960-7995: Avoid bools in oneof discriminators; use empty messages to make the variant explicit.

PlatformFilterV0.kind uses bool all = 1; bool block_committed = 2; in a oneof. Setting all=false still selects the ALL variant (presence), while toObject() shows false, which is misleading and error‑prone.

Recommend replacing bools with empty messages so the discriminator is unambiguous:

 message PlatformFilterV0 {
   oneof kind {
-    bool all = 1;
-    bool block_committed = 2;
+    message All {}
+    message BlockCommittedFilter {}
+    All all = 1;
+    BlockCommittedFilter block_committed = 2;
     StateTransitionResultFilter state_transition_result = 3;
   }
 }

Also document that clients must not rely on toObject() booleans for presence; use getKindCase()/has*(). Regenerate JS after proto change.

Also applies to: 8089-8113, 8120-8170


7591-7602: Consider omitting client_subscription_id on every event to reduce payload.

PlatformSubscriptionResponseV0 includes client_subscription_id with each streamed message. If streams are one‑subscription‑per‑stream (common for server streaming), the ID is redundant. Options:

  • Send the ID only in the first “ack” message, omit thereafter.
  • Make the field optional behind a flag if future multiplexing is planned.

Small bandwidth win; behavior unchanged for clients that don’t need per‑event IDs.

If multiplexing multiple subscriptions per stream is planned, please confirm so we don’t remove a necessary field.

Also applies to: 7667-7684

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m (1)

597-614: Bound clientSubscriptionId size and format.

Consider documenting/validating a max length and allowed charset for clientSubscriptionId to prevent oversized frames or ambiguous IDs across transports.

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (4)

527-540: Subscription ID placement/naming

clientSubscriptionId is only on responses; request has no matching field. If the server assigns it, rename to subscriptionId. If clients provide it, add it to request v0 to support correlation.

Proto options:

 message PlatformSubscriptionResponseV0 {
-  string client_subscription_id = 1;
+  string subscription_id = 1;
   PlatformEventV0 event = 2;
 }

 // OR, if client-supplied correlation is intended:
 message PlatformSubscriptionRequestV0 {
   PlatformFilterV0 filter = 1;
   uint32 keepalive = 2;
+  string client_subscription_id = 3; // echoed back in responses
 }

487-498: Keepalive bounds: clarify server behavior and default

Docs say “min 25, max 300, 0 disables”. Specify server behavior when out-of-range and the default when 0 (e.g., clamp to [25,300] or reject with INVALID_ARGUMENT; default to 60s if 0).

Proto comment tweak:

// Interval in seconds between keepalive events.
// Valid: 25..300. 0 = use server default (e.g., 60s).
// Out-of-range values are rejected with INVALID_ARGUMENT.
uint32 keepalive = 2;

543-559: txHash vs stateTransitionHash naming

New types use txHash while existing WaitForStateTransitionResult* uses stateTransitionHash. Prefer one term platform-wide (stateTransitionHash is clearer).

Proto sketch (if adopting stateTransitionHash):

-message StateTransitionResultFilter { bytes tx_hash = 1; }
+message StateTransitionResultFilter { bytes state_transition_hash = 1; }

-message StateTransitionResult { BlockMetadata meta = 1; bytes tx_hash = 2; }
+message StateTransitionResult { BlockMetadata meta = 1; bytes state_transition_hash = 2; }

Also applies to: 665-678


576-585: Oneof usage with BOOL fields: add note to avoid ObjC confusion

Because all, block_committed are BOOL in a oneof, toggling them can silently replace the active case. Add a brief proto comment advising clients to use the 'kind' oneof semantics and the generated ClearKindOneOfCase() when switching.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d7ca2e and 068dcd7.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • packages/dashmate/templates/platform/gateway/envoy.yaml.dot is excluded by !**/*.dot
📒 Files selected for processing (22)
  • .github/scripts/check-grpc-coverage.py (1 hunks)
  • packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java (8 hunks)
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h (3 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m (1 hunks)
  • packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py (4 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (1 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts (3 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js (2 hunks)
  • packages/dapi-grpc/protos/platform/v0/platform.proto (2 hunks)
  • packages/rs-dapi/src/server/grpc.rs (1 hunks)
  • packages/rs-dash-event-bus/Cargo.toml (1 hunks)
  • packages/rs-drive-abci/Cargo.toml (2 hunks)
  • packages/rs-drive-abci/src/query/service.rs (5 hunks)
  • packages/rs-sdk/Cargo.toml (4 hunks)
  • packages/rs-sdk/examples/platform_events.rs (1 hunks)
  • packages/rs-sdk/src/platform.rs (1 hunks)
  • packages/rs-sdk/src/platform/events.rs (1 hunks)
  • packages/rs-sdk/tests/fetch/platform_events.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/rs-drive-abci/Cargo.toml
  • packages/rs-dash-event-bus/Cargo.toml
🧰 Additional context used
📓 Path-based instructions (5)
**/*.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/grpc.rs
  • packages/rs-sdk/src/platform/events.rs
  • packages/rs-sdk/src/platform.rs
  • packages/rs-sdk/tests/fetch/platform_events.rs
  • packages/rs-drive-abci/src/query/service.rs
  • packages/rs-sdk/examples/platform_events.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/grpc.rs
  • packages/rs-sdk/src/platform/events.rs
  • packages/rs-sdk/src/platform.rs
  • packages/rs-sdk/tests/fetch/platform_events.rs
  • packages/rs-drive-abci/src/query/service.rs
  • packages/rs-sdk/examples/platform_events.rs
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/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
packages/**/tests/**

📄 CodeRabbit inference engine (AGENTS.md)

Place unit and integration tests alongside each package in packages//tests

Files:

  • packages/rs-sdk/tests/fetch/platform_events.rs
packages/**/tests/**/*.{js,ts,jsx,tsx,rs}

📄 CodeRabbit inference engine (AGENTS.md)

packages/**/tests/**/*.{js,ts,jsx,tsx,rs}: Name tests descriptively, starting with “should …”
Unit/integration tests must not perform network calls; mock dependencies instead

Files:

  • packages/rs-sdk/tests/fetch/platform_events.rs
🧠 Learnings (2)
📚 Learning: 2024-10-29T10:42:00.521Z
Learnt from: lklimek
PR: dashpay/platform#2277
File: packages/rs-dapi-client/Cargo.toml:22-22
Timestamp: 2024-10-29T10:42:00.521Z
Learning: In `packages/rs-dapi-client/Cargo.toml`, `backon` will not work without the `tokio-sleep` feature in our setup, so it's unnecessary to declare `tokio-sleep` as a separate feature in the `[features]` section.

Applied to files:

  • packages/rs-sdk/Cargo.toml
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: lklimek
PR: dashpay/platform#2139
File: packages/rs-sdk/Cargo.toml:0-0
Timestamp: 2024-10-09T00:22:57.778Z
Learning: `bincode` is used in the `mocks` feature of the `rs-sdk`.

Applied to files:

  • packages/rs-sdk/Cargo.toml
🪛 Ruff (0.14.2)
packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py

549-549: Unused method argument: request

(ARG002)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
🔇 Additional comments (45)
packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h (1)

108-109: LGTM: Forward declarations properly added.

The forward declarations for PlatformSubscriptionRequest and PlatformSubscriptionResponse follow the established pattern and are correctly positioned in alphabetical order.

packages/rs-drive-abci/src/query/service.rs (5)

76-83: LGTM!

The Drop implementation correctly aborts all worker tasks on service shutdown.


94-103: LGTM!

Constructor correctly initializes the new event_bus and workers fields.


899-902: Good: filter.kind validation prevents silent no-op subscriptions.

This validation correctly addresses the past review concern by ensuring clients get an explicit error rather than silently receiving no events.


918-951: LGTM!

Subscription setup correctly generates a unique ID, establishes the event bus subscription, creates a buffered channel, and sends a handshake response before streaming events.


953-1023: LGTM: Worker task logic is correct.

The worker properly:

  • Receives events from the subscription handle with optional keepalive timeout
  • Forwards events wrapped in PlatformSubscriptionResponse
  • Generates keepalive events on timeout
  • Detects client disconnection and exits cleanly

Note: The handle storage at line 1024 contributes to the resource leak flagged separately.

packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java (4)

2240-2245: bindService uses asyncServerStreamingCall appropriately.

Registration and handler binding look correct.


3490-3490: Method id added without collision.

Increment to 47 is consistent with prior ids.


3697-3700: Switch-case wiring added for the new RPC.

Routing to subscribePlatformEvents is correct.


3809-3810: ServiceDescriptor includes the new method.

Descriptor update is correct.

packages/rs-sdk/src/platform.rs (1)

21-22: LGTM!

The feature-gated module declaration follows the existing pattern and properly exposes the events module when the subscriptions feature is enabled.

packages/rs-sdk/tests/fetch/platform_events.rs (4)

13-16: LGTM!

The test configuration with multi-threaded runtime and appropriate feature gating aligns with the existing test patterns in the codebase.


18-32: LGTM!

The gRPC client setup is correct, with appropriate timeouts and error handling for the test environment.


34-47: LGTM!

The subscription request is properly constructed with appropriate filter and keepalive settings, and error handling is in place.


75-81: LGTM!

The stream verification correctly validates that the subscription remains open without receiving immediate events, using an appropriate timeout.

packages/rs-sdk/Cargo.toml (3)

55-55: LGTM!

Adding the signal feature to the tokio dev-dependency is appropriate for supporting Ctrl+C handling in the platform_events example.


77-77: Consider whether preliminary feature should be enabled by default.

The subscriptions feature is added to the default feature set. Since this PR provides "preliminary support" (per PR objectives) and is still a draft, verify whether enabling this by default is intentional. For preliminary/experimental features, it's common to require explicit opt-in until the API stabilizes.


102-103: LGTM!

The empty subscriptions feature declaration is correct for a feature flag that gates code without pulling additional dependencies.

packages/rs-sdk/src/platform/events.rs (3)

13-13: LGTM!

The EventSubscriptionId type alias simplifies the API. Note that the past review comment about Default derive is no longer applicable as the implementation changed from a counter-based struct to a String type alias.


65-71: LGTM!

The Subscription trait provides a clean abstraction for extracting subscription IDs from responses, with clear documentation.


73-80: LGTM!

The Subscription implementation correctly extracts the subscription ID from V0 responses and handles other versions gracefully by returning an empty string.

packages/rs-sdk/examples/platform_events.rs (4)

1-8: LGTM!

The feature-gated main function provides a clear user experience whether the subscriptions feature is enabled or not.


31-67: LGTM!

The Config struct is well-designed with appropriate types, and the loading logic correctly handles both .env file and environment variables. Using Zeroizing for the password is a good security practice.


89-143: LGTM!

The main function correctly sets up multiple concurrent subscriptions with proper error handling and Ctrl+C signal handling. The use of abort handles for forceful shutdown is appropriate for an example.


195-219: LGTM!

The SDK setup function correctly handles platform and core configuration, with appropriate conditional CA certificate loading for non-WASM targets.

packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js (1)

436-443: Service descriptor for SubscribePlatformEvents — LGTM

Server‑streaming shape matches proto; no issues.

packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts (1)

430-438: Typings align with server‑streaming API — LGTM

Platform.SubscribePlatformEvents descriptor and client subscribePlatformEvents(...) returning ResponseStream look correct.

Also applies to: 488-489, 946-947

packages/dapi-grpc/protos/platform/v0/platform.proto (1)

170-173: Naming inconsistency confirmed: SubscribePlatformEvents is the only PascalCase RPC in platform.proto

Verification shows all other RPCs (50+) use lowerCamel throughout the service (e.g., waitForStateTransitionResult, getConsensusParams). Core.proto follows the same lowerCamel pattern (subscribeToBlockHeadersWithChainLocks, etc.). Changing this would require updates across generated clients in Python, Java, Node.js, Objective-C, and Rust.

packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py (3)

252-256: LGTM: Client stub correctly implements server streaming.

The client stub properly uses channel.unary_stream for the SubscribePlatformEvents endpoint, enabling server streaming of platform events to clients.


794-798: LGTM: Handler registration correctly configured for server streaming.

The handler registration properly uses grpc.unary_stream_rpc_method_handler with correct serialization/deserialization for the SubscribePlatformEvents RPC.


1608-1623: LGTM: Experimental API correctly implements server streaming.

The experimental static method properly uses grpc.experimental.unary_stream with appropriate request/response serialization and standard gRPC options.

packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (1)

9-24: Subscription API properly generated and wired.

Verified: The SubscribePlatformEvents server-streaming RPC is correctly generated in both platform_pb_service.d.ts and platform_pb_service.js. The method signature matches the d.ts declarations, and all required message classes (PlatformSubscriptionRequest, PlatformSubscriptionResponse, PlatformEventV0) with their nested types and oneof patterns (VersionCase, EventCase) are present in the runtime. Type definitions align with the grpc-web implementation.

packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (1)

463-9203: LGTM - Generated protobuf code appears correct.

This file is auto-generated by JsPbCodeGenerator from the platform.proto definitions. The generated code follows standard protobuf JavaScript patterns consistently throughout, including proper constructors, serialization/deserialization methods, getters/setters, and oneof field handling.

Any modifications to these message structures should be made in the source .proto files and regenerated, not edited manually here.

packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (1)

7235-7382: Clarify keepalive semantics; document that server enforces 25–300 second range.

PlatformSubscriptionRequestV0.keepalive (uint32, seconds) already has server-side validation clamping the interval to [25, 300], which is enforced by the DAPI query service. However, the naming creates confusion: the field is named keepalive and there is also a separate Keepalive event type.

Recommendations:

  1. Document in generated code: Add JSDoc/comment in the generated JS/TS bindings clarifying that the field is in seconds and the valid range is 25–300, with 0 disabling keepalive.
  2. Consider renaming for clarity (optional, for next proto revision): Rename the field to keepalive_interval_secs to avoid overlap with the Keepalive event type and make units explicit.
  3. Verify downstream: Ensure client libraries and examples correctly interpret the uint32 as seconds, not milliseconds or opaque units.

No changes required now if the proto comment and server validation are sufficient. Recommend adding explicit unit documentation when updating client SDKs.

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m (10)

320-337: New message declarations wired correctly — LGTM.

The added GPBObjCClassDeclaration entries align with the new subscription/events schema. No issues spotted.


421-455: Versioned request envelope is future‑proof — LGTM.

Oneof "version" with v0 matches the established pattern and keeps wire compatibility.


533-569: Versioned response envelope — LGTM.

Oneof "version" mirrors request; descriptor setup is consistent.


639-660: Constrain txHash length for correctness.

txHash should be a fixed length (likely 32 bytes). Document/enforce this in server‑side validation and proto comments to prevent ambiguous matching.


776-827: Event envelope oneof is consistent — LGTM.

blockCommitted/stateTransitionFinalized/keepalive are correctly grouped under "event".


867-874: Document timeMs epoch and units.

Confirm this is Unix time in milliseconds; add a comment in the proto for cross‑language consistency (JS 53‑bit note, Rust/Go 64‑bit ok).


933-940: txCount semantics.

If zero is meaningful (e.g., empty block), keep optional; otherwise consider non‑optional with explicit default in docs to avoid presence ambiguity.


1029-1047: Keepalive message — LGTM.

Empty marker message is appropriate for heartbeat events.


700-727: Confirmed: Avoid booleans inside oneof "kind" in PlatformFilterV0 proto definition.

The proto definition at packages/dapi-grpc/protos/platform/v0/platform.proto (lines 35–43) contains two boolean fields (all and block_committed) inside oneof kind. Setting a bool to false still "selects" that oneof branch, creating semantically awkward behavior and potentially blocking other filters.

Recommended refactor: Replace boolean fields with empty marker messages (e.g., message All {} and message BlockCommitted {}) or use an enum discriminator.


471-501: Proto documentation for keepalive is already comprehensive.

The proto file at packages/dapi-grpc/protos/platform/v0/platform.proto lines 13-15 already documents: "Interval in seconds between keepalive events (min 25, max 300, 0 disables keepalive)." This explicitly specifies units (seconds), bounds (25–300), and behavior (0 disables).

Server-side validation in rs-drive-abci enforces these constraints, rejecting out-of-range values with the error message "keepalive interval must be between 25 and 300 seconds." Rust SDK and Objective-C client implementations both treat keepalive as a uint32 field, consistent with the proto definition. No client divergence is evident.

The only enhancement that could be made is to explicitly document the default value (0) in the proto comment if not already implied.

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (1)

231-246: Forward declarations look consistent with new proto surface

Types align with later interfaces. No issues.

@lklimek
Copy link
Contributor Author

lklimek commented Nov 3, 2025

@coderabbitai review

@lklimek lklimek marked this pull request as ready for review November 3, 2025 11:35
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Nov 3, 2025

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

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

Caution

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

⚠️ Outside diff range comments (2)
packages/dashmate/configs/defaults/getBaseConfigFactory.js (1)

242-258: Remove waitForStResultTimeout from defaults; it's handled by migration logic and shouldn't coexist with timeouts.waitForStateTransitionResult in new configs.

The waitForStResultTimeout field at line 258 is the legacy field being migrated away. The migration logic (getConfigFileMigrationsFactory.js lines 1378-1382) reads this field from old configs and copies its value to the new timeouts.waitForStateTransitionResult location, then deletes the old field (lines 1430-1435).

Including waitForStResultTimeout in the base defaults creates unnecessary duplication in new configurations. The field should only exist:

  • In old/migrating configs (handled by the migration)
  • Not in the defaults used for fresh installations

Move waitForStResultTimeout: 120000 from the base defaults into the migration logic where it already exists as a fallback value (line 1389), or document it explicitly as deprecated with a timeline for removal.

packages/dashmate/configs/getConfigFileMigrationsFactory.js (1)

1380-1425: Remove legacy waitForStResultTimeout after building timeouts

After we copy the old value into the new rsDapi.timeouts, the legacy rsDapi.waitForStResultTimeout field remains on the config. The updated JSON schema now forbids extra properties on rsDapi, so existing nodes will fail validation post-migration unless we drop that key. Please delete it once the new object is populated.

           options.platform.dapi.rsDapi.timeouts = {
             waitForStateTransitionResult,
             subscribePlatformEvents,
             coreStreams,
           };
+
+          delete options.platform.dapi.rsDapi.waitForStResultTimeout;
♻️ Duplicate comments (7)
packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java (1)

2658-2670: Same Javadoc typo; fix via proto comments and regenerate.

Repeat of “subscribint” typo; apply the same proto‑doc fix as above.

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m (1)

1115-1121: Remove unary convenience for a server‑streaming RPC.

Method returns GRPCUnaryProtoCall for a streaming RPC; this is misleading and can cause misuse. Prefer the eventHandler variant that already returns GRPCProtoCall.

-/**
- * Server-streaming subscription for platform events.
- * 
- * Allows subscribing to various Platform events.
- * 
- * Once connected, it sends handshake response with empty event.
- */
-- (GRPCUnaryProtoCall *)subscribePlatformEventsWithMessage:(PlatformSubscriptionRequest *)message responseHandler:(id<GRPCProtoResponseHandler>)handler callOptions:(GRPCCallOptions *_Nullable)callOptions {
-  return [self RPCToMethod:@"subscribePlatformEvents"
-                   message:message
-           responseHandler:handler
-               callOptions:callOptions
-             responseClass:[PlatformSubscriptionResponse class]];
-}
+/* Server‑streaming RPC: use -subscribePlatformEventsWithRequest:eventHandler: or RPCTosubscribePlatformEventsWithRequest:... */
packages/rs-drive-abci/src/query/service.rs (1)

70-74: Do not retain JoinHandles; this leaks over time.

JoinHandles are pushed into a Vec and never removed; completed tasks accumulate until process exit. Either:

  • Don’t store the handle at all (spawn and drop), or
  • Use a TaskTracker/reaper to drain finished tasks.

Minimal fix: remove the workers field and the push.

@@ pub struct QueryService {
-    event_bus: EventBus<PlatformEvent, PlatformFilterAdapter>,
-    /// background worker tasks
-    workers: Mutex<Vec<tokio::task::JoinHandle<()>>>,
+    event_bus: EventBus<PlatformEvent, PlatformFilterAdapter>,
 }
@@
-impl Drop for QueryService {
-    fn drop(&mut self) {
-        let mut workers = self.workers.lock().unwrap();
-        for handle in workers.drain(..) {
-            handle.abort();
-        }
-    }
-}
+// No Drop impl needed when not retaining join handles.
@@ pub fn new(
-            event_bus,
-            workers: Mutex::new(Vec::new()),
+            event_bus,
         }
@@ spawn worker ...
-        let worker = tokio::task::spawn(async move {
+        tokio::task::spawn(async move {
@@
-        });
-        self.workers.lock().unwrap().push(worker);
+        });

If you prefer to keep tracking, replace Vec<JoinHandle<()>> with a tokio_util::task::TaskTracker and call tracker.close() in Drop.

Also applies to: 76-83, 92-103, 950-1024

packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (1)

117-124: Align naming: use stateTransitionHash consistently (not txHash).

Existing API (WaitForStateTransitionResultRequestV0) uses stateTransitionHash. New types introduce txHash; keep one term.

-message StateTransitionResultFilter {
-  bytes tx_hash = 1;
-}
+message StateTransitionResultFilter {
+  bytes state_transition_hash = 1;
+}

-message StateTransitionFinalized {
-  PlatformEventV0.BlockMetadata meta = 1;
-  bytes tx_hash = 2;
-}
+message StateTransitionFinalized {
+  PlatformEventV0.BlockMetadata meta = 1;
+  bytes state_transition_hash = 2;
+}

Reduces client confusion and code churn.

#!/bin/bash
# Verify inconsistent hash field names across proto/clients
rg -n --hidden -S -g '!**/node_modules/**' -C2 \
  -e 'stateTransitionHash' \
  -e 'state_transition_hash' \
  -e '\btxHash\b' \
  -e 'tx_hash' \
  packages

Also applies to: 279-283

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (2)

664-679: Unify naming: StateTransitionResult vs StateTransitionFinalized; txHash vs stateTransitionHash

Event type uses PlatformEventV0_StateTransitionFinalized with txHash, while filters and WaitForStateTransitionResult* use “StateTransitionResult” and stateTransitionHash. Please standardize the proto before locking the API and regenerate Objective‑C:

Proto-level sketch:

 message PlatformEventV0 {
   oneof event {
     BlockCommitted block_committed = 1;
-    StateTransitionFinalized state_transition_finalized = 2;
+    StateTransitionResult state_transition_result = 2;
     Keepalive keepalive = 3;
   }
 }

-message StateTransitionFinalized {
+message StateTransitionResult {
   BlockMetadata meta = 1;
-  bytes tx_hash = 2;
+  bytes state_transition_hash = 2;
}

And align the filter field:

 message StateTransitionResultFilter {
-  bytes tx_hash = 1;
+  bytes state_transition_hash = 1;
}

587-589: Fix truncated doc for StateTransitionResult filter selector

Comment ends mid‑sentence. Replace with a complete note and state oneof semantics.

Suggested wording for the proto (then regenerate):

// Subscribe to StateTransitionResult events (optionally filtered by
// StateTransitionResultFilter). Setting this clears other 'kind' variants.
StateTransitionResultFilter state_transition_result = 3;
packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (1)

8504-8527: Generated file: fix parseInt() at source and regenerate.

The previous review identified that parseInt(f, 10) !== 0 on lines 8507 and 8514 is semantically incorrect for uint64 fields (which are handled as strings elsewhere, see lines 8466-8467, 8426-8427, 8534-8535, 8552-8553). This issue remains unaddressed.

Since this is a generated protobuf file, do not manually edit it. Instead:

  1. Fix the generator configuration or proto definitions to use string comparison: if (f !== "0")
  2. Regenerate this file using the corrected tooling
🧹 Nitpick comments (10)
packages/dashmate/docs/services/gateway.md (1)

109-111: Fix bullet indentation to satisfy markdownlint

The leading space before each dash makes the list fail MD005/MD007 and breaks our doc lint. Please align these bullets with the rest of the list so the docs and CI stay clean.

- - Core streaming endpoints: derived from `platform.dapi.rsDapi.timeouts.coreStreams` (default 600 000 ms)
- - waitForStateTransitionResult endpoint: derived from `platform.dapi.rsDapi.timeouts.waitForStateTransitionResult` (default 120 000 ms)
- - subscribePlatformEvents endpoint: derived from `platform.dapi.rsDapi.timeouts.subscribePlatformEvents` (default 600 000 ms)
+- Core streaming endpoints: derived from `platform.dapi.rsDapi.timeouts.coreStreams` (default 600 000 ms)
+- waitForStateTransitionResult endpoint: derived from `platform.dapi.rsDapi.timeouts.waitForStateTransitionResult` (default 120 000 ms)
+- subscribePlatformEvents endpoint: derived from `platform.dapi.rsDapi.timeouts.subscribePlatformEvents` (default 600 000 ms)
packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java (1)

3031-3043: Improve blocking‑stub docs; mention Iterator return.

Doc is generic; add that the blocking stub returns an Iterator. Also fix the typo.

Update proto comments so generated Javadoc reflects it:

- // Server-streaming subscription for Platform events.
+ // Server‑streaming subscription for Platform events.
 // Allows subscribing to various Platform events.
+ // Client notes: blocking stub returns an Iterator over PlatformSubscriptionResponse;
+ // async stub emits responses via StreamObserver.
.github/scripts/check-grpc-coverage.py (1)

17-18: Exclude streaming RPCs automatically (reduce manual list churn).

Adding subscribePlatformEvents to EXCLUDED_QUERIES is fine. Consider detecting server-streaming from the proto and auto-excluding, so future streaming RPCs don’t require list updates.

Here’s a minimal adjustment to extract and skip server-streaming RPCs:

-    # Extract all rpc methods
-    rpc_pattern = r'rpc\s+(\w+)\s*\('
-    for match in re.finditer(rpc_pattern, service_content):
-        query_name = match.group(1)
-        if query_name not in EXCLUDED_QUERIES:
-            queries.append(query_name)
+    # Extract all rpc methods and detect server-streaming
+    rpc_pattern = r'rpc\s+(\w+)\s*\([^\)]*\)\s*returns\s*\(\s*(stream\s+)?([A-Za-z_]\w*)\s*\)'
+    for match in re.finditer(rpc_pattern, service_content):
+        query_name = match.group(1)
+        is_streaming = match.group(2) is not None
+        if is_streaming:
+            # auto-exclude server-streaming RPCs from coverage
+            continue
+        if query_name not in EXCLUDED_QUERIES:
+            queries.append(query_name)
packages/rs-sdk/tests/fetch/config.rs (1)

48-52: Gate the allow(unused) with the feature flag (match core_host).

Keep warnings active under network-testing and silence only when unused in offline runs.

-    #[allow(unused)]
+    #[cfg_attr(not(feature = "network-testing"), allow(unused))]
     pub platform_ca_cert_path: Option<PathBuf>,
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (3)

31-39: Clarify keepalive units and intent.

Name implies “interval” but units aren’t clear. Prefer keepaliveMs (uint32) and document behavior (0 disables, min clamp).

-message PlatformSubscriptionRequestV0 {
-  PlatformFilterV0 filter = 1;
-  uint32 keepalive = 2;
-}
+message PlatformSubscriptionRequestV0 {
+  PlatformFilterV0 filter = 1;
+  uint32 keepalive_ms = 2; // interval in milliseconds; 0 disables
+}

This prevents client/server mismatches, especially for gRPC‑Web.


141-181: Prefer oneof with empty messages over boolean flags for filter kind.

Boolean members in a oneof serialize as false when unset, which is ambiguous in JS/TS. Use empty message markers for clarity.

-message PlatformFilterV0 {
-  oneof kind {
-    bool all = 1;
-    bool block_committed = 2;
-    StateTransitionResultFilter state_transition_result = 3;
-  }
-}
+message PlatformFilterV0 {
+  message All {}
+  message BlockCommitted {}
+  oneof kind {
+    All all = 1;
+    BlockCommitted block_committed = 2;
+    StateTransitionResultFilter state_transition_result = 3;
+  }
+}

Improves client ergonomics and reduces accidental misuse.


183-208: Add a cursor/sequence to support ordering and resumption.

For server‑streaming over gRPC‑Web, include a monotonic cursor in each message (response‑level is fine) so clients can resume after disconnects and detect gaps.

 message PlatformSubscriptionResponseV0 {
-  string subscription_id = 1;
-  PlatformEventV0 event = 2;
+  string subscription_id = 1;
+  PlatformEventV0 event = 2;
+  uint64 cursor = 3; // increases by 1 per event on this stream
 }

Optionally add eventIndexInBlock to BlockCommitted/StateTransitionFinalized.

Also applies to: 94-104

packages/rs-sdk/tests/fetch/platform_events.rs (1)

14-17: Drop the second setup_logs() call.

The double invocation doesn’t break anything, but it’s redundant. Please remove the extra call to keep the test lean.

Apply this diff:

-    setup_logs();
-
     setup_logs();
packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (2)

549-553: Remove “placeholder” phrasing; clarify filter semantics

Public headers shouldn’t say “Initial placeholder… to be refined”. Tighten the proto docs and regenerate.

Proposed proto comment:

// Filter for StateTransitionResult events.
// When state_transition_hash is set, only events for that hash are delivered.
message StateTransitionResultFilter { ... }

564-575: Prefer Empty over bool in oneof to avoid ambiguous presence

Using bool inside oneof (all, block_committed) is easy to mis-set to false yet still occupy the variant. Use google.protobuf.Empty for presence-only selectors.

Proto sketch:

+import "google/protobuf/empty.proto";

 message PlatformFilterV0 {
   oneof kind {
-    bool all = 1;
-    bool block_committed = 2;
+    google.protobuf.Empty all = 1;
+    google.protobuf.Empty block_committed = 2;
     StateTransitionResultFilter state_transition_result = 3;
   }
 }

Also applies to: 581-586

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 068dcd7 and 51fb24e.

⛔ Files ignored due to path filters (2)
  • Cargo.lock is excluded by !**/*.lock
  • packages/dashmate/templates/platform/gateway/envoy.yaml.dot is excluded by !**/*.dot
📒 Files selected for processing (35)
  • .github/scripts/check-grpc-coverage.py (1 hunks)
  • packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java (8 hunks)
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h (3 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m (1 hunks)
  • packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py (4 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (1 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts (3 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js (2 hunks)
  • packages/dapi-grpc/protos/platform/v0/platform.proto (2 hunks)
  • packages/dapi-grpc/src/lib.rs (1 hunks)
  • packages/dashmate/configs/defaults/getBaseConfigFactory.js (1 hunks)
  • packages/dashmate/configs/getConfigFileMigrationsFactory.js (5 hunks)
  • packages/dashmate/docker-compose.yml (1 hunks)
  • packages/dashmate/docs/config/gateway.md (1 hunks)
  • packages/dashmate/docs/services/gateway.md (1 hunks)
  • packages/dashmate/src/config/configJsonSchema.js (3 hunks)
  • packages/rs-dapi/README.md (1 hunks)
  • packages/rs-dapi/src/config/mod.rs (2 hunks)
  • packages/rs-dapi/src/config/tests.rs (4 hunks)
  • packages/rs-dapi/src/services/platform_service/mod.rs (2 hunks)
  • packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs (1 hunks)
  • packages/rs-dapi/src/services/streaming_service/block_header_stream.rs (3 hunks)
  • packages/rs-dapi/src/services/streaming_service/masternode_list_stream.rs (2 hunks)
  • packages/rs-dapi/src/services/streaming_service/mod.rs (2 hunks)
  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs (1 hunks)
  • packages/rs-drive-abci/src/query/service.rs (5 hunks)
  • packages/rs-drive-abci/tests/strategy_tests/main.rs (1 hunks)
  • packages/rs-sdk/examples/platform_events.rs (1 hunks)
  • packages/rs-sdk/src/sdk.rs (6 hunks)
  • packages/rs-sdk/tests/fetch/config.rs (1 hunks)
  • packages/rs-sdk/tests/fetch/platform_events.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (4)
  • packages/rs-drive-abci/tests/strategy_tests/main.rs
  • packages/rs-dapi/src/services/platform_service/mod.rs
  • packages/rs-sdk/src/sdk.rs
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h
🧰 Additional context used
📓 Path-based instructions (5)
**/*.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/block_header_stream.rs
  • packages/rs-dapi/src/config/mod.rs
  • packages/rs-dapi/src/services/streaming_service/masternode_list_stream.rs
  • packages/rs-dapi/src/services/streaming_service/mod.rs
  • packages/dapi-grpc/src/lib.rs
  • packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs
  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
  • packages/rs-sdk/tests/fetch/platform_events.rs
  • packages/rs-dapi/src/config/tests.rs
  • packages/rs-sdk/examples/platform_events.rs
  • packages/rs-drive-abci/src/query/service.rs
  • packages/rs-sdk/tests/fetch/config.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/block_header_stream.rs
  • packages/rs-dapi/src/config/mod.rs
  • packages/rs-dapi/src/services/streaming_service/masternode_list_stream.rs
  • packages/rs-dapi/src/services/streaming_service/mod.rs
  • packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs
  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
  • packages/rs-sdk/tests/fetch/platform_events.rs
  • packages/rs-dapi/src/config/tests.rs
  • packages/rs-sdk/examples/platform_events.rs
  • packages/rs-drive-abci/src/query/service.rs
  • packages/rs-sdk/tests/fetch/config.rs
packages/**/tests/**

📄 CodeRabbit inference engine (AGENTS.md)

Place unit and integration tests alongside each package in packages//tests

Files:

  • packages/rs-sdk/tests/fetch/platform_events.rs
  • packages/rs-sdk/tests/fetch/config.rs
packages/**/tests/**/*.{js,ts,jsx,tsx,rs}

📄 CodeRabbit inference engine (AGENTS.md)

packages/**/tests/**/*.{js,ts,jsx,tsx,rs}: Name tests descriptively, starting with “should …”
Unit/integration tests must not perform network calls; mock dependencies instead

Files:

  • packages/rs-sdk/tests/fetch/platform_events.rs
  • packages/rs-sdk/tests/fetch/config.rs
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/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts
  • packages/dashmate/configs/defaults/getBaseConfigFactory.js
  • packages/dashmate/src/config/configJsonSchema.js
  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.js
🧠 Learnings (39)
📓 Common learnings
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:119-120
Timestamp: 2024-10-06T16:18:07.994Z
Learning: In the `run_block_proposal` function in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, it's acceptable to pass `platform_state` to `perform_events_on_first_block_of_protocol_change`, even if `block_platform_state` has been updated.
📚 Learning: 2025-10-15T14:45:30.856Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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.

Applied to files:

  • packages/dashmate/docker-compose.yml
  • packages/rs-dapi/README.md
  • packages/dashmate/docs/config/gateway.md
  • packages/dashmate/docs/services/gateway.md
  • packages/dashmate/configs/defaults/getBaseConfigFactory.js
  • packages/rs-dapi/src/config/tests.rs
  • packages/dashmate/src/config/configJsonSchema.js
  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2025-10-29T10:31:02.449Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2827
File: packages/dashmate/configs/defaults/getBaseConfigFactory.js:254-255
Timestamp: 2025-10-29T10:31:02.449Z
Learning: In dashmate configs (packages/dashmate/configs/defaults/getBaseConfigFactory.js), the `waitForStResultTimeout` for rs-dapi (120000ms / 120s) is intentionally set lower than the gateway listener timeout (125s). This design allows rs-dapi to execute its own timeout handling and return a proper response before the gateway times out, ensuring better error handling.

Applied to files:

  • packages/dashmate/docker-compose.yml
  • packages/rs-dapi/README.md
  • packages/dashmate/docs/config/gateway.md
  • packages/dashmate/docs/services/gateway.md
  • packages/dashmate/configs/defaults/getBaseConfigFactory.js
  • packages/dashmate/src/config/configJsonSchema.js
  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-10-04T09:08:48.470Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2206
File: packages/rs-platform-version/src/version/protocol_version.rs:155-157
Timestamp: 2024-10-04T09:08:48.470Z
Learning: In the dashmate default configurations, the default protocol version for local networks has been removed, and an update mechanism for the protocol version in the consensus parameters has been implemented.

Applied to files:

  • packages/dashmate/docker-compose.yml
  • packages/dashmate/docs/config/gateway.md
  • packages/dashmate/src/config/configJsonSchema.js
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:105-105
Timestamp: 2024-10-09T00:22:57.778Z
Learning: In `run_block_proposal` in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, when retrieving `last_block_time_ms`, it's acceptable to use `platform_state` instead of `block_platform_state`, even after updating the protocol version.

Applied to files:

  • packages/rs-dapi/src/services/streaming_service/block_header_stream.rs
📚 Learning: 2024-10-22T10:53:12.111Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2259
File: packages/rs-dapi-client/src/dapi_client.rs:137-139
Timestamp: 2024-10-22T10:53:12.111Z
Learning: In `packages/rs-dapi-client/src/dapi_client.rs`, when passing data into asynchronous code, ensure that data structures are `Send + Sync`. Using `Arc<AtomicUsize>` is necessary for the retry counter.

Applied to files:

  • packages/rs-dapi/src/services/streaming_service/block_header_stream.rs
  • packages/rs-dapi/src/services/streaming_service/masternode_list_stream.rs
  • packages/rs-dapi/src/services/streaming_service/mod.rs
📚 Learning: 2025-01-23T09:23:32.740Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2405
File: packages/rs-sdk/src/sync.rs:88-95
Timestamp: 2025-01-23T09:23:32.740Z
Learning: The `block_on` function in `packages/rs-sdk/src/sync.rs` is currently only used in tests, and its WebAssembly implementation is deferred until there's a user request for it.

Applied to files:

  • packages/rs-dapi/src/services/streaming_service/block_header_stream.rs
  • packages/rs-sdk/tests/fetch/platform_events.rs
📚 Learning: 2024-10-19T06:10:00.808Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2255
File: packages/dashmate/src/status/scopes/platform.js:112-116
Timestamp: 2024-10-19T06:10:00.808Z
Learning: In the Dashmate project, when fetching from Tenderdash RPC endpoints like `/status`, `/net_info`, and `/abci_info`, if one request fails, it's likely that the others will fail as well, so individual error handling for each fetch may not be necessary.

Applied to files:

  • packages/rs-dapi/src/services/streaming_service/mod.rs
  • packages/dashmate/docs/services/gateway.md
📚 Learning: 2025-09-03T16:37:11.605Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2756
File: packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/update_state_masternode_list/v0/mod.rs:11-11
Timestamp: 2025-09-03T16:37:11.605Z
Learning: In packages/rs-dpp/Cargo.toml, the abci feature already includes core_rpc_client, and core_rpc_client is defined as ["dep:dashcore-rpc"]. This means rs-drive-abci can access dashcore-rpc types through dpp when using the abci feature.

Applied to files:

  • packages/rs-dapi/src/services/streaming_service/mod.rs
📚 Learning: 2025-09-12T13:18:08.661Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:18:08.661Z
Learning: Applies to packages/rs-*/**/*.rs : Use PascalCase for Rust types

Applied to files:

  • packages/dapi-grpc/src/lib.rs
📚 Learning: 2024-10-18T15:39:51.172Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2254
File: packages/rs-sdk/src/sdk.rs:585-585
Timestamp: 2024-10-18T15:39:51.172Z
Learning: The 'platform' project uses Rust version 1.80, so code in 'packages/rs-sdk' can use features available in Rust 1.80, such as the `abs_diff()` method.

Applied to files:

  • packages/dapi-grpc/src/lib.rs
  • packages/rs-sdk/tests/fetch/platform_events.rs
  • packages/rs-sdk/examples/platform_events.rs
  • packages/rs-sdk/tests/fetch/config.rs
📚 Learning: 2024-10-08T13:28:03.529Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-drive-abci/src/platform_types/platform_state/mod.rs:141-141
Timestamp: 2024-10-08T13:28:03.529Z
Learning: When converting `PlatformStateV0` to `PlatformStateForSavingV1` in `packages/rs-drive-abci/src/platform_types/platform_state/mod.rs`, only version `0` needs to be handled in the match on `platform_state_for_saving_structure_default` because the changes are retroactive.

Applied to files:

  • packages/dapi-grpc/src/lib.rs
  • packages/rs-drive-abci/src/query/service.rs
  • packages/dapi-grpc/protos/platform/v0/platform.proto
📚 Learning: 2025-09-12T13:18:08.661Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:18:08.661Z
Learning: Applies to packages/rs-*/**/*.rs : Keep Rust code clippy-clean (cargo clippy)

Applied to files:

  • packages/dapi-grpc/src/lib.rs
  • packages/rs-sdk/tests/fetch/config.rs
📚 Learning: 2025-09-12T13:18:08.661Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:18:08.661Z
Learning: Applies to packages/rs-*/**/*.rs : Use SCREAMING_SNAKE_CASE for Rust constants

Applied to files:

  • packages/dapi-grpc/src/lib.rs
📚 Learning: 2024-10-29T10:42:00.521Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-dapi-client/Cargo.toml:22-22
Timestamp: 2024-10-29T10:42:00.521Z
Learning: In `packages/rs-dapi-client/Cargo.toml`, `backon` will not work without the `tokio-sleep` feature in our setup, so it's unnecessary to declare `tokio-sleep` as a separate feature in the `[features]` section.

Applied to files:

  • packages/dapi-grpc/src/lib.rs
📚 Learning: 2024-11-20T10:01:50.837Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/platform_types/platform_state/v0/old_structures/mod.rs:94-94
Timestamp: 2024-11-20T10:01:50.837Z
Learning: In `packages/rs-drive-abci/src/platform_types/platform_state/v0/old_structures/mod.rs`, when converting with `PublicKey::try_from`, it's acceptable to use `.expect()` to handle potential conversion errors.

Applied to files:

  • packages/dapi-grpc/src/lib.rs
  • packages/rs-sdk/tests/fetch/platform_events.rs
📚 Learning: 2024-10-10T10:30:19.883Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2232
File: packages/rs-sdk/src/mock/sdk.rs:90-95
Timestamp: 2024-10-10T10:30:19.883Z
Learning: In `packages/rs-sdk/src/mock/sdk.rs`, the `load_expectations` method in `MockDashPlatformSdk` remains asynchronous (`async`) for backward compatibility, even though it now delegates to the synchronous `load_expectations_sync` method.

Applied to files:

  • packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs
  • packages/rs-sdk/tests/fetch/platform_events.rs
  • packages/rs-sdk/examples/platform_events.rs
📚 Learning: 2025-10-09T15:59:28.329Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2716
File: packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs:181-187
Timestamp: 2025-10-09T15:59:28.329Z
Learning: In `packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs`, the maintainer requires logging full state transition bytes (`tx_bytes = hex::encode(st_bytes)`) at debug level when a state transition passes CheckTx but is removed from the block by the proposer, to facilitate debugging of this rare edge case.

Applied to files:

  • packages/rs-dapi/src/services/streaming_service/transaction_stream.rs
  • packages/rs-sdk/tests/fetch/platform_events.rs
  • packages/rs-sdk/examples/platform_events.rs
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
📚 Learning: 2024-10-30T11:19:59.163Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/tests/fetch/config.rs:233-233
Timestamp: 2024-10-30T11:19:59.163Z
Learning: In the Rust SDK's `rs-sdk/tests` integration tests (e.g., in `packages/rs-sdk/tests/fetch/config.rs`), we cannot create objects during tests because there is no support for object creation in this context. Therefore, hardcoded values for test identities must be used.

Applied to files:

  • packages/rs-sdk/tests/fetch/platform_events.rs
  • packages/rs-sdk/examples/platform_events.rs
  • packages/rs-sdk/tests/fetch/config.rs
📚 Learning: 2024-11-25T01:17:02.001Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2347
File: packages/rs-drive/tests/query_tests.rs:438-460
Timestamp: 2024-11-25T01:17:02.001Z
Learning: In Rust test files (`packages/rs-drive/tests/query_tests.rs`), when code is used only in tests, defining explicit enums for fields (like the `status` field in the `Withdrawal` struct) may not be necessary; using primitive types is acceptable.

Applied to files:

  • packages/rs-sdk/tests/fetch/platform_events.rs
📚 Learning: 2024-11-20T16:05:40.200Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs:148-151
Timestamp: 2024-11-20T16:05:40.200Z
Learning: In `packages/rs-drive-abci/src/platform_types/signature_verification_quorum_set/v0/for_saving.rs`, when converting public keys from `QuorumForSavingV0` to `VerificationQuorum`, it's acceptable to use `.expect()` for public key conversion, as the conversion has been verified and panics are acceptable in this context.

Applied to files:

  • packages/rs-sdk/tests/fetch/platform_events.rs
📚 Learning: 2024-11-20T20:43:41.185Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/tests/strategy_tests/masternodes.rs:212-220
Timestamp: 2024-11-20T20:43:41.185Z
Learning: In `packages/rs-drive-abci/tests/strategy_tests/masternodes.rs`, the pattern of generating a `PrivateKey`, converting it to bytes, and reconstructing a `BlsPrivateKey` from those bytes is intentional. Avoid suggesting to simplify this code in future reviews.

Applied to files:

  • packages/rs-sdk/tests/fetch/platform_events.rs
📚 Learning: 2024-10-29T14:13:35.584Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/dapi-grpc/src/mock.rs:95-109
Timestamp: 2024-10-29T14:13:35.584Z
Learning: In test code (e.g., `packages/dapi-grpc/src/mock.rs`), panicking on deserialization errors is acceptable behavior.

Applied to files:

  • packages/rs-sdk/tests/fetch/platform_events.rs
📚 Learning: 2024-11-03T10:39:11.242Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2305
File: packages/rs-drive-abci/src/abci/handler/finalize_block.rs:81-0
Timestamp: 2024-11-03T10:39:11.242Z
Learning: In `packages/rs-drive-abci/src/abci/handler/finalize_block.rs`, the use of `.expect("commit transaction")` after `app.commit_transaction(platform_version)` is intentional due to the provided comment explaining its necessity. Do not flag this usage in future reviews.

Applied to files:

  • packages/rs-sdk/tests/fetch/platform_events.rs
📚 Learning: 2024-09-26T14:58:26.560Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2162
File: packages/dashmate/src/status/providers.js:87-96
Timestamp: 2024-09-26T14:58:26.560Z
Learning: In the `checkPortStatus` function, it's better to use `options.timeout` to set the socket timeout for both request and response.

Applied to files:

  • packages/dashmate/configs/defaults/getBaseConfigFactory.js
📚 Learning: 2024-10-06T16:18:07.994Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:119-120
Timestamp: 2024-10-06T16:18:07.994Z
Learning: In the `run_block_proposal` function in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, it's acceptable to pass `platform_state` to `perform_events_on_first_block_of_protocol_change`, even if `block_platform_state` has been updated.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
📚 Learning: 2025-09-05T06:00:56.491Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2761
File: packages/rs-drive/src/query/filter.rs:268-272
Timestamp: 2025-09-05T06:00:56.491Z
Learning: For document subscription filters in rs-drive, validation should not require index availability checks like queries do. Subscription filtering has different validation requirements than query optimization.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-10T10:30:24.653Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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-drive-abci/src/query/service.rs
📚 Learning: 2025-10-09T15:59:33.162Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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-drive-abci/src/query/service.rs
📚 Learning: 2024-10-29T14:40:54.727Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/src/core/transaction.rs:0-0
Timestamp: 2024-10-29T14:40:54.727Z
Learning: In `packages/rs-sdk/src/platform/document_query.rs` and `packages/rs-sdk/src/core/transaction.rs`, certain places don't implement `IntoInner`, so direct error mappings cannot be simplified using `IntoInner`. A TODO comment has been added to address this in a future PR.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-30T11:04:33.634Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/src/platform/fetch_unproved.rs:0-0
Timestamp: 2024-10-30T11:04:33.634Z
Learning: In `packages/rs-sdk/src/platform/fetch_unproved.rs`, the `execute()` method consumes the request object, so cloning the request is necessary before passing it to `execute()` and `maybe_from_unproved_with_metadata`.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2025-05-28T16:22:26.334Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2644
File: packages/rs-drive/src/cache/system_contracts.rs:18-19
Timestamp: 2025-05-28T16:22:26.334Z
Learning: In packages/rs-drive/src/cache/system_contracts.rs, the `active_since_protocol_version` field in `ActiveSystemDataContract` struct is intentionally added for future use, not current implementation. QuantumExplorer confirmed this is "meant for later" when questioned about the `#[allow(unused)]` attribute.

Applied to files:

  • packages/rs-sdk/tests/fetch/config.rs
📚 Learning: 2024-10-03T11:51:06.980Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2201
File: packages/rs-platform-version/src/version/v2.rs:1186-1188
Timestamp: 2024-10-03T11:51:06.980Z
Learning: In the `IdentityTransitionVersions` structure within `packages/rs-platform-version/src/version/v2.rs`, the field `credit_withdrawal` does not need the `identity_` prefix since it is already encompassed within identity state transitions.

Applied to files:

  • packages/rs-sdk/tests/fetch/config.rs
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
📚 Learning: 2024-12-03T15:00:50.385Z
Learnt from: lklimek
Repo: dashpay/platform PR: 1924
File: packages/rs-sdk/src/sdk.rs:855-870
Timestamp: 2024-12-03T15:00:50.385Z
Learning: In `packages/rs-sdk/src/sdk.rs`, remember that `rustls_pemfile::certs` returns an iterator over `Result`, not a `Result` directly. Handle it accordingly in future code reviews.

Applied to files:

  • packages/rs-sdk/tests/fetch/config.rs
📚 Learning: 2024-10-24T05:00:56.657Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:83-85
Timestamp: 2024-10-24T05:00:56.657Z
Learning: An upcoming filter will be introduced to the `unconfirmed_txs` endpoint in `broadcastStateTransitionHandlerFactory.js`, as noted in the TODO comment. Therefore, optimizing transaction existence checks may not be necessary at this time.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
📚 Learning: 2024-10-24T04:59:20.436Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:75-77
Timestamp: 2024-10-24T04:59:20.436Z
Learning: Tenderdash's `tx` RPC method accepts transaction hashes in base64 encoding, or in hex encoding if prefixed with `0x`. Therefore, in `packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js`, it's acceptable to use `stHash.toString('base64')` when calling `requestTenderRpc('tx', { hash: stHash.toString('base64') })`.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
📚 Learning: 2025-02-03T23:39:10.579Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2450
File: packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/v0/methods.rs:10-12
Timestamp: 2025-02-03T23:39:10.579Z
Learning: Block interval calculations in token distribution logic should use checked arithmetic operations (checked_sub, checked_add) to prevent potential overflows, especially when dealing with block heights and intervals.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
📚 Learning: 2024-10-25T09:33:50.383Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2274
File: packages/js-dapi-client/lib/transport/GrpcTransport/createGrpcTransportError.js:127-127
Timestamp: 2024-10-25T09:33:50.383Z
Learning: In `createGrpcTransportError.js`, the size of consensus error data is already validated by gRPC transport, so adding an additional size check before base64 decoding in the `createGrpcTransportError` function is unnecessary.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
📚 Learning: 2025-10-09T15:59:18.338Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2716
File: packages/wallet-lib/src/plugins/Workers/TransactionsSyncWorker/TransactionsReader.js:325-334
Timestamp: 2025-10-09T15:59:18.338Z
Learning: In `packages/wallet-lib/src/plugins/Workers/TransactionsSyncWorker/TransactionsReader.js`, the continuous sync restart intentionally uses `Math.max(1, lastSyncedBlockHeight)` rather than `lastSyncedBlockHeight + 1` because the last block's processing status is uncertain at restart time. This conservative approach ensures no blocks are missed by reprocessing the last synced block, accepting potential duplicate processing for data completeness.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
🪛 markdownlint-cli2 (0.18.1)
packages/dashmate/docs/services/gateway.md

109-109: Inconsistent indentation for list items at the same level
Expected: 0; Actual: 1

(MD005, list-indent)


109-109: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


110-110: Inconsistent indentation for list items at the same level
Expected: 0; Actual: 1

(MD005, list-indent)


110-110: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


111-111: Inconsistent indentation for list items at the same level
Expected: 0; Actual: 1

(MD005, list-indent)


111-111: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

🪛 Ruff (0.14.2)
packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py

549-549: Unused method argument: request

(ARG002)

⏰ 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). (17)
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (dash-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • 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: Build JS packages / Build JS
  • GitHub Check: Rust crates security audit
  • GitHub Check: Swift SDK and Example build (warnings as errors)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
🔇 Additional comments (30)
packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py (3)

252-256: Client stub correctly implements server streaming.

The unary_stream pattern is appropriate for this subscription use case, allowing the client to send one request and receive multiple event responses.


798-802: Handler registration correctly configured.

The unary_stream_rpc_method_handler properly wires the server-streaming RPC with appropriate serialization.


1612-1627: Experimental API correctly mirrors main implementation.

The experimental subscribePlatformEvents method properly implements server streaming with the same endpoint and payload types.

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

173-174: LGTM!

The timeout is correctly applied to both historical and combined streaming modes, as it's scheduled before the mode check. The 600-second default (10 minutes) provides reasonable protection against hanging streams.

packages/rs-dapi/src/config/mod.rs (1)

88-99: LGTM!

The new timeout configuration fields are well-structured and follow existing patterns. The 10-minute default is appropriate for long-running streaming subscriptions.

packages/rs-dapi/src/services/streaming_service/block_header_stream.rs (3)

3-3: LGTM!

Import added for timeout functionality.


84-85: LGTM!

Timeout correctly applied to historical streaming mode.


105-106: LGTM!

Timeout correctly applied to combined streaming mode, consistent with the historical mode implementation.

packages/rs-dapi/README.md (1)

25-26: LGTM!

The documentation clearly describes the new timeout environment variables with accurate defaults.

packages/dashmate/docs/config/gateway.md (1)

25-25: LGTM!

The documentation update correctly reflects the new timeout configuration location and helpfully notes the Envoy grace period behavior.

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

6-6: LGTM!

Import added for timeout functionality.


24-25: LGTM!

Timeout correctly applied to masternode list streaming, consistent with other streaming service implementations.

packages/dashmate/docker-compose.yml (1)

153-155: LGTM!

The environment variable mappings correctly reflect the config structure migration, with the old flat waitForStResultTimeout now nested under timeouts.waitForStateTransitionResult, and new timeout variables added for platform events and core streams.

packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java (5)

2242-2248: Service binding for server‑streaming is correct.

asyncServerStreamingCall with the new method ID is properly wired.


3499-3499: Method ID assignment looks consistent.

METHODID_SUBSCRIBE_PLATFORM_EVENTS = 47 follows sequential numbering.


3706-3709: MethodHandlers case correctly routes to subscribePlatformEvents.

Switch wiring matches SERVER_STREAMING path.


3818-3818: ServiceDescriptor includes subscribePlatformEvents.

Descriptor registration completed; no issues.


1475-1504: Now let me verify the Javadoc typos mentioned in the original review:

Now I need to search for and display the Javadoc areas to verify the typo claims:

Based on the verification results, the naming consistency check passed—no stale PascalCase references were found, and proto comments in protobuf 2.5+ generate Javadoc in the Java code, meaning any typos originate from the .proto file. The verification script confirmed the proto file uses correct lowerCamel casing at line 181.

However, the original review mentions Javadoc typos ("subscribint") at specific line ranges (1898–1909, 2242–2248, 2658–2670), but only the descriptor snippet (lines 1475–1504) was provided. To finalize the review assessment, those Javadoc areas must be inspected directly.

RPC descriptor: casing and streaming type are correct.

Naming verification passed—no stale PascalCase found; proto file uses subscribePlatformEvents (lowerCamel) at line 181. MethodDescriptor wiring uses SERVER_STREAMING consistently as expected.

Verify the Javadoc areas mentioned in the original review (ImplBase method around line 1898–1909 and stub implementations) to confirm reported typos and recommend regenerating from the proto file to fix them, if found.

packages/dapi-grpc/clients/platform/v0/web/platform_pb_service.d.ts (2)

430-437: Typings for server‑streaming look correct.
requestStream=false, responseStream=true with proper request/response types. LGTM.


946-947: Client API shape matches grpc-web streaming conventions.
Returning ResponseStream with optional metadata is consistent.

packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs (1)

34-47: Proxy stream implementation looks solid. Confirm error metric semantics.

Flow, backpressure, and lifecycle are sane; duplicate timeout/error emissions won’t surface due to channel close. Please confirm that counting a locally generated deadline_exceeded as a forwarded_error matches your metrics intent.

Also applies to: 54-67, 70-101

packages/rs-drive-abci/src/query/service.rs (2)

281-320: FilterAdapter semantics look correct. Keepalives bypass filtering.
Matches All, BlockCommitted, and STR with optional tx_hash; keepalives always pass. LGTM.


894-914: Good validation of filter.kind and keepalive bounds.
Returning InvalidArgument for missing kind and out-of-range keepalive aligns with API docs.

packages/dapi-grpc/protos/platform/v0/platform.proto (1)

29-49: Solid presence‑based filter design.
Using empty messages in oneof avoids the bool-in-oneof ambiguity. Event envelope and metadata look fine.

Also applies to: 51-75

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m (2)

320-337: New message declarations align with the proto changes.

All Objective-C class declarations for the new event, filter, and subscription message types are present and match the schema additions.


409-1047: Descriptor wiring for subscriptions/events looks correct.

The descriptor setups cover the expected oneofs, field flags, and containment relations for the new subscription request/response messages, filters, and event payloads. No issues spotted.

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

24-35: Allowing generated naming is appropriate here.

Good call adding the non-CamelCase allowance so the generated platform bindings stay warning-free without touching the proto output.

packages/rs-sdk/examples/platform_events.rs (1)

89-143: Example flow looks solid.

Appreciate the comprehensive sample—covering specific filters plus Ctrl+C teardown makes it easy for devs to reuse.

packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (1)

463-9203: LGTM! Auto-generated protobuf code follows standard patterns.

This is correctly generated JavaScript protobuf code from protocol buffer definitions. The implementation follows all standard Google Protocol Buffer patterns for JavaScript:

  • Proper message constructors with jspb.Message.initialize
  • Correct oneof group handling for versioned messages
  • Standard serialization/deserialization methods
  • Appropriate getter/setter/clear/has accessors for all fields
  • Proper JSDoc type annotations

The new platform event subscription API surface (PlatformSubscriptionRequest, PlatformSubscriptionResponse, PlatformEventV0, filters, etc.) is correctly generated. Any API design concerns should be addressed in the source .proto files rather than in this generated output.

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (1)

493-498: Server-side keepalive validation is already implemented correctly; range enforcement is in place

The codebase already handles the concerns raised:

  • Range validation: Server rejects values outside the 25–300 range with a clear error message
  • Semantic interpretation of 0: Server treats keepalive == 0 as disabled (None), distinct from invalid out-of-range values
  • Client-side safeguard: SDK clamps computed keepalive to the valid range [25, 300]
  • Implicit optional semantics: The generated code uses optional field semantics despite proto3's lack of explicit presence

The Objective-C file under review is generated from the .proto definition, so manual edits would be overwritten. Switching to google.protobuf.UInt32Value would require a protocol-breaking change without additional benefit, given that the current implementation semantically distinguishes "0 = disabled" from invalid values through server-side validation.

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

♻️ Duplicate comments (6)
packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java (1)

1898-1909: Polish Javadoc handshake phrasing via proto comments, then regenerate.

Wording “it sends handshake response with empty event” is slightly awkward; tweak in platform.proto and regen so all languages inherit it. For example:

- // Once connected, it sends handshake response with empty event.
+ // On connect, the server sends an initial handshake response (empty event) before real events.
packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (2)

603-616: Unify naming: StateTransitionResult (filter) vs StateTransitionFinalized (event); also rename txHash → stateTransitionHash

Filter uses StateTransitionResult while event uses StateTransitionFinalized, and fields use txHash vs stateTransitionHash elsewhere (e.g., WaitForStateTransitionResult*). This cross-language/public API inconsistency will confuse SDKs and users. Prefer “StateTransitionResult” and “state_transition_hash” across proto and regenerate all bindings.

Proto-level sketch (edit platform.proto, then regenerate):

 message PlatformEventV0 {
   oneof event {
     BlockCommitted block_committed = 1;
-    StateTransitionFinalized state_transition_finalized = 2;
+    StateTransitionResult state_transition_result = 2;
     Keepalive keepalive = 3;
   }
 }

-message StateTransitionFinalized {
+message StateTransitionResult {
   BlockMetadata meta = 1;
-  bytes tx_hash = 2;
+  bytes state_transition_hash = 2;
 }

 message PlatformFilterV0 {
   oneof kind {
     AllEvents all = 1;
     BlockCommitted block_committed = 2;
     StateTransitionResultFilter state_transition_result = 3;
   }
 }

 message StateTransitionResultFilter {
-  bytes tx_hash = 1;
+  bytes state_transition_hash = 1;
}

Also update generated names in ObjC/TS/Java, and references in rs-* and clients.

Also applies to: 621-633, 688-701


573-575: Fix truncated doc comment for stateTransitionResult filter

The comment ends mid‑sentence. Replace with a complete note that references the filter type and oneof semantics.

Proto comment suggestion (in platform.proto):

// Subscribe to StateTransitionResult events (optionally filtered by
// StateTransitionResultFilter). Setting this clears other 'kind' variants.
StateTransitionResultFilter state_transition_result = 3;
packages/dapi-grpc/protos/platform/v0/platform.proto (1)

177-183: Fix grammar in subscription RPC doc.

The RPC comment still omits the article that was requested previously (“handshake response with empty event”). Please update the proto comment so it reads “Once connected, it sends a handshake response with an empty event.” and drop the extra-spaced blank line. Regenerate the client bindings afterwards so the corrected wording propagates to Python, Objective-C, etc.

-  // Allows subscribing to various Platform events.
-  // 
-  // Once connected, it sends handshake response with empty event.
+  // Allows subscribing to various Platform events.
+  //
+  // Once connected, it sends a handshake response with an empty event.
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (1)

85-108: Resolve the clientSubscriptionId asymmetry before freezing the API.

Response V0 still exposes clientSubscriptionId, but PlatformSubscriptionRequestV0 gives clients no field to set such an ID. That leaves the server inventing a “client” identifier, which is misleading for consumers that need to correlate streams. Either add an optional client_subscription_id to the request and echo it back, or rename the response field to a server-generated subscription_id. Please address this before the contract ships—this was flagged previously.

 message PlatformSubscriptionRequestV0 {
   PlatformFilterV0 filter = 1;
-  uint32 keepalive = 2;
+  uint32 keepalive = 2;
+  string client_subscription_id = 3; // optional: echo in responses
 }
 
 message PlatformSubscriptionResponseV0 {
-  string client_subscription_id = 1;
+  string subscription_id = 1; // echo client's ID or server-generated
   PlatformEventV0 event = 2;
 }
packages/rs-drive-abci/src/query/service.rs (1)

69-83: Completed subscription tasks still accumulate in the workers Vec.

The Drop implementation ensures cleanup on service shutdown, which is good. However, when a subscription completes normally (e.g., client disconnects), its JoinHandle remains in the Vec indefinitely. Over the service's lifetime, this causes unbounded memory growth as subscription handles accumulate.

Consider one of these approaches:

Option 1 (simplest): Use tokio::spawn directly at line 1017 and drop the handle immediately, removing the workers field entirely:

-        let worker = tokio::task::spawn(async move {
+        tokio::spawn(async move {
             ...
         });
-        self.workers.lock().unwrap().push(worker);

Then remove the workers field and Drop impl.

Option 2: Implement a background reaper task that periodically drains finished tasks from the JoinSet/Vec.

🧹 Nitpick comments (8)
packages/rs-sdk/examples/platform_events.rs (3)

98-101: Log hex decode failures for better user experience.

Silent failure on invalid hex input can confuse users. Consider logging a warning when decode fails.

Apply this diff to warn on decode failures:

-        let tx_hash_bytes = config
-            .state_transition_tx_hash_hex
-            .as_deref()
-            .and_then(|s| hex::decode(s).ok());
+        let tx_hash_bytes = config
+            .state_transition_tx_hash_hex
+            .as_deref()
+            .and_then(|s| {
+                hex::decode(s).map_err(|e| {
+                    tracing::warn!("Failed to decode tx hash hex: {}", e);
+                    e
+                }).ok()
+            });

142-142: Consider handling worker task results.

Ignoring join results means panics or errors in worker tasks are silently lost, making debugging harder.

For better observability:

-        let _ = tokio::join!(block_worker, str_worker, all_worker);
+        let (r1, r2, r3) = tokio::join!(block_worker, str_worker, all_worker);
+        for result in [r1, r2, r3] {
+            if let Err(e) = result {
+                tracing::error!("Worker task failed: {}", e);
+            }
+        }

145-193: Use consistent logging throughout the worker function.

The function mixes println!/eprintln! (lines 168, 187, 192) with tracing::info! (lines 157, 178), which is inconsistent and bypasses the configured logging framework.

Apply this diff for consistency:

                                     PlatformEvent::StateTransitionFinalized(r) => {
                                         if let Some(meta) = r.meta {
-                                            println!(
+                                            info!(
                                                 "{label}: id={sub_id} height={} tx_hash=0x{} block_id_hash=0x{}",
                                                 meta.height,
                                                 hex::encode(r.tx_hash),
                                                 hex::encode(meta.block_id_hash)
                                             );
                                         }
                                     }
 
                 Err(status) => {
-                    eprintln!("{label}: stream error {status}");
+                    tracing::error!("{label}: stream error {status}");
                     break;
                 }
             }
         }
-        println!("{label}: stream closed");
+        info!("{label}: stream closed");
     }
packages/dashmate/configs/getConfigFileMigrationsFactory.js (2)

1167-1175: Remove redundant initialization of deprecated config.

The migration initializes options.platform.dapi.deprecated from defaults (lines 1167-1175) but then deletes it shortly after in the same migration (line 1338). This initialization is unnecessary since the value is immediately discarded.

Consider removing the initialization block (lines 1167-1175) entirely, as the deletion at line 1338 is the intended final state:

-            if (!options.platform.dapi.deprecated) {
-              if (defaultConfig.has('platform.dapi.deprecated')) {
-                options.platform.dapi.deprecated = defaultConfig.get('platform.dapi.deprecated');
-              }
-            } else if (typeof options.platform.dapi.deprecated.enabled === 'undefined') {
-              if (defaultConfig.has('platform.dapi.deprecated.enabled')) {
-                options.platform.dapi.deprecated.enabled = defaultConfig.get('platform.dapi.deprecated.enabled');
-              }
-            }
-

Also applies to: 1337-1339


1416-1444: Refactor timeout normalization to improve clarity.

The timeout normalization logic accesses options.platform.dapi.api.timeouts and options.platform.dapi.api.waitForStResultTimeout (lines 1417, 1419) after options.platform.dapi.api was already deleted at line 1389. While the optional chaining prevents runtime errors, these accesses will always yield undefined, making the fallback chains misleading. Additionally, the subsequent deletions at lines 1434-1440 attempt to remove fields from the already-deleted api object, making them no-ops.

The timeout migration at lines 1380-1390 already handles copying waitForStResultTimeout from api to rsDapi before deleting api. The later access at line 1419 is redundant.

Consider restructuring to make the logic flow clearer:

             // Normalize rsDapi timeout structure and remove redundant legacy fields
             const existingTimeouts = options.platform.dapi.rsDapi.timeouts
-              ?? options.platform.dapi.api?.timeouts;
+              ?? {};
             const waitForStateTransitionResult = existingTimeouts?.waitForStateTransitionResult
-              ?? options.platform?.dapi?.api?.waitForStResultTimeout
               ?? 120000;
             const subscribePlatformEvents = existingTimeouts?.subscribePlatformEvents ?? 600000;
             const coreStreams = existingTimeouts?.coreStreams ?? 600000;
 
             options.platform.dapi.rsDapi.timeouts = {
               waitForStateTransitionResult,
               subscribePlatformEvents,
               coreStreams,
             };
 
             if (typeof rsDapi.waitForStResultTimeout !== 'undefined') {
               delete rsDapi.waitForStResultTimeout;
             }
-
-            if (options.platform?.dapi?.api?.timeouts) {
-              delete options.platform.dapi.api.timeouts;
-            }
-
-            if (typeof options.platform?.dapi?.api?.waitForStResultTimeout !== 'undefined') {
-              delete options.platform.dapi.api.waitForStResultTimeout;
-            }
-

This removes the confusing attempts to access and delete from the already-deleted api object, since those values were already migrated earlier at lines 1380-1390.

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (2)

682-683: Clarify what txCount counts

Specify that txCount is the number of state transitions included in the committed block (not Core txs). Update proto comment.


495-500: Keepalive: document default and server-side validation/clamping

Docs provide range (25–300s, 0 disables) but not default or enforcement. Please document the default interval and confirm server clamps out-of-range values (and whether per-connection overrides apply). Edit proto comments accordingly.

packages/rs-drive-abci/src/query/service.rs (1)

970-970: Remove unnecessary .clone() on Copy type.

subscription_id is u64, which implements Copy. The .clone() call is redundant.

Apply this diff:

-                                subscription_id: subscription_id.clone(),
+                                subscription_id,
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 51fb24e and 2c8d6be.

⛔ Files ignored due to path filters (1)
  • Cargo.lock is excluded by !**/*.lock
📒 Files selected for processing (18)
  • packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java (8 hunks)
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (3 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h (3 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m (1 hunks)
  • packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py (4 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (1 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (3 hunks)
  • packages/dapi-grpc/protos/platform/v0/platform.proto (2 hunks)
  • packages/dashmate/configs/defaults/getBaseConfigFactory.js (1 hunks)
  • packages/dashmate/configs/getConfigFileMigrationsFactory.js (5 hunks)
  • packages/rs-drive-abci/Cargo.toml (4 hunks)
  • packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_state_transition_identity_signed/v0/mod.rs (0 hunks)
  • packages/rs-drive-abci/src/query/service.rs (5 hunks)
  • packages/rs-sdk/examples/platform_events.rs (1 hunks)
  • packages/rs-sdk/src/platform/events.rs (1 hunks)
  • packages/wasm-drive-verify/tests/fuzz_tests.rs (1 hunks)
💤 Files with no reviewable changes (1)
  • packages/rs-drive-abci/src/execution/validation/state_transition/common/validate_state_transition_identity_signed/v0/mod.rs
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/rs-sdk/src/platform/events.rs
  • packages/dashmate/configs/defaults/getBaseConfigFactory.js
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.m
🧰 Additional context used
📓 Path-based instructions (5)
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/dashmate/configs/getConfigFileMigrationsFactory.js
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • packages/rs-sdk/examples/platform_events.rs
  • packages/rs-drive-abci/src/query/service.rs
  • packages/wasm-drive-verify/tests/fuzz_tests.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-sdk/examples/platform_events.rs
  • packages/rs-drive-abci/src/query/service.rs
packages/**/tests/**

📄 CodeRabbit inference engine (AGENTS.md)

Place unit and integration tests alongside each package in packages//tests

Files:

  • packages/wasm-drive-verify/tests/fuzz_tests.rs
packages/**/tests/**/*.{js,ts,jsx,tsx,rs}

📄 CodeRabbit inference engine (AGENTS.md)

packages/**/tests/**/*.{js,ts,jsx,tsx,rs}: Name tests descriptively, starting with “should …”
Unit/integration tests must not perform network calls; mock dependencies instead

Files:

  • packages/wasm-drive-verify/tests/fuzz_tests.rs
🧠 Learnings (37)
📚 Learning: 2025-09-03T16:37:11.605Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2756
File: packages/rs-drive-abci/src/execution/platform_events/core_based_updates/update_masternode_list/update_state_masternode_list/v0/mod.rs:11-11
Timestamp: 2025-09-03T16:37:11.605Z
Learning: In packages/rs-dpp/Cargo.toml, the abci feature already includes core_rpc_client, and core_rpc_client is defined as ["dep:dashcore-rpc"]. This means rs-drive-abci can access dashcore-rpc types through dpp when using the abci feature.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2024-12-05T09:29:38.918Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2375
File: packages/rs-drive-abci/Cargo.toml:61-63
Timestamp: 2024-12-05T09:29:38.918Z
Learning: In the `drive-abci` package, avoid adding unused dependencies like `hashbrown` to `Cargo.toml`. The team relies on CI to detect dependency version issues.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2025-01-19T07:36:46.042Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2431
File: packages/rs-drive/Cargo.toml:55-60
Timestamp: 2025-01-19T07:36:46.042Z
Learning: The grovedb dependencies in packages/rs-drive/Cargo.toml and related files are intentionally kept at specific revisions rather than using the latest stable version, with plans to update them at a later time.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2024-10-29T10:42:00.521Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-dapi-client/Cargo.toml:22-22
Timestamp: 2024-10-29T10:42:00.521Z
Learning: In `packages/rs-dapi-client/Cargo.toml`, `backon` will not work without the `tokio-sleep` feature in our setup, so it's unnecessary to declare `tokio-sleep` as a separate feature in the `[features]` section.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2024-10-18T15:39:51.172Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2254
File: packages/rs-sdk/src/sdk.rs:585-585
Timestamp: 2024-10-18T15:39:51.172Z
Learning: The 'platform' project uses Rust version 1.80, so code in 'packages/rs-sdk' can use features available in Rust 1.80, such as the `abs_diff()` method.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
  • packages/rs-sdk/examples/platform_events.rs
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2206
File: packages/rs-drive-abci/tests/strategy_tests/main.rs:1162-1162
Timestamp: 2024-10-09T00:22:57.778Z
Learning: In the Rust test file `packages/rs-drive-abci/tests/strategy_tests/main.rs`, specific protocol versions like `PROTOCOL_VERSION_1` are intentionally used in tests instead of `PROTOCOL_VERSION_LATEST`.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2025-03-11T09:39:23.071Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2489
File: packages/rs-dpp/Cargo.toml:32-32
Timestamp: 2025-03-11T09:39:23.071Z
Learning: In the Dash Platform project, dependencies are currently managed using Git repository references with tags (repo+tag format in Cargo.toml) rather than published crates, as the team is not currently publishing crates to crates.io.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2024-10-10T10:30:25.283Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2232
File: packages/rs-sdk/src/mock/sdk.rs:129-130
Timestamp: 2024-10-10T10:30:25.283Z
Learning: In the codebase `packages/rs-sdk/src/mock/sdk.rs`, `tokio::sync::Mutex` is used instead of `std::sync::Mutex` because `std::sync::MutexGuard` is not `Send` and cannot be used in async contexts.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2024-10-10T10:30:19.883Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2232
File: packages/rs-sdk/src/mock/sdk.rs:90-95
Timestamp: 2024-10-10T10:30:19.883Z
Learning: In `packages/rs-sdk/src/mock/sdk.rs`, the `load_expectations` method in `MockDashPlatformSdk` remains asynchronous (`async`) for backward compatibility, even though it now delegates to the synchronous `load_expectations_sync` method.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
  • packages/rs-sdk/examples/platform_events.rs
📚 Learning: 2024-10-29T14:16:00.141Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/dapi-grpc/src/mock.rs:125-145
Timestamp: 2024-10-29T14:16:00.141Z
Learning: Using `serde_json` encoding produces deterministic output required to identify requests and responses by hash, therefore `serde_json` is used as the basic serialization algorithm for mocking.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2024-09-27T08:23:18.028Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2139
File: packages/rs-sdk/Cargo.toml:0-0
Timestamp: 2024-09-27T08:23:18.028Z
Learning: `bincode` is used in the `mocks` feature of the `rs-sdk`.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2025-01-24T07:54:55.723Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2440
File: packages/rs-drive-abci/Cargo.toml:76-76
Timestamp: 2025-01-24T07:54:55.723Z
Learning: In the drive-abci package, bls-signatures is intentionally declared twice:
1. As an optional dependency in [dependencies] to make it an optional feature in production
2. As a non-optional dependency in [dev-dependencies] to ensure it's always available for tests

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2024-10-29T14:44:01.184Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-dapi-client/src/executor.rs:38-38
Timestamp: 2024-10-29T14:44:01.184Z
Learning: In `packages/rs-dapi-client/src/executor.rs`, for the structs `ExecutionError<E>` and `ExecutionResponse<R>`, only the serde derives (`Serialize`, `Deserialize`) should be conditional based on the "mocks" feature; the other derives (`Debug`, `Clone`, `Eq`, `PartialEq`) should always be present.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2025-09-12T13:18:08.661Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:18:08.661Z
Learning: Applies to packages/rs-*/**/*.rs : Keep Rust code clippy-clean (cargo clippy)

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2024-10-17T08:52:54.300Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2248
File: packages/rs-drive-abci/src/main.rs:106-111
Timestamp: 2024-10-17T08:52:54.300Z
Learning: In this project, the environment variable `CARGO_PKG_RUST_VERSION` is defined and can be used safely with the `env!` macro.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2025-09-12T13:18:08.661Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:18:08.661Z
Learning: Applies to packages/rs-sdk-ffi/** : Keep iOS/FFI Rust SDK artifacts in packages/rs-sdk-ffi

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2025-09-12T13:18:08.661Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:18:08.661Z
Learning: Applies to packages/rs-*/**/*.rs : Use rustfmt defaults for Rust code (format via cargo fmt --all)

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
📚 Learning: 2024-10-30T11:19:59.163Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/tests/fetch/config.rs:233-233
Timestamp: 2024-10-30T11:19:59.163Z
Learning: In the Rust SDK's `rs-sdk/tests` integration tests (e.g., in `packages/rs-sdk/tests/fetch/config.rs`), we cannot create objects during tests because there is no support for object creation in this context. Therefore, hardcoded values for test identities must be used.

Applied to files:

  • packages/rs-drive-abci/Cargo.toml
  • packages/rs-sdk/examples/platform_events.rs
  • packages/wasm-drive-verify/tests/fuzz_tests.rs
📚 Learning: 2025-10-15T14:45:30.856Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js
📚 Learning: 2025-10-29T10:31:02.449Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2827
File: packages/dashmate/configs/defaults/getBaseConfigFactory.js:254-255
Timestamp: 2025-10-29T10:31:02.449Z
Learning: In dashmate configs (packages/dashmate/configs/defaults/getBaseConfigFactory.js), the `waitForStResultTimeout` for rs-dapi (120000ms / 120s) is intentionally set lower than the gateway listener timeout (125s). This design allows rs-dapi to execute its own timeout handling and return a proper response before the gateway times out, ensuring better error handling.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-10-04T09:08:48.470Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2206
File: packages/rs-platform-version/src/version/protocol_version.rs:155-157
Timestamp: 2024-10-04T09:08:48.470Z
Learning: In the dashmate default configurations, the default protocol version for local networks has been removed, and an update mechanism for the protocol version in the consensus parameters has been implemented.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2025-10-09T15:59:28.329Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2716
File: packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs:181-187
Timestamp: 2025-10-09T15:59:28.329Z
Learning: In `packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs`, the maintainer requires logging full state transition bytes (`tx_bytes = hex::encode(st_bytes)`) at debug level when a state transition passes CheckTx but is removed from the block by the proposer, to facilitate debugging of this rare edge case.

Applied to files:

  • packages/rs-sdk/examples/platform_events.rs
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
📚 Learning: 2024-10-06T16:18:07.994Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:119-120
Timestamp: 2024-10-06T16:18:07.994Z
Learning: In the `run_block_proposal` function in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, it's acceptable to pass `platform_state` to `perform_events_on_first_block_of_protocol_change`, even if `block_platform_state` has been updated.

Applied to files:

  • packages/rs-sdk/examples/platform_events.rs
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
  • packages/dapi-grpc/protos/platform/v0/platform.proto
  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-24T05:00:56.657Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:83-85
Timestamp: 2024-10-24T05:00:56.657Z
Learning: An upcoming filter will be introduced to the `unconfirmed_txs` endpoint in `broadcastStateTransitionHandlerFactory.js`, as noted in the TODO comment. Therefore, optimizing transaction existence checks may not be necessary at this time.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
📚 Learning: 2024-10-03T11:51:06.980Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2201
File: packages/rs-platform-version/src/version/v2.rs:1186-1188
Timestamp: 2024-10-03T11:51:06.980Z
Learning: In the `IdentityTransitionVersions` structure within `packages/rs-platform-version/src/version/v2.rs`, the field `credit_withdrawal` does not need the `identity_` prefix since it is already encompassed within identity state transitions.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
📚 Learning: 2024-10-08T13:28:03.529Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-drive-abci/src/platform_types/platform_state/mod.rs:141-141
Timestamp: 2024-10-08T13:28:03.529Z
Learning: When converting `PlatformStateV0` to `PlatformStateForSavingV1` in `packages/rs-drive-abci/src/platform_types/platform_state/mod.rs`, only version `0` needs to be handled in the match on `platform_state_for_saving_structure_default` because the changes are retroactive.

Applied to files:

  • packages/dapi-grpc/protos/platform/v0/platform.proto
  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2025-09-05T06:00:56.491Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2761
File: packages/rs-drive/src/query/filter.rs:268-272
Timestamp: 2025-09-05T06:00:56.491Z
Learning: For document subscription filters in rs-drive, validation should not require index availability checks like queries do. Subscription filtering has different validation requirements than query optimization.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-10T10:30:24.653Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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-drive-abci/src/query/service.rs
📚 Learning: 2025-10-09T15:59:33.162Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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-drive-abci/src/query/service.rs
📚 Learning: 2024-10-29T14:40:54.727Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/src/core/transaction.rs:0-0
Timestamp: 2024-10-29T14:40:54.727Z
Learning: In `packages/rs-sdk/src/platform/document_query.rs` and `packages/rs-sdk/src/core/transaction.rs`, certain places don't implement `IntoInner`, so direct error mappings cannot be simplified using `IntoInner`. A TODO comment has been added to address this in a future PR.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
  • packages/wasm-drive-verify/tests/fuzz_tests.rs
📚 Learning: 2024-10-30T11:04:33.634Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/src/platform/fetch_unproved.rs:0-0
Timestamp: 2024-10-30T11:04:33.634Z
Learning: In `packages/rs-sdk/src/platform/fetch_unproved.rs`, the `execute()` method consumes the request object, so cloning the request is necessary before passing it to `execute()` and `maybe_from_unproved_with_metadata`.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-11-25T01:17:02.001Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2347
File: packages/rs-drive/tests/query_tests.rs:438-460
Timestamp: 2024-11-25T01:17:02.001Z
Learning: In Rust test files (`packages/rs-drive/tests/query_tests.rs`), when code is used only in tests, defining explicit enums for fields (like the `status` field in the `Withdrawal` struct) may not be necessary; using primitive types is acceptable.

Applied to files:

  • packages/wasm-drive-verify/tests/fuzz_tests.rs
📚 Learning: 2025-09-03T14:41:16.196Z
Learnt from: thephez
Repo: dashpay/platform PR: 2754
File: packages/wasm-sdk/AI_REFERENCE.md:766-766
Timestamp: 2025-09-03T14:41:16.196Z
Learning: In packages/wasm-sdk/, the AI_REFERENCE.md file is auto-generated from api-definitions.json. Any documentation fixes should be made in api-definitions.json rather than directly in AI_REFERENCE.md, as manual changes to AI_REFERENCE.md would be overwritten during regeneration.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h
📚 Learning: 2025-02-03T23:39:10.579Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2450
File: packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/v0/methods.rs:10-12
Timestamp: 2025-02-03T23:39:10.579Z
Learning: Block interval calculations in token distribution logic should use checked arithmetic operations (checked_sub, checked_add) to prevent potential overflows, especially when dealing with block heights and intervals.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
📚 Learning: 2024-10-25T09:33:50.383Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2274
File: packages/js-dapi-client/lib/transport/GrpcTransport/createGrpcTransportError.js:127-127
Timestamp: 2024-10-25T09:33:50.383Z
Learning: In `createGrpcTransportError.js`, the size of consensus error data is already validated by gRPC transport, so adding an additional size check before base64 decoding in the `createGrpcTransportError` function is unnecessary.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
📚 Learning: 2025-10-09T15:59:18.338Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2716
File: packages/wallet-lib/src/plugins/Workers/TransactionsSyncWorker/TransactionsReader.js:325-334
Timestamp: 2025-10-09T15:59:18.338Z
Learning: In `packages/wallet-lib/src/plugins/Workers/TransactionsSyncWorker/TransactionsReader.js`, the continuous sync restart intentionally uses `Math.max(1, lastSyncedBlockHeight)` rather than `lastSyncedBlockHeight + 1` because the last block's processing status is uncertain at restart time. This conservative approach ensures no blocks are missed by reprocessing the last synced block, accepting potential duplicate processing for data completeness.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
📚 Learning: 2024-10-24T04:59:20.436Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:75-77
Timestamp: 2024-10-24T04:59:20.436Z
Learning: Tenderdash's `tx` RPC method accepts transaction hashes in base64 encoding, or in hex encoding if prefixed with `0x`. Therefore, in `packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js`, it's acceptable to use `stHash.toString('base64')` when calling `requestTenderRpc('tx', { hash: stHash.toString('base64') })`.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
🧬 Code graph analysis (8)
packages/rs-sdk/examples/platform_events.rs (2)
packages/rs-sdk/src/sdk.rs (3)
  • fmt (173-187)
  • new (847-852)
  • default (797-834)
packages/rs-dapi-client/src/address_list.rs (1)
  • uri (65-67)
packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (1)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (2)
  • PlatformEventV0 (215-240)
  • PlatformFilterV0 (117-142)
packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py (1)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (2)
  • PlatformSubscriptionRequest (9-24)
  • PlatformSubscriptionResponse (63-78)
packages/rs-drive-abci/src/query/service.rs (5)
packages/rs-drive-abci/src/abci/app/full.rs (3)
  • platform (48-50)
  • event_bus (60-62)
  • new (37-44)
packages/rs-drive-abci/src/abci/app/consensus.rs (3)
  • platform (51-53)
  • event_bus (63-65)
  • new (37-47)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (10)
  • Keepalive (333-342)
  • PlatformEventV0 (215-240)
  • PlatformSubscriptionRequest (9-24)
  • PlatformSubscriptionResponse (63-78)
  • PlatformFilterV0 (117-142)
  • BlockCommitted (167-176)
  • BlockCommitted (279-296)
  • StateTransitionFinalized (305-324)
  • Version (5947-5966)
  • PlatformSubscriptionResponseV0 (85-102)
packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs (3)
  • mpsc (50-52)
  • drop (25-27)
  • new (18-21)
packages/rs-sdk/src/platform/events.rs (1)
  • subscribe_platform_events (17-61)
packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java (2)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (2)
  • PlatformSubscriptionRequest (9-24)
  • PlatformSubscriptionResponse (63-78)
packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py (2)
  • subscribePlatformEvents (549-558)
  • subscribePlatformEvents (1613-1627)
packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbrpc.h (2)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (2)
  • PlatformSubscriptionRequest (9-24)
  • PlatformSubscriptionResponse (63-78)
packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py (2)
  • subscribePlatformEvents (549-558)
  • subscribePlatformEvents (1613-1627)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (3)
packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (1)
  • proto (16-16)
packages/dapi-grpc/clients/drive/v0/nodejs/drive_protoc.js (1)
  • proto (16-16)
packages/dapi-grpc/clients/drive/v0/web/drive_pb.js (1)
  • proto (16-16)
packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (1)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (1)
  • proto (16-16)
🪛 Ruff (0.14.2)
packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py

549-549: Unused method argument: request

(ARG002)

⏰ 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). (20)
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (rs-dapi-client) / Tests
  • GitHub Check: Rust packages (drive-abci) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (dapi-grpc) / Tests
  • GitHub Check: Rust packages (dapi-grpc) / Check each feature
  • GitHub Check: Rust packages (dapi-grpc) / Unused dependencies
  • 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 JS packages / Build JS
  • GitHub Check: Swift SDK and Example build (warnings as errors)
  • GitHub Check: Rust crates security audit
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
🔇 Additional comments (24)
packages/rs-drive-abci/Cargo.toml (3)

112-112: Reconsider including "mocks" and "console" in default features.

Including test/debugging features (mocks, console) in the default feature set means the production binary will include mock infrastructure and console debugging by default, which is unusual and potentially problematic (bloated binary, exposed internals, unintended debug behavior).

Typically, these should be opt-in features. Verify this is intentional.


128-130: Cargo-machete ignore list is reasonable.

Adding rs-dash-event-bus to the cargo-machete ignore list is appropriate if the crate is used indirectly (e.g., through trait bounds or type references) rather than direct imports.


76-82: All three dependencies are actively used.

  • tokio-stream: Used in packages/rs-drive-abci/src/query/service.rs:63 to wrap MPSC receivers as streams.
  • sha2: Used in packages/rs-drive-abci/src/abci/handler/finalize_block.rs:166 to hash transactions (Sha256::digest(tx)).
  • rs-dash-event-bus: Extensively used across the codebase for event publishing and subscription (server initialization, query service, and finalize_block handlers).
packages/wasm-drive-verify/tests/fuzz_tests.rs (1)

73-73: LGTM! Correctly removes unnecessary mut keyword.

The binding doesn't need to be mutable since the object is mutated through JavaScript's interior mutability via Reflect::set at line 84. This change makes the code more idiomatic for wasm-bindgen FFI.

packages/rs-sdk/examples/platform_events.rs (3)

1-8: LGTM: Clean feature-gated entry point.

The interaction between the sync main and the async subscribe::main() works correctly because #[tokio::main] transforms the async function into a regular function with runtime setup.


31-67: LGTM: Well-structured configuration with secure password handling.

Good use of Zeroizing<String> for the password field, and the fallback to environment variables when the .env file is missing is appropriate for an example.


195-220: LGTM: SDK setup demonstrates proper configuration.

The function correctly handles URI construction, core connection setup, and conditional CA certificate loading for non-WASM targets. The use of .expect() with descriptive messages is acceptable for example code.

packages/dapi-grpc/clients/platform/v0/java/org/dash/platform/dapi/v0/PlatformGrpc.java (7)

2242-2248: bindService wiring for server stream is correct.

Registered with asyncServerStreamingCall and correct METHODID.


2658-2670: Async stub Javadoc and call match server‑streaming.

Uses asyncServerStreamingCall; docs now aligned.


3031-3043: Blocking stub correctly exposes Iterator for server stream.

Javadoc and blockingServerStreamingCall usage are consistent.


3499-3499: Method ID added without collision.

New METHODID_SUBSCRIBE_PLATFORM_EVENTS = 47 fits sequence.


3706-3709: MethodHandlers routing is correct.

Routes to subscribePlatformEvents with proper types.


3818-3819: Service descriptor includes the new RPC.

addMethod(getSubscribePlatformEventsMethod()) present.


1475-1504: Server-streaming descriptor wiring verified as correct; naming is consistent throughout.

MethodType SERVER_STREAMING, lowerCamel full name ("subscribePlatformEvents"), marshallers, and schema descriptor all verified correct. Proto definition (platform.proto:182) matches Java code generation. No stale PascalCase references found.

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m (2)

320-332: LGTM! Auto-generated forward declarations.

The forward class declarations for the new subscription-related protobuf message types are correctly formatted and consistent with the existing code patterns in this file.


409-1121: LGTM! Auto-generated protobuf implementations.

The implementations for all 13 new subscription-related message classes are correctly structured and follow standard Google Protocol Buffer Objective-C conventions:

  • Thread-safe lazy descriptor initialization with proper recursion guards
  • Correct storage structures with properly calculated field offsets
  • Appropriate field flags and data types for all message, scalar, and bytes fields
  • Proper oneof group setup for discriminated unions (version, kind, event)
  • Nested message classes correctly reference their containing classes

Since this is auto-generated code from protobuf definitions, any modifications should be made to the source .proto files rather than this implementation file.

packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (1)

463-9456: LGTM! Auto-generated protobuf bindings are correctly structured.

This file contains auto-generated JavaScript protobuf client bindings for platform event subscription messages. The code follows standard protobuf JS patterns consistently:

  • Proper export declarations for Google Closure Compiler
  • Correct constructor definitions with inheritance from jspb.Message
  • Complete serialization/deserialization implementation
  • Appropriate handling of oneof groups, nested messages, and type conversions
  • Consistent with other generated files in the codebase

Since this is auto-generated code, ensure the underlying protobuf definitions (platform.proto) are correct, as that's the true source of truth.

packages/rs-drive-abci/src/query/service.rs (7)

13-13: LGTM!

The new imports and buffer constant properly support the event subscription infrastructure.

Also applies to: 51-51, 55-55, 59-59, 62-63, 66-66


94-102: LGTM!

The constructor properly initializes the new event_bus and workers fields, aligning with the event subscription infrastructure.


281-320: LGTM!

The PlatformFilterAdapter correctly implements filter matching semantics: keepalive events always pass through, and subscription filters are properly applied based on event type and optional transaction hash.


896-899: LGTM!

The filter kind validation now correctly rejects requests with missing filter.kind, addressing the previous review concern and preventing silent no-op subscriptions.


901-913: LGTM!

Keepalive interval validation is sound: the 25–300 second range is sensible and clearly communicated to clients.


930-947: LGTM!

The handshake message ensures the client receives the subscription_id before events flow, enabling proper association of responses with the subscription request.


952-1010: LGTM!

The event forwarding loop correctly handles:

  • Real events from the subscription
  • Keepalive timeout to emit keepalive messages
  • Client disconnection via channel closure

The timeout-based keepalive mechanism is elegant and ensures the stream remains active per the client's requirements.

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

Caution

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

⚠️ Outside diff range comments (1)
packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs (1)

178-207: Fix move of transaction_event.tx after matching transaction_event.result.

Line 178 matches transaction_event.result, which moves that field out of the struct. Later in the same branch (Line 186) we try to move transaction_event.tx, but the struct is already partially moved, so this will not compile. Please destructure both result and tx up front (or match on a tuple) before moving either field.

Apply this diff to keep ownership straight:

-        match transaction_event.result {
+        let crate::clients::TransactionEvent { result, tx, .. } = transaction_event;
+        match result {
             crate::clients::TransactionResult::Success => {
-                if prove && let Some(tx_bytes) = transaction_event.tx {
-                    match self.fetch_proof_for_state_transition(tx_bytes).await {
+                if prove {
+                    if let Some(tx_bytes) = tx {
+                        match self.fetch_proof_for_state_transition(tx_bytes).await {
                             Ok((proof, metadata)) => {
                                 response_v0.result = Some(
                                     wait_for_state_transition_result_response::wait_for_state_transition_result_response_v0::Result::Proof(proof),
                                 );
                                 response_v0.metadata = Some(metadata);
                             }
                             Err(e) => {
                                 debug!("Failed to fetch proof: {}", e);
                                 // Continue without proof
                             }
                         }
+                    }
                 }
♻️ Duplicate comments (2)
packages/rs-dapi/src/server/grpc.rs (2)

126-192: Emit the actual gRPC path in tracing fields.
Lines [128], [183], and [189] still call tracing::trace!(path, …), which records path=true instead of the URI. This was flagged previously and remains unresolved—please emit the real value using the % formatter (and reuse it in both branches) so we keep observability when debugging deadline issues.

Apply this diff to log the real path everywhere:

-        tracing::trace!(
-            path,
+        tracing::trace!(
+            path = %path,
             timeout = timeout.as_secs_f32(),
             "Applying timeout for gRPC method"
         );
...
-            tracing::trace!(
-                path,
-                header_timeout = timeout_from_header.unwrap_or_default().as_secs_f32(),
+            tracing::trace!(
+                path = %path,
+                header_timeout = timeout_from_header.unwrap_or_default().as_secs_f32(),
                 timeout = effective_timeout.as_secs_f32(),
                 "Applying gRPC timeout from header"
             );
...
-            tracing::trace!(
-                path,
+            tracing::trace!(
+                path = %path,
                 timeout = effective_timeout.as_secs_f32(),
                 "Applying default gRPC timeout"
             );

262-289: Add a timeout test for the real streaming URI.
Line [272] still uses "/test"; if this test exercised /org.dash.platform.dapi.v0.Platform/SubscribePlatformEvents, it would have caught the casing bug above. Please expand the test (or add a new one) that hits the actual streaming path so per-method timeouts stay covered.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2c8d6be and fa042cc.

📒 Files selected for processing (5)
  • packages/rs-dapi/src/server/grpc.rs (5 hunks)
  • packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs (1 hunks)
  • packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs (2 hunks)
  • packages/rs-dapi/src/services/streaming_service/block_header_stream.rs (0 hunks)
  • packages/rs-dapi/src/services/streaming_service/mod.rs (2 hunks)
💤 Files with no reviewable changes (1)
  • packages/rs-dapi/src/services/streaming_service/block_header_stream.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/rs-dapi/src/services/streaming_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/services/platform_service/wait_for_state_transition_result.rs
  • packages/rs-dapi/src/server/grpc.rs
  • packages/rs-dapi/src/services/platform_service/subscribe_platform_events.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/platform_service/wait_for_state_transition_result.rs
  • packages/rs-dapi/src/server/grpc.rs
  • packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs
🧠 Learnings (9)
📓 Common learnings
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:119-120
Timestamp: 2024-10-06T16:18:07.994Z
Learning: In the `run_block_proposal` function in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, it's acceptable to pass `platform_state` to `perform_events_on_first_block_of_protocol_change`, even if `block_platform_state` has been updated.
📚 Learning: 2025-10-09T15:59:28.329Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2716
File: packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs:181-187
Timestamp: 2025-10-09T15:59:28.329Z
Learning: In `packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs`, the maintainer requires logging full state transition bytes (`tx_bytes = hex::encode(st_bytes)`) at debug level when a state transition passes CheckTx but is removed from the block by the proposer, to facilitate debugging of this rare edge case.

Applied to files:

  • packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs
  • packages/rs-dapi/src/server/grpc.rs
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:105-105
Timestamp: 2024-10-09T00:22:57.778Z
Learning: In `run_block_proposal` in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, when retrieving `last_block_time_ms`, it's acceptable to use `platform_state` instead of `block_platform_state`, even after updating the protocol version.

Applied to files:

  • packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs
📚 Learning: 2024-10-06T16:18:07.994Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:119-120
Timestamp: 2024-10-06T16:18:07.994Z
Learning: In the `run_block_proposal` function in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, it's acceptable to pass `platform_state` to `perform_events_on_first_block_of_protocol_change`, even if `block_platform_state` has been updated.

Applied to files:

  • packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs
  • packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs
📚 Learning: 2024-10-08T13:28:03.529Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-drive-abci/src/platform_types/platform_state/mod.rs:141-141
Timestamp: 2024-10-08T13:28:03.529Z
Learning: When converting `PlatformStateV0` to `PlatformStateForSavingV1` in `packages/rs-drive-abci/src/platform_types/platform_state/mod.rs`, only version `0` needs to be handled in the match on `platform_state_for_saving_structure_default` because the changes are retroactive.

Applied to files:

  • packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs
📚 Learning: 2024-11-20T10:01:50.837Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/src/platform_types/platform_state/v0/old_structures/mod.rs:94-94
Timestamp: 2024-11-20T10:01:50.837Z
Learning: In `packages/rs-drive-abci/src/platform_types/platform_state/v0/old_structures/mod.rs`, when converting with `PublicKey::try_from`, it's acceptable to use `.expect()` to handle potential conversion errors.

Applied to files:

  • packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs
📚 Learning: 2024-10-03T11:51:06.980Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2201
File: packages/rs-platform-version/src/version/v2.rs:1186-1188
Timestamp: 2024-10-03T11:51:06.980Z
Learning: In the `IdentityTransitionVersions` structure within `packages/rs-platform-version/src/version/v2.rs`, the field `credit_withdrawal` does not need the `identity_` prefix since it is already encompassed within identity state transitions.

Applied to files:

  • packages/rs-dapi/src/services/platform_service/wait_for_state_transition_result.rs
📚 Learning: 2024-10-17T08:52:46.847Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2248
File: packages/rs-drive-abci/src/main.rs:311-331
Timestamp: 2024-10-17T08:52:46.847Z
Learning: In our codebase, connections to the gRPC server happen within the local network, so timeouts are not expected, and adding timeouts is unnecessary.

Applied to files:

  • packages/rs-dapi/src/server/grpc.rs
📚 Learning: 2024-10-10T10:30:19.883Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2232
File: packages/rs-sdk/src/mock/sdk.rs:90-95
Timestamp: 2024-10-10T10:30:19.883Z
Learning: In `packages/rs-sdk/src/mock/sdk.rs`, the `load_expectations` method in `MockDashPlatformSdk` remains asynchronous (`async`) for backward compatibility, even though it now delegates to the synchronous `load_expectations_sync` method.

Applied to files:

  • packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs
🧬 Code graph analysis (1)
packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs (3)
packages/rs-drive-abci/src/query/service.rs (4)
  • mpsc (926-926)
  • new (94-103)
  • new (289-291)
  • drop (77-82)
packages/rs-dapi/src/services/platform_service/mod.rs (1)
  • new (111-164)
packages/rs-dapi/src/metrics.rs (6)
  • new (373-375)
  • platform_events_active_sessions_inc (500-502)
  • platform_events_active_sessions_dec (505-507)
  • platform_events_upstream_stream_started (520-522)
  • platform_events_forwarded_event (510-512)
  • platform_events_forwarded_error (515-517)
⏰ 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). (21)
  • GitHub Check: Rust packages (dapi-grpc) / Check each feature
  • GitHub Check: Rust packages (drive-abci) / Formatting
  • GitHub Check: Rust packages (drive-abci) / Tests
  • GitHub Check: Rust packages (drive-abci) / Linting
  • GitHub Check: Rust packages (drive-abci) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Tests
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dash-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • GitHub Check: Rust packages (dash-sdk) / 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 (Drive, drive, drive-abci) / Build Drive image
  • GitHub Check: Build JS packages / Build JS
  • GitHub Check: Rust crates security audit
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios-sim)
  • GitHub Check: Swift SDK and Example build (warnings as errors)
  • GitHub Check: Build rs-sdk-ffi for iOS targets (aarch64-apple-ios)
🔇 Additional comments (1)
packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs (1)

52-77: Nice session guard to tie metrics to the stream lifetime.

Keeping the guard inside the forwarder ensures active-session metrics stay accurate until the uplink loop actually exits. Clean and robust.

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 (7)
packages/rs-drive-abci/src/query/service.rs (1)

915-915: Add missing rand import.

rand::random::<u64>() is called without importing the rand crate, which will cause a compilation error.

Add this import at the top of the file with other use statements:

+use rand::random;

Then update line 915:

-        let subscription_id = rand::random::<u64>();
+        let subscription_id = random::<u64>();
packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (2)

622-633: Unify event/filter naming and hash field names across API

Filter uses StateTransitionResult while event is StateTransitionFinalized, and fields use txHash vs stateTransitionHash. Align on “StateTransitionResult” and “state_transition_hash” to match WaitForStateTransitionResult*. Regenerate bindings after editing platform.proto.

Proto-level sketch:

 message PlatformEventV0 {
   oneof event {
     BlockCommitted block_committed = 1;
-    StateTransitionFinalized state_transition_finalized = 2;
+    StateTransitionResult state_transition_result = 2;
     Keepalive keepalive = 3;
   }
 }

-message StateTransitionFinalized {
+message StateTransitionResult {
   BlockMetadata meta = 1;
-  bytes tx_hash = 2;
+  bytes state_transition_hash = 2;
 }

 message PlatformFilterV0 {
   oneof kind {
     AllEvents all = 1;
     BlockCommitted block_committed = 2;
-    StateTransitionResultFilter state_transition_result = 3;
+    StateTransitionResultFilter state_transition_result = 3; // unchanged name
   }
 }

 message PlatformFilterV0_StateTransitionResultFilter {
-  bytes tx_hash = 1;
+  bytes state_transition_hash = 1;
 }

Also applies to: 687-702, 546-559


574-576: Complete the truncated doc comment for stateTransitionResult filter

Comment ends mid‑sentence. Replace with a full sentence and presence semantics.

Suggested proto comment (then regenerate):

// Subscribe to StateTransitionResult events (optionally filtered by
// StateTransitionResultFilter). Setting this clears other 'kind' variants.
StateTransitionResultFilter state_transition_result = 3;
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (2)

183-205: Inconsistent naming: txHash vs stateTransitionHash; align with existing API.

Elsewhere you use stateTransitionHash (e.g., WaitForStateTransitionResultRequestV0). Rename here for consistency and client ergonomics.

Proto-level suggestion:

-message StateTransitionResultFilter {
-  bytes tx_hash = 1;
-}
+message StateTransitionResultFilter {
+  bytes state_transition_hash = 1;
+}

305-331: Event field naming: use stateTransitionHash instead of txHash.

Stay consistent with request/filters to avoid confusion between Tenderdash tx vs Platform state transition terms.

Proto-level suggestion:

-message StateTransitionFinalized {
-  BlockMetadata meta = 1;
-  bytes tx_hash = 2;
-}
+message StateTransitionFinalized {
+  BlockMetadata meta = 1;
+  bytes state_transition_hash = 2;
+}
packages/dapi-grpc/protos/platform/v0/platform.proto (1)

30-50: Standardize on google.protobuf.Empty for presence-only oneof fields.

The code correctly uses local empty message types (AllEvents, BlockCommitted) to avoid the bool-in-oneof ambiguity issue flagged in prior reviews. However, prefer the standard library pattern for clarity and consistency with proto3 idioms.

Apply this diff:

+import "google/protobuf/empty.proto";
+
 // Criteria that must be met by platform event to be propagated to the user.
 message PlatformFilterV0 {
-  // Include all events generated by the Platform; experimental
-  message AllEvents{}
-  // Notify about every Platform (Tenderdash) block that gets committed (mined)
-  message BlockCommitted{}
-
   // Filter for StateTransitionResult events, by state transition hash
   message StateTransitionResultFilter {
     // When set, only match StateTransitionResult events for this tx hash.
     optional bytes tx_hash = 1;
   }
 
   oneof kind {
-    AllEvents all = 1;             // subscribe to all platform events
-    BlockCommitted block_committed = 2; // subscribe to BlockCommitted events only
+    google.protobuf.Empty all = 1;             // subscribe to all platform events
+    google.protobuf.Empty block_committed = 2; // subscribe to BlockCommitted events only
     StateTransitionResultFilter state_transition_result =
         3; // subscribe to StateTransitionResult events (optionally filtered by
            // tx_hash)
   }
 }
packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (1)

8759-8766: uint64 zero-checks use parseInt(); regenerate from proto definitions.

The parseInt(f, 10) !== 0 checks for uint64 string fields (height, timeMs) contradict proper uint64 handling as strings/BigInt used elsewhere (lines 8718, 8722, 8786-8787, 8804-8805). While the string value is ultimately serialized correctly, the zero-check should compare strings: if (f !== "0").

Since this is generated code from JsPbCodeGenerator, fix the proto generator configuration or proto files and regenerate rather than editing manually.

🧹 Nitpick comments (5)
packages/rs-drive-abci/src/query/service.rs (1)

901-913: LGTM! Subscription logic is well-implemented.

The keepalive validation, handshake flow, and event forwarding logic are correct. The worker task properly handles events, timeouts, and client disconnections.

Optional: Consider periodically removing completed JoinHandles from self.workers to prevent unbounded Vec growth, though the memory overhead is minimal since JoinHandles are lightweight:

// Before pushing new worker at line 1017:
let mut workers = self.workers.lock().unwrap();
workers.retain(|h| !h.is_finished());
workers.push(worker);

This is optional and can be deferred if subscription churn is low.

Also applies to: 921-1020

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (1)

495-501: Document keepalive validation and filtering behavior in proto file

The code correctly validates keepalive bounds (rejects values outside [25, 300] and accepts 0) and always delivers keepalive events regardless of filter kind. However, the proto documentation should be enhanced for clarity.

Suggested proto comment refinement (lines ~9-10 in platform.proto):

// keepalive: interval in seconds (min 25, max 300; 0 disables). The server
// rejects invalid intervals with INVALID_ARGUMENT. Keepalive events are always
// delivered regardless of filter kind.

Note: The review comment proposes "clamps to bounds," but the implementation actually rejects out-of-range values (see rs-drive-abci/src/query/service.rs:908-910), so the documentation should reflect rejection, not clamping.

packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (3)

31-39: keepalive lacks time unit; prefer explicit keepaliveMs.

Ambiguous units create client bugs, especially on the web. Rename to keepalive_ms in proto (surfacing as keepaliveMs here).

Proto-level suggestion:

-message PlatformSubscriptionRequestV0 {
-  PlatformFilterV0 filter = 1;
-  uint32 keepalive = 2;
-}
+message PlatformSubscriptionRequestV0 {
+  PlatformFilterV0 filter = 1;
+  uint32 keepalive_ms = 2; // client ping/expectation interval in milliseconds
+}

85-102: subscriptionId as number risks precision; use string/bytes and consider a cursor.

JS numbers are unsafe > 2^53−1. If this ID can grow or be non-trivial, represent it as string (or bytes). Also consider adding a monotonically increasing cursor to aid reconnection/resume.

Proto-level suggestion:

-message PlatformSubscriptionResponseV0 {
-  uint32 subscription_id = 1;
-  PlatformEventV0 event = 2;
-}
+message PlatformSubscriptionResponseV0 {
+  string subscription_id = 1; // or bytes; stable across cluster shards
+  PlatformEventV0 event = 2;
+  uint64 cursor = 3; // optional: per-stream monotonic sequence for resume
+}

215-231: Optional: include metadata on Keepalive (server interval, deadline).

Empty Keepalive works, but adding fields like interval_ms or deadline_ms can help clients tune heartbeats/timeouts without out-of-band config.

Proto-level idea:

message Keepalive {
  uint32 interval_ms = 1; // server-intended cadence
  uint32 timeout_ms  = 2; // suggest client-side 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 fa042cc and 2293471.

⛔ Files ignored due to path filters (1)
  • packages/dashmate/templates/platform/gateway/envoy.yaml.dot is excluded by !**/*.dot
📒 Files selected for processing (9)
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (3 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m (2 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (1 hunks)
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (3 hunks)
  • packages/dapi-grpc/protos/platform/v0/platform.proto (2 hunks)
  • packages/dashmate/configs/getConfigFileMigrationsFactory.js (4 hunks)
  • packages/dashmate/docs/config/dapi.md (1 hunks)
  • packages/rs-drive-abci/src/query/service.rs (5 hunks)
🧰 Additional context used
📓 Path-based instructions (3)
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/dashmate/configs/getConfigFileMigrationsFactory.js
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js
  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • packages/rs-drive-abci/src/query/service.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-drive-abci/src/query/service.rs
🧠 Learnings (29)
📚 Learning: 2025-10-15T14:45:30.856Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
  • packages/dashmate/docs/config/dapi.md
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.js
📚 Learning: 2025-10-29T10:31:02.449Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2827
File: packages/dashmate/configs/defaults/getBaseConfigFactory.js:254-255
Timestamp: 2025-10-29T10:31:02.449Z
Learning: In dashmate configs (packages/dashmate/configs/defaults/getBaseConfigFactory.js), the `waitForStResultTimeout` for rs-dapi (120000ms / 120s) is intentionally set lower than the gateway listener timeout (125s). This design allows rs-dapi to execute its own timeout handling and return a proper response before the gateway times out, ensuring better error handling.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
  • packages/dashmate/docs/config/dapi.md
📚 Learning: 2024-10-04T09:08:48.470Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2206
File: packages/rs-platform-version/src/version/protocol_version.rs:155-157
Timestamp: 2024-10-04T09:08:48.470Z
Learning: In the dashmate default configurations, the default protocol version for local networks has been removed, and an update mechanism for the protocol version in the consensus parameters has been implemented.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-11-22T10:28:33.588Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2107
File: packages/dashmate/src/listr/tasks/setup/local/configureCoreTaskFactory.js:116-124
Timestamp: 2024-11-22T10:28:33.588Z
Learning: In `configureCoreTaskFactory` in `packages/dashmate/src/listr/tasks/setup/local/configureCoreTaskFactory.js`, the `local_seed` configuration is already established earlier in the code, so adding error handling for its absence in the 'Generating funds to use as a collateral for masternodes' task is unnecessary.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-10-18T15:37:36.387Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2249
File: packages/dashmate/test/unit/status/scopes/platform.spec.js:77-78
Timestamp: 2024-10-18T15:37:36.387Z
Learning: In `packages/dashmate/test/unit/status/scopes/platform.spec.js`, prefer to keep mocks explicitly in tests to increase readability, rather than refactoring them into shared `beforeEach` blocks or helper functions.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-12-10T12:39:38.182Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2381
File: packages/rs-sdk/scripts/connect_to_remote.sh:0-0
Timestamp: 2024-12-10T12:39:38.182Z
Learning: When reviewing scripts in `packages/rs-sdk/scripts/`, avoid suggesting additional error handling and timeout management that complicate the script without adding significant value.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-10-18T15:37:21.329Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2249
File: packages/dashmate/test/unit/status/scopes/platform.spec.js:466-467
Timestamp: 2024-10-18T15:37:21.329Z
Learning: In test files for the dashmate project, such as `packages/dashmate/test/unit/status/scopes/platform.spec.js`, prefer to keep mocks explicitly in tests rather than consolidating them, to increase readability.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-10-06T16:18:07.994Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:119-120
Timestamp: 2024-10-06T16:18:07.994Z
Learning: In the `run_block_proposal` function in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, it's acceptable to pass `platform_state` to `perform_events_on_first_block_of_protocol_change`, even if `block_platform_state` has been updated.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
  • packages/dapi-grpc/protos/platform/v0/platform.proto
📚 Learning: 2024-10-08T13:28:03.529Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-drive-abci/src/platform_types/platform_state/mod.rs:141-141
Timestamp: 2024-10-08T13:28:03.529Z
Learning: When converting `PlatformStateV0` to `PlatformStateForSavingV1` in `packages/rs-drive-abci/src/platform_types/platform_state/mod.rs`, only version `0` needs to be handled in the match on `platform_state_for_saving_structure_default` because the changes are retroactive.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
  • packages/dapi-grpc/protos/platform/v0/platform.proto
📚 Learning: 2025-09-05T06:00:56.491Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2761
File: packages/rs-drive/src/query/filter.rs:268-272
Timestamp: 2025-09-05T06:00:56.491Z
Learning: For document subscription filters in rs-drive, validation should not require index availability checks like queries do. Subscription filtering has different validation requirements than query optimization.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-10T10:30:24.653Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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-drive-abci/src/query/service.rs
📚 Learning: 2025-10-09T15:59:33.162Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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-drive-abci/src/query/service.rs
📚 Learning: 2024-10-29T14:40:54.727Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/src/core/transaction.rs:0-0
Timestamp: 2024-10-29T14:40:54.727Z
Learning: In `packages/rs-sdk/src/platform/document_query.rs` and `packages/rs-sdk/src/core/transaction.rs`, certain places don't implement `IntoInner`, so direct error mappings cannot be simplified using `IntoInner`. A TODO comment has been added to address this in a future PR.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2025-09-12T13:18:08.661Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:18:08.661Z
Learning: Applies to packages/rs-*/**/*.rs : Use PascalCase for Rust types

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-11-03T10:39:11.242Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2305
File: packages/rs-drive-abci/src/abci/handler/finalize_block.rs:81-0
Timestamp: 2024-11-03T10:39:11.242Z
Learning: In `packages/rs-drive-abci/src/abci/handler/finalize_block.rs`, the use of `.expect("commit transaction")` after `app.commit_transaction(platform_version)` is intentional due to the provided comment explaining its necessity. Do not flag this usage in future reviews.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
📚 Learning: 2025-09-12T13:18:08.661Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:18:08.661Z
Learning: Applies to packages/rs-*/**/*.rs : Use SCREAMING_SNAKE_CASE for Rust constants

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-11-20T20:43:41.185Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/tests/strategy_tests/masternodes.rs:212-220
Timestamp: 2024-11-20T20:43:41.185Z
Learning: In `packages/rs-drive-abci/tests/strategy_tests/masternodes.rs`, the pattern of generating a `PrivateKey`, converting it to bytes, and reconstructing a `BlsPrivateKey` from those bytes is intentional. Avoid suggesting to simplify this code in future reviews.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-22T10:53:12.111Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2259
File: packages/rs-dapi-client/src/dapi_client.rs:137-139
Timestamp: 2024-10-22T10:53:12.111Z
Learning: In `packages/rs-dapi-client/src/dapi_client.rs`, when passing data into asynchronous code, ensure that data structures are `Send + Sync`. Using `Arc<AtomicUsize>` is necessary for the retry counter.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-12-05T09:29:38.918Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2375
File: packages/rs-drive-abci/Cargo.toml:61-63
Timestamp: 2024-12-05T09:29:38.918Z
Learning: In the `drive-abci` package, avoid adding unused dependencies like `hashbrown` to `Cargo.toml`. The team relies on CI to detect dependency version issues.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-12-03T15:00:50.385Z
Learnt from: lklimek
Repo: dashpay/platform PR: 1924
File: packages/rs-sdk/src/sdk.rs:855-870
Timestamp: 2024-12-03T15:00:50.385Z
Learning: In `packages/rs-sdk/src/sdk.rs`, remember that `rustls_pemfile::certs` returns an iterator over `Result`, not a `Result` directly. Handle it accordingly in future code reviews.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2025-10-09T15:59:28.329Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2716
File: packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs:181-187
Timestamp: 2025-10-09T15:59:28.329Z
Learning: In `packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs`, the maintainer requires logging full state transition bytes (`tx_bytes = hex::encode(st_bytes)`) at debug level when a state transition passes CheckTx but is removed from the block by the proposer, to facilitate debugging of this rare edge case.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:105-105
Timestamp: 2024-10-09T00:22:57.778Z
Learning: In `run_block_proposal` in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, when retrieving `last_block_time_ms`, it's acceptable to use `platform_state` instead of `block_platform_state`, even after updating the protocol version.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-30T11:04:33.634Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/src/platform/fetch_unproved.rs:0-0
Timestamp: 2024-10-30T11:04:33.634Z
Learning: In `packages/rs-sdk/src/platform/fetch_unproved.rs`, the `execute()` method consumes the request object, so cloning the request is necessary before passing it to `execute()` and `maybe_from_unproved_with_metadata`.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-24T05:00:56.657Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:83-85
Timestamp: 2024-10-24T05:00:56.657Z
Learning: An upcoming filter will be introduced to the `unconfirmed_txs` endpoint in `broadcastStateTransitionHandlerFactory.js`, as noted in the TODO comment. Therefore, optimizing transaction existence checks may not be necessary at this time.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
📚 Learning: 2024-10-03T11:51:06.980Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2201
File: packages/rs-platform-version/src/version/v2.rs:1186-1188
Timestamp: 2024-10-03T11:51:06.980Z
Learning: In the `IdentityTransitionVersions` structure within `packages/rs-platform-version/src/version/v2.rs`, the field `credit_withdrawal` does not need the `identity_` prefix since it is already encompassed within identity state transitions.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h
📚 Learning: 2025-02-03T23:39:10.579Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2450
File: packages/rs-dpp/src/data_contract/associated_token/token_perpetual_distribution/v0/methods.rs:10-12
Timestamp: 2025-02-03T23:39:10.579Z
Learning: Block interval calculations in token distribution logic should use checked arithmetic operations (checked_sub, checked_add) to prevent potential overflows, especially when dealing with block heights and intervals.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
📚 Learning: 2024-10-25T09:33:50.383Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2274
File: packages/js-dapi-client/lib/transport/GrpcTransport/createGrpcTransportError.js:127-127
Timestamp: 2024-10-25T09:33:50.383Z
Learning: In `createGrpcTransportError.js`, the size of consensus error data is already validated by gRPC transport, so adding an additional size check before base64 decoding in the `createGrpcTransportError` function is unnecessary.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
📚 Learning: 2025-10-09T15:59:18.338Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2716
File: packages/wallet-lib/src/plugins/Workers/TransactionsSyncWorker/TransactionsReader.js:325-334
Timestamp: 2025-10-09T15:59:18.338Z
Learning: In `packages/wallet-lib/src/plugins/Workers/TransactionsSyncWorker/TransactionsReader.js`, the continuous sync restart intentionally uses `Math.max(1, lastSyncedBlockHeight)` rather than `lastSyncedBlockHeight + 1` because the last block's processing status is uncertain at restart time. This conservative approach ensures no blocks are missed by reprocessing the last synced block, accepting potential duplicate processing for data completeness.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js
📚 Learning: 2024-10-24T04:59:20.436Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2270
File: packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js:75-77
Timestamp: 2024-10-24T04:59:20.436Z
Learning: Tenderdash's `tx` RPC method accepts transaction hashes in base64 encoding, or in hex encoding if prefixed with `0x`. Therefore, in `packages/dapi/lib/grpcServer/handlers/platform/broadcastStateTransitionHandlerFactory.js`, it's acceptable to use `stHash.toString('base64')` when calling `requestTenderRpc('tx', { hash: stHash.toString('base64') })`.

Applied to files:

  • packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts
🧬 Code graph analysis (5)
packages/dashmate/configs/getConfigFileMigrationsFactory.js (1)
packages/dapi-grpc/clients/platform/v0/python/platform_pb2_grpc.py (4)
  • waitForStateTransitionResult (364-368)
  • waitForStateTransitionResult (1103-1117)
  • subscribePlatformEvents (549-558)
  • subscribePlatformEvents (1613-1627)
packages/rs-drive-abci/src/query/service.rs (4)
packages/rs-drive-abci/src/abci/app/full.rs (3)
  • platform (48-50)
  • event_bus (60-62)
  • new (37-44)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (10)
  • Keepalive (333-342)
  • PlatformEventV0 (215-240)
  • PlatformSubscriptionRequest (9-24)
  • PlatformSubscriptionResponse (63-78)
  • PlatformFilterV0 (117-142)
  • BlockCommitted (167-176)
  • BlockCommitted (279-296)
  • StateTransitionFinalized (305-324)
  • Version (5947-5966)
  • PlatformSubscriptionResponseV0 (85-102)
packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs (3)
  • mpsc (46-48)
  • drop (24-26)
  • new (17-20)
packages/rs-dash-event-bus/src/event_bus.rs (5)
  • mpsc (96-96)
  • drop (261-286)
  • new (76-78)
  • matches (16-16)
  • matches (430-432)
packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (1)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.d.ts (2)
  • PlatformEventV0 (215-240)
  • PlatformFilterV0 (117-142)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (4)
packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (1)
  • proto (16-16)
packages/js-dapi-client/test/unit/methods/platform/getStatus/GetStatusResponse.spec.js (1)
  • proto (18-18)
packages/dapi-grpc/clients/drive/v0/nodejs/drive_protoc.js (1)
  • proto (16-16)
packages/dapi-grpc/clients/drive/v0/web/drive_pb.js (1)
  • proto (16-16)
packages/dapi-grpc/clients/platform/v0/nodejs/platform_protoc.js (3)
packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (1)
  • proto (16-16)
packages/dapi-grpc/clients/drive/v0/nodejs/drive_protoc.js (1)
  • proto (16-16)
packages/dapi-grpc/clients/drive/v0/web/drive_pb.js (1)
  • proto (16-16)
⏰ 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). (11)
  • GitHub Check: Rust packages (dapi-grpc) / Check each feature
  • GitHub Check: Rust packages (drive-abci) / Check each feature
  • GitHub Check: Rust packages (drive-abci) / Linting
  • 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 (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 JS packages / Build JS
  • GitHub Check: Rust crates security audit
  • GitHub Check: Swift SDK and Example build (warnings as errors)
🔇 Additional comments (18)
packages/dashmate/configs/getConfigFileMigrationsFactory.js (5)

1167-1175: LGTM: Deprecated config initialization.

This correctly initializes the deprecated configuration structure from defaults in preparation for migration. The logic properly handles both missing structure and missing enabled flag scenarios.


1336-1367: LGTM: Clean migration of legacy configuration.

The logic correctly:

  • Removes the deprecated marker added in earlier migrations
  • Derives rsDapi.maxRequests from the maximum of legacy dapiApi and dapiCoreStreams values
  • Falls back to defaults when legacy values are unavailable
  • Cleans up obsolete upstream keys

1373-1389: LGTM: Proper legacy configuration extraction.

The code correctly:

  • Ensures rsDapi exists by cloning from defaults when missing
  • Extracts legacy timeout values before deleting the old structure
  • Removes the deprecated options.platform.dapi.api configuration

1391-1421: LGTM: Docker alignment and timeout structure normalization.

The migration properly:

  • Aligns docker images with current defaults
  • Consolidates timeouts into a unified structure with proper fallback chain (existing → legacy → defaults)
  • Introduces three distinct timeout settings for different operations
  • Cleans up the legacy waitForStResultTimeout field from rsDapi

1431-1433: LGTM: Gateway listener timeout cleanup.

Correctly removes the legacy waitForStResultTimeout from the gateway listener configuration.

packages/dashmate/docs/config/dapi.md (1)

42-44: LGTM: Clear and accurate timeout documentation.

The documentation correctly describes the three new timeout options introduced in this PR:

  • waitForStateTransitionResult (renamed from the old waitForStResultTimeout)
  • subscribePlatformEvents (new feature for platform event subscriptions)
  • coreStreams (for Core streaming subscriptions)

The default values match those specified in the migration code, and the descriptions clearly explain the purpose of each timeout.

packages/rs-drive-abci/src/query/service.rs (5)

66-66: LGTM! Constant naming and struct fields are correct.

The constant follows SCREAMING_SNAKE_CASE convention, and the new fields properly support event subscription infrastructure.

Also applies to: 71-74


76-83: LGTM! Proper cleanup of background workers.

The Drop implementation correctly aborts all worker tasks when the service is dropped, preventing resource leaks.


94-103: LGTM! Constructor properly initializes new fields.

The updated signature and initialization correctly set up the event bus and worker tracking.


281-320: LGTM! PlatformFilterAdapter implementation is correct.

The filter matching logic properly handles all filter types (All, BlockCommitted, StateTransitionResult) and ensures keepalive events are always delivered to all subscriptions.


894-899: LGTM! Filter validation prevents silent no-op subscriptions.

The validation ensures filter.kind is specified before creating a subscription, providing clear error feedback to clients. This properly addresses the earlier concern about silent failures.

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.h (1)

595-598: Grammar fix acknowledged

“gets committed” is corrected. Thanks for addressing.

packages/dapi-grpc/protos/platform/v0/platform.proto (3)

9-28: Message structure and versioning look good. Request/response wrappers follow the established versioning pattern in the file, with clear field documentation. The keepalive interval bounds (min 25s, max 300s, 0 disables) are properly documented.


52-76: Event message structure is well-designed. Nested messages provide clear separation of concerns, and jstype = JS_STRING annotations properly handle 64-bit integer serialization for JavaScript clients. The oneof discriminator correctly selects among the three event types (BlockCommitted, StateTransitionFinalized, Keepalive).


177-183: RPC comment and signature are aligned. The comment correctly describes this as a server-streaming RPC (not bi-directional), which aligns with the returns (stream ...) signature and resolves the prior mismatch. The handshake semantics ("Once connected, it sends handshake response with empty event") are clear. Prior typo and formatting issues have also been resolved.

packages/dapi-grpc/clients/platform/v0/web/platform_pb.js (1)

463-9456: Generated protobuf code looks correct.

This file contains auto-generated JavaScript code from protobuf definitions. The new message types (PlatformSubscriptionRequest, PlatformSubscriptionResponse, PlatformFilterV0, PlatformEventV0) and their implementations follow standard protobuf JS patterns:

  • Google Closure exports and inheritance setup
  • Standard oneof group handling
  • Consistent (de)serialization logic
  • Proper getter/setter/clear/has accessor methods

Any modifications to these message structures should be made in the source .proto files (likely packages/dapi-grpc/protos/platform/v0/platform.proto) and then regenerated, not edited directly in this file.

packages/dapi-grpc/clients/platform/v0/objective-c/Platform.pbobjc.m (2)

320-332: LGTM - Generated protobuf class declarations.

The forward declarations for the new platform event subscription classes follow the standard Google Protocol Buffers pattern for Objective-C and are correctly positioned in the file.


409-1121: LGTM - Well-formed protobuf descriptor implementations.

The descriptor implementations for the platform event subscription infrastructure are correctly generated:

  • Thread-safe lazy initialization with static descriptors
  • Proper field descriptions with correct types, offsets, and flags
  • Oneof groups correctly configured with clear helper functions
  • Nested message relationships properly established
  • Storage structs appropriately sized and aligned

All patterns are consistent with Google Protocol Buffers conventions for Objective-C.

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 (2)
packages/dapi-grpc/protos/platform/v0/platform.proto (1)

30-50: Consider using standard google.protobuf.Empty for presence-only variants.

The code defines custom empty message types locally (AllEvents, BlockCommitted, Keepalive). While functionally equivalent and correct, using the standard library google.protobuf.Empty would be more idiomatic and reduce boilerplate. The file already imports other google.protobuf types.

Proposed change:

+import "google/protobuf/empty.proto";

 message PlatformFilterV0 {
-  message AllEvents{}
-  message BlockCommitted{}
+  // Remove local empty messages; use google.protobuf.Empty instead
 
   message StateTransitionResultFilter {
     optional bytes tx_hash = 1;
   }
 
   oneof kind {
-    AllEvents all = 1;
-    BlockCommitted block_committed = 2;
+    google.protobuf.Empty all = 1;
+    google.protobuf.Empty block_committed = 2;
     StateTransitionResultFilter state_transition_result = 3;
   }
 }

 message PlatformEventV0 {
   // ... existing messages ...
-  message Keepalive {}
+  // Use google.protobuf.Empty for keepalive
 
   oneof event {
     BlockCommitted block_committed = 1;
     StateTransitionFinalized state_transition_finalized = 2;
-    Keepalive keepalive = 3;
+    google.protobuf.Empty keepalive = 3;
   }
 }
packages/rs-drive-abci/src/query/service.rs (1)

915-915: [CRITICAL] Add missing rand import.

Line 915 uses rand::random::<u64>() but rand is not imported in this file. While rand is declared in Cargo.toml, Rust requires an explicit import to use it.

Add the import at the top of the file:

+use rand::random;

Then update line 915:

-        let subscription_id = rand::random::<u64>();
+        let subscription_id = random::<u64>();

Or alternatively, import the crate and keep the full path:

+use rand;

(The existing line 915 will then compile as-is)

🧹 Nitpick comments (1)
packages/rs-drive-abci/src/query/service.rs (1)

1018-1026: LGTM: Worker lifecycle management.

The worker management strategy is sound:

  • Spawned tasks are tracked in the workers vector
  • retain() removes finished tasks on each new subscription (prevents memory leak)
  • The Drop impl ensures all workers are aborted when QueryService is dropped

Optional: Consider running cleanup more frequently (e.g., via a periodic background task) if you expect many short-lived subscriptions. However, the current approach is acceptable since cleanup happens on each new subscription and at Drop time.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2293471 and ddb66d7.

⛔ Files ignored due to path filters (1)
  • packages/dashmate/templates/platform/gateway/envoy.yaml.dot is excluded by !**/*.dot
📒 Files selected for processing (5)
  • packages/dapi-grpc/protos/platform/v0/platform.proto (2 hunks)
  • packages/dashmate/configs/getConfigFileMigrationsFactory.js (4 hunks)
  • packages/dashmate/docs/services/gateway.md (1 hunks)
  • packages/rs-drive-abci/src/query/service.rs (5 hunks)
  • packages/rs-sdk/src/platform/events.rs (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/rs-sdk/src/platform/events.rs
🧰 Additional context used
📓 Path-based instructions (3)
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/dashmate/configs/getConfigFileMigrationsFactory.js
**/*.rs

📄 CodeRabbit inference engine (CLAUDE.md)

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

Files:

  • packages/rs-drive-abci/src/query/service.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-drive-abci/src/query/service.rs
🧠 Learnings (24)
📚 Learning: 2025-10-15T14:45:30.856Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
  • packages/dashmate/docs/services/gateway.md
📚 Learning: 2025-10-29T10:31:02.449Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2827
File: packages/dashmate/configs/defaults/getBaseConfigFactory.js:254-255
Timestamp: 2025-10-29T10:31:02.449Z
Learning: In dashmate configs (packages/dashmate/configs/defaults/getBaseConfigFactory.js), the `waitForStResultTimeout` for rs-dapi (120000ms / 120s) is intentionally set lower than the gateway listener timeout (125s). This design allows rs-dapi to execute its own timeout handling and return a proper response before the gateway times out, ensuring better error handling.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
  • packages/dashmate/docs/services/gateway.md
📚 Learning: 2024-10-04T09:08:48.470Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2206
File: packages/rs-platform-version/src/version/protocol_version.rs:155-157
Timestamp: 2024-10-04T09:08:48.470Z
Learning: In the dashmate default configurations, the default protocol version for local networks has been removed, and an update mechanism for the protocol version in the consensus parameters has been implemented.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-11-22T10:28:33.588Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2107
File: packages/dashmate/src/listr/tasks/setup/local/configureCoreTaskFactory.js:116-124
Timestamp: 2024-11-22T10:28:33.588Z
Learning: In `configureCoreTaskFactory` in `packages/dashmate/src/listr/tasks/setup/local/configureCoreTaskFactory.js`, the `local_seed` configuration is already established earlier in the code, so adding error handling for its absence in the 'Generating funds to use as a collateral for masternodes' task is unnecessary.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-10-18T15:37:36.387Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2249
File: packages/dashmate/test/unit/status/scopes/platform.spec.js:77-78
Timestamp: 2024-10-18T15:37:36.387Z
Learning: In `packages/dashmate/test/unit/status/scopes/platform.spec.js`, prefer to keep mocks explicitly in tests to increase readability, rather than refactoring them into shared `beforeEach` blocks or helper functions.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-12-10T12:39:38.182Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2381
File: packages/rs-sdk/scripts/connect_to_remote.sh:0-0
Timestamp: 2024-12-10T12:39:38.182Z
Learning: When reviewing scripts in `packages/rs-sdk/scripts/`, avoid suggesting additional error handling and timeout management that complicate the script without adding significant value.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-10-18T15:37:21.329Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2249
File: packages/dashmate/test/unit/status/scopes/platform.spec.js:466-467
Timestamp: 2024-10-18T15:37:21.329Z
Learning: In test files for the dashmate project, such as `packages/dashmate/test/unit/status/scopes/platform.spec.js`, prefer to keep mocks explicitly in tests rather than consolidating them, to increase readability.

Applied to files:

  • packages/dashmate/configs/getConfigFileMigrationsFactory.js
📚 Learning: 2024-10-19T06:10:00.808Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2255
File: packages/dashmate/src/status/scopes/platform.js:112-116
Timestamp: 2024-10-19T06:10:00.808Z
Learning: In the Dashmate project, when fetching from Tenderdash RPC endpoints like `/status`, `/net_info`, and `/abci_info`, if one request fails, it's likely that the others will fail as well, so individual error handling for each fetch may not be necessary.

Applied to files:

  • packages/dashmate/docs/services/gateway.md
📚 Learning: 2024-10-06T16:18:07.994Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:119-120
Timestamp: 2024-10-06T16:18:07.994Z
Learning: In the `run_block_proposal` function in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, it's acceptable to pass `platform_state` to `perform_events_on_first_block_of_protocol_change`, even if `block_platform_state` has been updated.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
  • packages/dapi-grpc/protos/platform/v0/platform.proto
📚 Learning: 2024-10-08T13:28:03.529Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2227
File: packages/rs-drive-abci/src/platform_types/platform_state/mod.rs:141-141
Timestamp: 2024-10-08T13:28:03.529Z
Learning: When converting `PlatformStateV0` to `PlatformStateForSavingV1` in `packages/rs-drive-abci/src/platform_types/platform_state/mod.rs`, only version `0` needs to be handled in the match on `platform_state_for_saving_structure_default` because the changes are retroactive.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
  • packages/dapi-grpc/protos/platform/v0/platform.proto
📚 Learning: 2025-09-05T06:00:56.491Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2761
File: packages/rs-drive/src/query/filter.rs:268-272
Timestamp: 2025-09-05T06:00:56.491Z
Learning: For document subscription filters in rs-drive, validation should not require index availability checks like queries do. Subscription filtering has different validation requirements than query optimization.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-10T10:30:24.653Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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-drive-abci/src/query/service.rs
📚 Learning: 2025-10-09T15:59:33.162Z
Learnt from: lklimek
Repo: dashpay/platform PR: 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-drive-abci/src/query/service.rs
📚 Learning: 2024-10-29T14:40:54.727Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/src/core/transaction.rs:0-0
Timestamp: 2024-10-29T14:40:54.727Z
Learning: In `packages/rs-sdk/src/platform/document_query.rs` and `packages/rs-sdk/src/core/transaction.rs`, certain places don't implement `IntoInner`, so direct error mappings cannot be simplified using `IntoInner`. A TODO comment has been added to address this in a future PR.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2025-09-12T13:18:08.661Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:18:08.661Z
Learning: Applies to packages/rs-*/**/*.rs : Use PascalCase for Rust types

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-11-03T10:39:11.242Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2305
File: packages/rs-drive-abci/src/abci/handler/finalize_block.rs:81-0
Timestamp: 2024-11-03T10:39:11.242Z
Learning: In `packages/rs-drive-abci/src/abci/handler/finalize_block.rs`, the use of `.expect("commit transaction")` after `app.commit_transaction(platform_version)` is intentional due to the provided comment explaining its necessity. Do not flag this usage in future reviews.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2025-09-12T13:18:08.661Z
Learnt from: CR
Repo: dashpay/platform PR: 0
File: AGENTS.md:0-0
Timestamp: 2025-09-12T13:18:08.661Z
Learning: Applies to packages/rs-*/**/*.rs : Use SCREAMING_SNAKE_CASE for Rust constants

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-11-20T20:43:41.185Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2257
File: packages/rs-drive-abci/tests/strategy_tests/masternodes.rs:212-220
Timestamp: 2024-11-20T20:43:41.185Z
Learning: In `packages/rs-drive-abci/tests/strategy_tests/masternodes.rs`, the pattern of generating a `PrivateKey`, converting it to bytes, and reconstructing a `BlsPrivateKey` from those bytes is intentional. Avoid suggesting to simplify this code in future reviews.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-22T10:53:12.111Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2259
File: packages/rs-dapi-client/src/dapi_client.rs:137-139
Timestamp: 2024-10-22T10:53:12.111Z
Learning: In `packages/rs-dapi-client/src/dapi_client.rs`, when passing data into asynchronous code, ensure that data structures are `Send + Sync`. Using `Arc<AtomicUsize>` is necessary for the retry counter.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-12-03T15:00:50.385Z
Learnt from: lklimek
Repo: dashpay/platform PR: 1924
File: packages/rs-sdk/src/sdk.rs:855-870
Timestamp: 2024-12-03T15:00:50.385Z
Learning: In `packages/rs-sdk/src/sdk.rs`, remember that `rustls_pemfile::certs` returns an iterator over `Result`, not a `Result` directly. Handle it accordingly in future code reviews.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-12-05T09:29:38.918Z
Learnt from: shumkov
Repo: dashpay/platform PR: 2375
File: packages/rs-drive-abci/Cargo.toml:61-63
Timestamp: 2024-12-05T09:29:38.918Z
Learning: In the `drive-abci` package, avoid adding unused dependencies like `hashbrown` to `Cargo.toml`. The team relies on CI to detect dependency version issues.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2025-10-09T15:59:28.329Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2716
File: packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs:181-187
Timestamp: 2025-10-09T15:59:28.329Z
Learning: In `packages/rs-dapi/src/services/platform_service/broadcast_state_transition.rs`, the maintainer requires logging full state transition bytes (`tx_bytes = hex::encode(st_bytes)`) at debug level when a state transition passes CheckTx but is removed from the block by the proposer, to facilitate debugging of this rare edge case.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-09T00:22:57.778Z
Learnt from: QuantumExplorer
Repo: dashpay/platform PR: 2215
File: packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs:105-105
Timestamp: 2024-10-09T00:22:57.778Z
Learning: In `run_block_proposal` in `packages/rs-drive-abci/src/execution/engine/run_block_proposal/mod.rs`, when retrieving `last_block_time_ms`, it's acceptable to use `platform_state` instead of `block_platform_state`, even after updating the protocol version.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
📚 Learning: 2024-10-30T11:04:33.634Z
Learnt from: lklimek
Repo: dashpay/platform PR: 2277
File: packages/rs-sdk/src/platform/fetch_unproved.rs:0-0
Timestamp: 2024-10-30T11:04:33.634Z
Learning: In `packages/rs-sdk/src/platform/fetch_unproved.rs`, the `execute()` method consumes the request object, so cloning the request is necessary before passing it to `execute()` and `maybe_from_unproved_with_metadata`.

Applied to files:

  • packages/rs-drive-abci/src/query/service.rs
🧬 Code graph analysis (1)
packages/rs-drive-abci/src/query/service.rs (5)
packages/rs-drive-abci/src/abci/app/full.rs (3)
  • platform (48-50)
  • event_bus (60-62)
  • new (37-44)
packages/rs-drive-abci/src/abci/app/consensus.rs (3)
  • platform (51-53)
  • event_bus (63-65)
  • new (37-47)
packages/rs-drive-abci/src/abci/app/mod.rs (2)
  • platform (32-32)
  • event_bus (24-26)
packages/rs-dapi/src/services/platform_service/subscribe_platform_events.rs (3)
  • mpsc (46-48)
  • drop (24-26)
  • new (17-20)
packages/rs-sdk/src/platform/events.rs (1)
  • subscribe_platform_events (17-61)
🪛 markdownlint-cli2 (0.18.1)
packages/dashmate/docs/services/gateway.md

109-109: Inconsistent indentation for list items at the same level
Expected: 0; Actual: 1

(MD005, list-indent)


109-109: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


110-110: Inconsistent indentation for list items at the same level
Expected: 0; Actual: 1

(MD005, list-indent)


110-110: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


111-111: Inconsistent indentation for list items at the same level
Expected: 0; Actual: 1

(MD005, list-indent)


111-111: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


112-112: Inconsistent indentation for list items at the same level
Expected: 0; Actual: 1

(MD005, list-indent)


112-112: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

⏰ 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). (16)
  • GitHub Check: Rust packages (wasm-sdk) / Linting
  • GitHub Check: Rust packages (wasm-sdk) / Unused dependencies
  • GitHub Check: Rust packages (wasm-sdk) / Formatting
  • GitHub Check: Rust packages (rs-sdk-ffi) / Tests
  • GitHub Check: Rust packages (dash-sdk) / Linting
  • GitHub Check: Rust packages (dash-sdk) / Check each feature
  • GitHub Check: Rust packages (dash-sdk) / Unused dependencies
  • GitHub Check: Rust packages (dash-sdk) / Tests
  • 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 JS packages / Build JS
  • GitHub Check: Rust crates security audit
  • 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)
🔇 Additional comments (19)
packages/dapi-grpc/protos/platform/v0/platform.proto (3)

43-50: Critical issue resolved: bool-in-oneof footgun eliminated.

The previous footgun of using bool inside oneof has been correctly eliminated by using empty message types (AllEvents, BlockCommitted). This ensures proper presence semantics across language implementations.


177-183: Well-documented server-streaming RPC with clear handshake semantics.

The RPC comment correctly describes the server-streaming nature (not bi-directional), aligns with gRPC-Web limitations noted in PR discussions, and the handshake mechanism is well-explained. The signature properly matches a server-streaming subscription pattern suitable for web clients.


52-76: Event hierarchy is well-structured with appropriate JS compatibility markers.

PlatformEventV0 and nested types (BlockMetadata, BlockCommitted, StateTransitionFinalized) are cleanly organized. The use of jstype = JS_STRING on 64-bit fields (lines 54–55) correctly addresses JavaScript number precision limits. Empty Keepalive message is appropriate for connection liveness.

packages/dashmate/docs/services/gateway.md (1)

106-106: LGTM: Clear explanation of timeout behavior.

The description accurately explains the shared timeout model between rs-dapi and Envoy, and clearly documents the five-second grace period for structured error responses.

packages/dashmate/configs/getConfigFileMigrationsFactory.js (8)

1167-1175: LGTM: Proper initialization of deprecated marker.

This block correctly initializes the deprecated marker from defaults before it's removed later in the migration. The nested conditional logic properly handles both missing objects and undefined properties.


1336-1339: LGTM: Clean removal of deprecated DAPI marker.

This correctly removes the legacy deprecated marker after it's been used for migration purposes.


1341-1367: LGTM: Thoughtful consolidation of legacy upstreams.

The migration correctly consolidates the old dapiApi and dapiCoreStreams upstreams into a single rsDapi upstream by taking the maximum of their maxRequests values. The fallback to defaults when no valid values exist is appropriate.


1369-1371: LGTM: Appropriate guard clause.

This guard correctly protects the subsequent DAPI-specific migration logic when the DAPI configuration doesn't exist.


1373-1376: LGTM: Proper initialization with early return.

This correctly initializes rsDapi from defaults for configs that don't have it yet, with an early return to skip unnecessary transformation logic.


1378-1389: LGTM: Proper extraction of legacy timeout values.

This block correctly extracts timeout values from the legacy api section before deleting it, preserving both the old waitForStResultTimeout field and the timeouts object for migration to the new structure.


1391-1400: LGTM: Standard docker image updates.

The docker image updates follow the established pattern used throughout this migration file, with proper existence checks before accessing nested properties.


1402-1425: LGTM: Comprehensive timeout normalization and cleanup.

This block correctly normalizes the timeout structure by:

  1. Computing each timeout value from multiple potential sources using proper fallback chains with the ?? operator
  2. Creating a clean, unified rsDapi.timeouts object with exactly three properties
  3. Removing all legacy timeout fields from both rsDapi and the gateway listener

The fallback logic properly handles undefined values at each level, ensuring defaults are used when legacy values are missing.

packages/rs-drive-abci/src/query/service.rs (7)

13-13: LGTM: Imports and constant.

The new imports support event bus integration and streaming. The buffer size of 128 is reasonable for platform event streams.

Also applies to: 51-51, 55-55, 59-59, 62-66


71-83: LGTM: Worker cleanup via Drop.

The Drop implementation properly aborts all background workers, preventing resource leaks when QueryService is dropped. Using Vec<JoinHandle> with explicit cleanup addresses the previous concern about task accumulation.


94-103: LGTM: Constructor updated.

The constructor properly accepts and stores the event_bus parameter, and initializes the workers vector.


281-320: LGTM: Filter adapter implementation.

The PlatformFilterAdapter correctly implements EventBusFilter semantics:

  • Keepalive events always pass through (essential for the keepalive mechanism)
  • Filter variants (All, BlockCommitted, StateTransitionResult) are properly matched
  • Optional tx_hash filtering for StateTransitionResult is correctly handled

894-913: LGTM: Request validation.

The validation logic properly handles:

  • Filter kind requirement (addresses previous review comment)
  • Keepalive interval range (25-300 seconds) with appropriate error messages
  • Zero keepalive value to disable keepalive

930-947: LGTM: Handshake pattern.

The handshake message (empty event with subscription_id) confirms subscription creation to the client before streaming events. Error handling for client disconnection during handshake is appropriate.


949-1016: LGTM: Event forwarding worker.

The worker implementation correctly:

  • Uses tokio::time::timeout to implement keepalive intervals
  • Forwards events when received
  • Emits keepalive events when timeout elapses
  • Handles stream closure gracefully
  • Logs disconnection and completion

Comment on lines +109 to +112
- Core streaming endpoints: derived from `platform.dapi.rsDapi.timeouts.coreStreams` (default 600 000 ms)
- waitForStateTransitionResult endpoint: derived from `platform.dapi.rsDapi.timeouts.waitForStateTransitionResult` (default 120 000 ms)
- subscribePlatformEvents endpoint: derived from `platform.dapi.rsDapi.timeouts.subscribePlatformEvents` (default 600 000 ms)
- All streaming routes share a fixed Envoy `idle_timeout` of 300s so that connections can stay open while rs-dapi manages its own deadlines.
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

Fix markdown indentation for list items.

These bullet points have 1 space of indentation when they should have 0. They are top-level list items, not nested items.

Apply this diff to fix the indentation:

-- Core streaming endpoints: derived from `platform.dapi.rsDapi.timeouts.coreStreams` (default 600 000 ms)
-- waitForStateTransitionResult endpoint: derived from `platform.dapi.rsDapi.timeouts.waitForStateTransitionResult` (default 120 000 ms)
-- subscribePlatformEvents endpoint: derived from `platform.dapi.rsDapi.timeouts.subscribePlatformEvents` (default 600 000 ms)
-- All streaming routes share a fixed Envoy `idle_timeout` of 300s so that connections can stay open while rs-dapi manages its own deadlines.
+- Core streaming endpoints: derived from `platform.dapi.rsDapi.timeouts.coreStreams` (default 600 000 ms)
+- waitForStateTransitionResult endpoint: derived from `platform.dapi.rsDapi.timeouts.waitForStateTransitionResult` (default 120 000 ms)
+- subscribePlatformEvents endpoint: derived from `platform.dapi.rsDapi.timeouts.subscribePlatformEvents` (default 600 000 ms)
+- All streaming routes share a fixed Envoy `idle_timeout` of 300s so that connections can stay open while rs-dapi manages its own deadlines.
📝 Committable suggestion

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

Suggested change
- Core streaming endpoints: derived from `platform.dapi.rsDapi.timeouts.coreStreams` (default 600000ms)
- waitForStateTransitionResult endpoint: derived from `platform.dapi.rsDapi.timeouts.waitForStateTransitionResult` (default 120000ms)
- subscribePlatformEvents endpoint: derived from `platform.dapi.rsDapi.timeouts.subscribePlatformEvents` (default 600000ms)
- All streaming routes share a fixed Envoy `idle_timeout` of 300s so that connections can stay open while rs-dapi manages its own deadlines.
- Core streaming endpoints: derived from `platform.dapi.rsDapi.timeouts.coreStreams` (default 600 000 ms)
- waitForStateTransitionResult endpoint: derived from `platform.dapi.rsDapi.timeouts.waitForStateTransitionResult` (default 120 000 ms)
- subscribePlatformEvents endpoint: derived from `platform.dapi.rsDapi.timeouts.subscribePlatformEvents` (default 600 000 ms)
- All streaming routes share a fixed Envoy `idle_timeout` of 300s so that connections can stay open while rs-dapi manages its own deadlines.
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

109-109: Inconsistent indentation for list items at the same level
Expected: 0; Actual: 1

(MD005, list-indent)


109-109: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


110-110: Inconsistent indentation for list items at the same level
Expected: 0; Actual: 1

(MD005, list-indent)


110-110: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


111-111: Inconsistent indentation for list items at the same level
Expected: 0; Actual: 1

(MD005, list-indent)


111-111: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)


112-112: Inconsistent indentation for list items at the same level
Expected: 0; Actual: 1

(MD005, list-indent)


112-112: Unordered list indentation
Expected: 0; Actual: 1

(MD007, ul-indent)

🤖 Prompt for AI Agents
In packages/dashmate/docs/services/gateway.md around lines 109 to 112, the four
bullet list items are incorrectly indented with a leading space; remove that
single leading space for each line so they are top-level list items (no
indentation) and ensure Markdown renders them as a primary list.

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.

3 participants