Skip to content

feat(sdk): prefer DAPI peers supporting the client's latest protocol version - #4221

Draft
QuantumExplorer wants to merge 6 commits into
v4.2-devfrom
claude/protocol-version-peer-startup-d02997
Draft

feat(sdk): prefer DAPI peers supporting the client's latest protocol version#4221
QuantumExplorer wants to merge 6 commits into
v4.2-devfrom
claude/protocol-version-peer-startup-d02997

Conversation

@QuantumExplorer

@QuantumExplorerQuantumExplorer commented Jul 24, 2026

Copy link
Copy Markdown
Member

Issue being fixed or feature implemented

When a client (rs-sdk / platform wallet / mobile bindings) connects to DAPI, peer selection is uniformly random over all live addresses. Nodes running older software may not support the client's newest protocol version, which can degrade behavior for version-sensitive flows. On startup the client should make a best effort to talk to peers whose software already supports (i.e. desires/votes for) the client's latest protocol version.

What was done?

  • rs-dapi-client: AddressList now tracks, per address, the highest protocol version the node reports supporting, plus an optional preferred-version target shared across clones. get_live_address picks randomly among live peers whose reported version is at least the preferred one, and falls back to any live peer when none match — no peer is ever excluded by version alone, and version knowledge survives unban (health and version are orthogonal).
  • rs-sdk: new Sdk::prefer_peers_with_latest_protocol_version() concurrently issues an unproven getStatus to every live peer (4 s per-node timeout, no retries, no banning), records each node's version.protocol.drive.latest, and sets the preference target to PlatformVersion::latest().protocol_version (the client's newest supported version). Probe failures leave the peer in rotation, unranked.
  • The probe is wired into Sdk::refresh_protocol_version() — the documented app-start / network-switch hook — so rs-sdk-ffi (Swift), the JNI bindings (Kotlin), and any caller of refresh get the behavior with no binding changes. It runs even for pinned or proofs-disabled SDKs (peer preference is orthogonal to version pinning); the proven version-ratchet path is unchanged and the unproven probe never feeds it.

How Has This Been Tested?

  • New unit tests in rs-dapi-client covering: preference targeting (>= semantics, newer peers count as preferred), best-effort fallback when no peer matches, ban filtering taking precedence over preference, version knowledge surviving unban, and preference propagation across AddressList clones.
  • cargo test -p rs-dapi-client and cargo test -p dash-sdk --lib pass; cargo clippy --all-targets clean on both crates; rs-sdk-ffi and wasm-sdk (wasm32-unknown-unknown) still compile.

Breaking Changes

None — all API additions are backward compatible, and with no preference set peer selection behaves exactly as before.

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

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Improved peer selection by preferring live nodes that support the latest protocol version.
    • Added protocol-version preference and per-peer capability tracking, preserved across unbans.
    • Added an SDK method to proactively prefer compatible peers.
  • Bug Fixes
    • Banned peers are excluded, with fallback to other live peers when needed.
    • Peer sampling now returns bounded, distinct, non-banned addresses.
  • Documentation
    • Clarified bounded peer probing, fallback behavior, ignored probe failures, and blocking requirements during protocol refresh.

@github-actionsgithub-actionsBot added this to the v4.1.0 milestone Jul 24, 2026
@thepastaclaw

thepastaclaw commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

✅ Final review complete — no blockers (commit 3709c6c)

@coderabbitai

coderabbitaiBot commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@QuantumExplorer, you've reached your PR review limit, so we couldn't start this review.

Next review available in:53 minutes

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 96948ccf-ec9a-4bfb-8861-ae9231530f2a

📥 Commits

Reviewing files that changed from the base of the PR and between 0d2a3e1 and 3709c6c.

📒 Files selected for processing (1)
  • packages/rs-sdk/src/sdk.rs
📝 Walkthrough

Walkthrough

The change records supported protocol versions for peers, biases live-address selection toward the configured version, and adds bounded concurrent peer probing before SDK protocol-version refresh logic. Probe failures do not change the stored protocol-version ratchet.

Changes

Protocol-aware peer selection

Layer / File(s)Summary
Address protocol metadata and selection
packages/rs-dapi-client/src/address_list.rs, packages/rs-dapi-client/Cargo.toml
AddressStatus preserves supported protocol versions across unban. AddressList exposes shared preference APIs, weighted live-peer selection, bounded distinct sampling, and fallback behavior. Tests cover these paths.
Peer protocol probing
packages/rs-sdk/src/sdk.rs
The SDK samples live peers and performs bounded concurrent unproven status requests. It records reported versions, sets the latest version as preferred, ignores failures, and counts supporting peers.
Refresh flow and API documentation
packages/rs-sdk/src/sdk.rs, packages/rs-sdk-ffi/..., packages/rs-unified-sdk-jni/..., packages/kotlin-sdk/..., packages/swift-sdk/...
Protocol refresh runs the peer probe before proven refresh handling, including pinned and proofs-disabled cases. Platform documentation describes the probe, blocking behavior, fallback selection, and pinned-version handling.

Estimated code review effort: 4 (Complex) | ~45 minutes

Suggested reviewers:lklimek, shumkov, llbartekll, zocolini

Sequence Diagram(s)

sequenceDiagram
participant Sdk
participant EvoNodeStatus
participant AddressList
participant ProtocolRefresh
Sdk->>AddressList: Sample live peers
Sdk->>EvoNodeStatus: Probe sampled peers with unproven status requests
EvoNodeStatus-->>Sdk: Return reported protocol versions
Sdk->>AddressList: Record peer versions and set preferred target
Sdk->>ProtocolRefresh: Continue refresh logic
ProtocolRefresh-->>Sdk: Return verified or pinned protocol version
Loading
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title clearly and concisely describes the main change: preferring DAPI peers that support the client's latest protocol version.
Docstring Coverage✅ PassedDocstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/protocol-version-peer-startup-d02997

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.

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/rs-sdk/src/sdk.rs (1)

406-425: 🚀 Performance & Scalability | 🔵 Trivial | ⚡ Quick win

Consider running the peer probe concurrently with the proven ratchet query.

prefer_peers_with_latest_protocol_version() (worst case ~PEER_VERSION_PROBE_TIMEOUT = 4s) is awaited sequentially before the proven ExtendedEpochInfo::fetch_current query. Since this function is documented to run on app start / network switch, the two steps could overlap instead of stacking their latencies — both only borrow &self and are independent.

⚡ Proposed refactor to overlap the probe and the proven query
 pub async fn refresh_protocol_version(&self) -> Result<u32, Error> {
- // Best-effort: bias peer selection towards nodes that already support- // this client's newest protocol version. Never fails, never ratchets.- self.prefer_peers_with_latest_protocol_version().await;-- if !self.prove() {- return Ok(self.protocol_version_number());- }- if !self.version_pinned {- if let Err(error) = ExtendedEpochInfo::fetch_current(self).await {- tracing::warn!(- target: "dash_sdk::protocol_version",- %error,- "proven protocol-version refresh failed; keeping current version \- (never falling back to an unverified one)"- );- }- }- Ok(self.protocol_version_number())+ // Best-effort: bias peer selection towards nodes that already support+ // this client's newest protocol version. Never fails, never ratchets.+ let should_ratchet = self.prove() && !self.version_pinned;++ if should_ratchet {+ let (_, ratchet_result) = futures::join!(+ self.prefer_peers_with_latest_protocol_version(),+ ExtendedEpochInfo::fetch_current(self)+ );+ if let Err(error) = ratchet_result {+ tracing::warn!(+ target: "dash_sdk::protocol_version",+ %error,+ "proven protocol-version refresh failed; keeping current version \+ (never falling back to an unverified one)"+ );+ }+ } else {+ self.prefer_peers_with_latest_protocol_version().await;+ }+ Ok(self.protocol_version_number())
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/rs-sdk/src/sdk.rs` around lines 406 - 425, Update
refresh_protocol_version to start prefer_peers_with_latest_protocol_version and
the proven ExtendedEpochInfo::fetch_current operation concurrently when
applicable, awaiting both while preserving the existing best-effort probe
behavior, version_pinned guard, warning, and returned protocol version.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/rs-sdk/src/sdk.rs`:
- Around line 406-425: Update refresh_protocol_version to start
prefer_peers_with_latest_protocol_version and the proven
ExtendedEpochInfo::fetch_current operation concurrently when applicable,
awaiting both while preserving the existing best-effort probe behavior,
version_pinned guard, warning, and returned protocol version.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 129416b7-e33d-4750-b878-ab9fe70d6310

📥 Commits

Reviewing files that changed from the base of the PR and between 25bbb37 and 5c5cb98.

📒 Files selected for processing (3)
  • packages/rs-dapi-client/src/address_list.rs
  • packages/rs-sdk-ffi/src/protocol_version/queries/refresh.rs
  • packages/rs-sdk/src/sdk.rs

@QuantumExplorer

Copy link
Copy Markdown
MemberAuthor

Re CodeRabbit's nitpick about overlapping the peer probe with the proven ratchet query: declining — the sequencing is intentional. The probe sets the peer preference before the proven fetch_current, so the ratchet query itself is routed to a peer already known to support our latest protocol version (a stale peer answering the startup refresh is exactly what this feature mitigates). Overlapping the two would race the ratchet against unranked random peer selection. Since the probes fan out concurrently, the added startup latency is a single status round-trip (bounded by the 4 s probe timeout), which is acceptable for an app-start hook. Pushed 46da294 documenting this in the code so the ordering reads as deliberate.

🤖 Addressed by Claude Code

@QuantumExplorerQuantumExplorer left a comment

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

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

Reviewed at 5c5cb98c. I found two mobile/runtime blockers and one binding-documentation regression; details are inline.

Validation completed:

  • cargo test -p rs-dapi-client — 115 unit tests plus integration/doc tests passed
  • cargo test -p dash-sdk --lib — 174 tests passed
  • git diff --check — clean

I did not find FFI ABI, pointer-lifetime, CString ownership, or Swift memory-management regressions.

Comment threadpackages/rs-sdk/src/sdk.rs Outdated
Comment threadpackages/rs-sdk/src/sdk.rs
Comment threadpackages/rs-sdk-ffi/src/protocol_version/queries/refresh.rs

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/swift-sdk/Sources/SwiftDashSDK/SDK.swift`:
- Around line 519-520: Update the documentation comment immediately preceding
the blocking SDK call to state that it always waits for the probe, and waits for
the proven query only when the SDK is not pinned; retain the guidance to invoke
it from a background queue or task rather than the main thread.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 421a1a2c-2cde-420e-aca4-c52764bd1146

📥 Commits

Reviewing files that changed from the base of the PR and between 5c5cb98 and f3a2e28.

📒 Files selected for processing (8)
  • packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/ffi/QueriesNative.kt
  • packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/queries/PlatformQueries.kt
  • packages/rs-dapi-client/Cargo.toml
  • packages/rs-dapi-client/src/address_list.rs
  • packages/rs-sdk-ffi/src/protocol_version/queries/refresh.rs
  • packages/rs-sdk/src/sdk.rs
  • packages/rs-unified-sdk-jni/src/queries.rs
  • packages/swift-sdk/Sources/SwiftDashSDK/SDK.swift
🚧 Files skipped from review as they are similar to previous changes (3)
  • packages/rs-sdk-ffi/src/protocol_version/queries/refresh.rs
  • packages/rs-dapi-client/src/address_list.rs
  • packages/rs-sdk/src/sdk.rs

Comment threadpackages/swift-sdk/Sources/SwiftDashSDK/SDK.swift Outdated

@thepastaclawthepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Preliminary review — Codex only

The prior fan-out and binding-documentation issues are fixed, and the Android call path was already marshalled through Dispatchers.IO. Three blocking issues remain: targeted probes can mutate an unrelated peer's ban state, deadline-dropped probes preserve stale rankings, and an unproved self-reported capability can become an exclusive and persistent routing gate.

Validated blockers were found in the Codex precheck. Sonnet is deferred until a fresh Codex revalidation clears the blocker gate.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (completed), gpt-5.6-sol — ffi-engineer (completed)
  • Verifier: gpt-5.6-sol — verifier
  • Sonnet: not run (deferred by blocker gate)

🔴 3 blocking

🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify each finding against the current code and only fix it if needed.
In `packages/rs-sdk/src/sdk.rs`:
- [BLOCKING] packages/rs-sdk/src/sdk.rs:501-506: Probe responses can unban an unrelated peer
The targeted `EvoNode` request still runs through the ordinary `DapiClient` executor. That executor selects a live address B and later records B in `ExecutionResponse.address`, while `EvoNode::execute_transport` ignores the supplied client and creates a separate connection to the requested probe address A. A successful response from A therefore invokes `update_address_ban_status` for B in both the DAPI-client and SDK retry layers. `ban_failed_address: false` suppresses failure-driven bans but does not suppress success-driven unbanning, so the probe can clear B's expired ban ladder or lift a ban placed concurrently while A was being queried. Execute targeted probes through a path that reports A as the response address, or disable health-state mutation for these maintenance requests.
- [BLOCKING] packages/rs-sdk/src/sdk.rs:496-535: Clear stale versions for probes dropped by the total deadline
Only futures yielded before `take_until` reach `set_supported_protocol_version`. If a peer already has `Some(target)` from an earlier refresh and its new probe is dropped at the six-second deadline, the old value remains and the peer is still treated as preferred even though the current pass learned nothing. This is especially reachable because the second concurrency batch can start after the four-second per-node timeouts and then has less than two seconds before the total deadline. Clear sampled addresses before launching the pass or explicitly clear every unfinished sampled address after the stream ends.
In `packages/rs-dapi-client/src/address_list.rs`:
- [BLOCKING] packages/rs-dapi-client/src/address_list.rs:382-397: Do not let an unproved capability report become an exclusive routing gate
The version stored for each peer comes directly from its unproved, self-asserted `getStatus` response, but this branch turns that assertion into an exclusive eligibility filter whenever at least one matching peer exists. A malicious sampled peer can claim `version >= preferred` and become the only selected endpoint when no other sampled peer reports the target. The ranking has no expiry and survives unban, while non-retryable gRPC responses such as `InvalidArgument` and `PermissionDenied` do not ban the peer; the attacker can therefore remain selected and persistently block proven refreshes, queries, and state-transition submissions while observing the client's DAPI traffic. Use this untrusted signal as a non-exclusive weight, preserving a nonzero selection probability for other live peers, or require independently authenticated capability information before filtering exclusively.

Comment threadpackages/rs-sdk/src/sdk.rs Outdated
Comment threadpackages/rs-sdk/src/sdk.rs
Comment threadpackages/rs-dapi-client/src/address_list.rs
@codecov

codecovBot commented Jul 24, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.53%. Comparing base (0e2282b) to head (3709c6c).
⚠️ Report is 132 commits behind head on v4.2-dev.

Additional details and impacted files
@@ Coverage Diff @@## v4.2-dev #4221 +/- ##
=========================================
Coverage 87.53% 87.53% =========================================
Files 2678 2678 Lines 341047 341047 =========================================
Hits 298519 298519 Misses 42528 42528 
ComponentsCoverage Δ
dpp88.49% <ø> (ø)
drive86.26% <ø> (ø)
drive-abci89.57% <ø> (ø)
sdk∅ <ø> (∅)
dapi-client∅ <ø> (∅)
platform-version∅ <ø> (∅)
platform-value92.88% <ø> (ø)
platform-wallet∅ <ø> (∅)
drive-proof-verifier49.60% <ø> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@QuantumExplorer
QuantumExplorer changed the base branch from v4.1-dev to v4.2-devJuly 24, 2026 20:11
@github-actionsgithub-actionsBot modified the milestones: v4.1.0, v4.2.0Jul 24, 2026

@thepastaclawthepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Final validation — Codex + Sonnet

At exact head 6dbe886, combined Codex checkpoint and successful Sonnet general, security, and FFI evidence found no remaining in-scope issues. Source inspection confirms that all three prior blockers are fixed: probes bypass health-mutating DAPI execution, sampled rankings are cleared before probing, and protocol preference is weighted rather than exclusive.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (completed), gpt-5.6-sol — ffi-engineer (completed)
  • Verifier: gpt-5.6-sol — final-verifier (fallback)
  • Sonnet reviewers: claude-sonnet-5 — general (completed), claude-sonnet-5 — security-auditor (failed), claude-sonnet-5 — ffi-engineer (completed), claude-sonnet-5 — security-auditor (completed)

QuantumExplorerand others added 5 commits August 4, 2026 10:53
…version
On startup (and network switch), the SDK now best-effort probes the known
DAPI peers with an unproven getStatus and records each node's reported
version.protocol.drive.latest — the highest protocol version that node's
software supports. Subsequent peer selection prefers, when possible, peers
whose reported version is at least the client's own latest supported
protocol version (PlatformVersion::latest()).
- rs-dapi-client: AddressList tracks a per-address supported protocol
version and an optional preferred version target (shared across clones);
get_live_address picks among preferred peers first and falls back to any
live peer — no peer is ever excluded by version alone, and version
knowledge survives unban.
- rs-sdk: new Sdk::prefer_peers_with_latest_protocol_version() fans out
concurrent getStatus probes (4 s per-node timeout, no retries, no
banning), records results, and sets the preference. It is wired into
Sdk::refresh_protocol_version(), the documented app-start/network-switch
hook, so the FFI/Kotlin/Swift bindings get the behavior without changes.
The probe is unproven and feeds only peer ordering; the protocol-version
ratchet stays proof-driven.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Address review feedback on the startup peer probe:
- Probe a random sample of at most 16 live peers (mainnet seeds ship ~340
Evo nodes) instead of the whole address list, with at most 8 connections
in flight and a 6 s overall wall-clock budget on top of the 4 s per-node
timeout. Results that arrive within the budget are kept; unprobed or
unanswered peers simply stay unranked and remain usable through the
best-effort fallback. New AddressList::sample_live_addresses backs the
sampling (rand `alloc` feature enabled for choose_multiple).
- Update the binding-facing contracts: Swift SDK.refreshProtocolVersion no
longer promises a pinned refresh is a no-op (the probe still runs) and
is documented as blocking — call off the main thread; Kotlin/JNI docs
now state the probe, the network I/O in pinned mode, and that the
blocking native call is marshalled onto Dispatchers.IO by queryGate.op.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Address the three blocking findings from review:
- Probes no longer run through the DapiClient executor, which pairs each
response with an address it selected itself and would attribute a
targeted probe's success to an unrelated peer, mutating that peer's ban
state (success-driven unban / ladder reset). The probe now executes its
transport directly against the target address and parses the response
via FromUnproved, leaving all peer health state untouched.
- Each probe pass clears the recorded supported version of every sampled
peer up front, so probes dropped by the overall deadline leave their
peer unranked instead of preserving a stale ranking from an earlier
pass (previously only completed-but-failed probes were cleared).
- Peer preference is now a weight, not an exclusive gate: 90% of
selections consult the preferred tier first, the rest select uniformly
from all live peers, so a peer's unproved self-reported version can
bias routing but never capture it. Selection tests updated from
exact-match loops to statistical bounds accordingly.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@QuantumExplorer
QuantumExplorerforce-pushed the claude/protocol-version-peer-startup-d02997 branch from 6dbe886 to 0d2a3e1CompareAugust 4, 2026 03:59

@coderabbitaicoderabbitaiBot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
packages/rs-sdk/src/sdk.rs (1)

594-604: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Consider stopping the probe when the SDK is cancelled.

The probe pass only ends on the 6 second budget or on completion. If a caller triggers Sdk::shutdown during refresh_protocol_version, the call still waits for the budget. Add the cancel token to the stop condition to shorten shutdown.

♻️ Proposed change to also stop on cancellation
- .take_until(rs_dapi_client::transport::sleep(- PEER_VERSION_PROBE_TOTAL_BUDGET,- )));+ .take_until(futures::future::select(+ Box::pin(rs_dapi_client::transport::sleep(+ PEER_VERSION_PROBE_TOTAL_BUDGET,+ )),+ Box::pin(self.cancelled()),+ )));
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/rs-sdk/src/sdk.rs` around lines 594 - 604, Update the probe stream
construction in refresh_protocol_version to include the SDK cancellation token
in the take_until stop condition alongside PEER_VERSION_PROBE_TOTAL_BUDGET.
Ensure Sdk::shutdown causes the probe loop consuming probes to terminate
promptly while preserving the existing time-budget behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@packages/rs-sdk/src/sdk.rs`:
- Around line 594-604: Update the probe stream construction in
refresh_protocol_version to include the SDK cancellation token in the take_until
stop condition alongside PEER_VERSION_PROBE_TOTAL_BUDGET. Ensure Sdk::shutdown
causes the probe loop consuming probes to terminate promptly while preserving
the existing time-budget behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 52c60b38-d252-43b9-a8f3-8d0799c528c0

📥 Commits

Reviewing files that changed from the base of the PR and between 6dbe886 and 0d2a3e1.

📒 Files selected for processing (8)
  • packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/ffi/QueriesNative.kt
  • packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/queries/PlatformQueries.kt
  • packages/rs-dapi-client/Cargo.toml
  • packages/rs-dapi-client/src/address_list.rs
  • packages/rs-sdk-ffi/src/protocol_version/queries/refresh.rs
  • packages/rs-sdk/src/sdk.rs
  • packages/rs-unified-sdk-jni/src/queries.rs
  • packages/swift-sdk/Sources/SwiftDashSDK/SDK.swift
🚧 Files skipped from review as they are similar to previous changes (7)
  • packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/ffi/QueriesNative.kt
  • packages/kotlin-sdk/sdk/src/main/kotlin/org/dashfoundation/dashsdk/queries/PlatformQueries.kt
  • packages/rs-unified-sdk-jni/src/queries.rs
  • packages/rs-sdk-ffi/src/protocol_version/queries/refresh.rs
  • packages/swift-sdk/Sources/SwiftDashSDK/SDK.swift
  • packages/rs-dapi-client/Cargo.toml
  • packages/rs-dapi-client/src/address_list.rs

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@QuantumExplorer

Copy link
Copy Markdown
MemberAuthor

Applied CodeRabbit's cancellation nitpick in 3709c6c: the probe's take_until now stops on whichever comes first — the 6 s budget or Sdk::cancelled() — so a shutdown() issued during refresh_protocol_version is no longer delayed by the remaining probe budget. Verified: dash-sdk unit tests (181) pass and wasm32-unknown-unknown still builds.

🤖 Addressed by Claude Code

@thepastaclawthepastaclaw left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Final validation — Codex + Sonnet

The only substantive change since the last clean review (6dbe886) is commit 3709c6c, a 14-line diff to packages/rs-sdk/src/sdk.rs that adds a futures::future::select cancellation arm to the peer protocol-version probe's take_until, so Sdk::shutdown() now stops the probe fan-out immediately instead of waiting out the full PEER_VERSION_PROBE_TOTAL_BUDGET. I re-verified this directly: cargo check and cargo clippy --lib -- -D warnings both pass cleanly for dash-sdk, the cancel_token/cancelled()/shutdown() wiring is correct and consistent with its documented contract, and the change touches no consensus-critical, proof, or FFI-exposed surface. No agent raised any in-scope blocking or suggestion findings, and none were fabricated here — the PR remains clean.

Review provenance

  • Codex reviewers: gpt-5.6-sol — general (completed), gpt-5.6-sol — security-auditor (completed), gpt-5.6-sol — ffi-engineer (completed)
  • Verifier: claude-sonnet-5 — final-verifier
  • Sonnet reviewers: claude-sonnet-5 — general (completed), claude-sonnet-5 — security-auditor (failed), claude-sonnet-5 — ffi-engineer (completed), claude-sonnet-5 — security-auditor (failed), claude-sonnet-5 — security-auditor (completed)

@QuantumExplorer
QuantumExplorer marked this pull request as draft August 25, 2026 09:40
@QuantumExplorer

Copy link
Copy Markdown
MemberAuthor

Not actually sure we should do this.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

@QuantumExplorer@thepastaclaw