Skip to content

fix(sdk): run blocking Swift SDK Platform queries off the caller's actor - #5146

Open
romchornyi wants to merge 4 commits into
v5.0-devfrom
fix/swift-sdk-queries-off-main-actor
Open

romchornyi wants to merge 4 commits into
v5.0-devfrom
fix/swift-sdk-queries-off-main-actor

Conversation

@romchornyi

@romchornyi romchornyi commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Issue being fixed or feature implemented

Closes #5145. Swift SDK query helpers live in @MainActor extension SDK blocks and call FFI entry
points that block in runtime.block_on until DAPI answers, so every call parks the main thread for a
full network round trip — and callers cannot avoid it (a Task.detached still hops back to the main
actor for the call). Dash Wallet iOS hits this on proof-link lookups (documentList), username
availability while typing (dpnsCheckAvailability) and contest state (dpnsContestVoteState /
dpnsContestIsOpen).

What was done?

  • SDK.performBlockingQuery(_:) (FFI/PlatformQueryExtensions.swift, nonisolated, internal):
    runs the FFI body on a concurrent .userInitiated queue and resumes the caller through a checked
    continuation — the pattern dataContractGetOffMain already used, generalised. self is held with
    withExtendedLifetime for the call (the handle is freed only in deinit); every FFI result is
    copied into a Sendable Swift value and freed on the queue thread.
  • documentList and dpnsCheckAvailability(name:) are now nonisolated and run through it;
    names and arguments unchanged (documentList returns sending [String: Any]), so existing
    try await callers go off-main without edits. Their blocking halves are nonisolated static
    helpers.
  • Voting/SDK+DPNSContests.swift: new dpnsContestVoteStateOffMain(normalizedLabel:limit:) and
    dpnsContestIsOpenOffMain(normalizedLabel:). The synchronous dpnsContestVoteState /
    dpnsContestIsOpen stay (callers use them synchronously) and share one fetchContestVoteState.
  • Why concurrent, not serial: every query entry point takes the handle as a shared &SDKWrapper,
    dash_sdk::Sdk is Send + Sync, and BigStackRuntime::block_on runs each call on its own thread
    over a multi-threaded runtime; dpnsActiveContests / dataContractGetOffMain already use the handle
    concurrently. A serial queue would make the newest availability check wait behind stale ones.
  • Other queries in the same @MainActor block are left as they are to keep the diff small (and clear
    of feat(sdk): expose the document erase and history lifecycle on mobile and FFI #4660, which edits this file); moving one later is a two-line wrapper.

How Has This Been Tested?

  • New SwiftTests/SwiftDashSDKTests/PlatformQueryOffMainTests.swift (FFI mock SDK, no network): the
    query body runs off the main thread; a query parked on a semaphore is released by the main actor
    (the caller's actor is not held); documentList, dpnsCheckAvailability and both …OffMain
    variants surface the mock's FFI error to a main-actor caller.
  • swift test --filter 'PlatformQueryOffMainTests|SDKMethodTests|DPNSContestDecoderTests': 30 tests,
    0 failures. Full swift test: 727 tests, 0 failures on two consecutive runs (one earlier run had a
    single failure whose output was not captured; not reproduced).
  • ./build_ios.sh --target tests --profile dev: Rust sim + mac slices and SwiftExampleApp for the iOS
    Simulator with warnings as errors — BUILD SUCCEEDED, covering the example app's main-actor call
    sites of documentList and dpnsCheckAvailability.

Breaking Changes

None. Same method names and arguments; two methods become nonisolated, two …OffMain variants are
added.

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
  • If I added or changed GroveDB structure, I described it in the area's structure.rs, regenerated grovedb-structure.json, and checked the structure viewer link posted on this pull request

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

🤖 Generated with Claude Code

PR Hygiene · 610c083

  • Bots — coderabbitai skipped after its own rate limit · thepastaclaw ✓
  • Self-review — posted; again after any push
  • Build green
  • Approvals
    • rust-sdk-ffi (packages/rs-sdk-ffi/src/data_contract/put.rs, packages/rs-sdk-ffi/src/document/create.rs, packages/rs-sdk-ffi/src/document/delete.rs and 22 more) — lklimek or shumkov
    • swift-sdk — you own it

When every merge requirement is met, the PR Hygiene check passes. Reviewer limits do not block merging; other required GitHub checks and protections still apply.

@romchornyi romchornyi added this to the v4.3.0 milestone Sep 28, 2026
@coderabbitai

coderabbitai Bot commented Sep 28, 2026 •

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

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

Next included review available in 21 minutes.

Check out review usage here.

View limit details

Limit details: You’ve used the included review currently available.

Learn how review limits work.

Review configuration:

⚙️ Run configuration
  • Configuration used: Repository: dashpay/platform/.coderabbit.yaml
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: ac5dbe45-5599-4aa3-a54d-1af899b1a98a
📥 Commits

Reviewing files that changed from the base of the PR and between 4cf12f2 and 610c083.

📒 Files selected for processing (30)
  • packages/rs-sdk-ffi/src/data_contract/put.rs
  • packages/rs-sdk-ffi/src/document/create.rs
  • packages/rs-sdk-ffi/src/document/delete.rs
  • packages/rs-sdk-ffi/src/document/price.rs
  • packages/rs-sdk-ffi/src/document/purchase.rs
  • packages/rs-sdk-ffi/src/document/put.rs
  • packages/rs-sdk-ffi/src/document/queries/fetch.rs
  • packages/rs-sdk-ffi/src/document/replace.rs
  • packages/rs-sdk-ffi/src/document/transfer.rs
  • packages/rs-sdk-ffi/src/identity/create.rs
  • packages/rs-sdk-ffi/src/identity/put.rs
  • packages/rs-sdk-ffi/src/identity/transfer.rs
  • packages/rs-sdk-ffi/src/identity/withdraw.rs
  • packages/rs-sdk-ffi/src/sdk.rs
  • packages/rs-sdk-ffi/src/token/burn.rs
  • packages/rs-sdk-ffi/src/token/claim.rs
  • packages/rs-sdk-ffi/src/token/config_update.rs
  • packages/rs-sdk-ffi/src/token/destroy_frozen_funds.rs
  • packages/rs-sdk-ffi/src/token/emergency_action.rs
  • packages/rs-sdk-ffi/src/token/freeze.rs
  • packages/rs-sdk-ffi/src/token/mint.rs
  • packages/rs-sdk-ffi/src/token/purchase.rs
  • packages/rs-sdk-ffi/src/token/set_price.rs
  • packages/rs-sdk-ffi/src/token/transfer.rs
  • packages/rs-sdk-ffi/src/token/unfreeze.rs
  • packages/swift-sdk/Sources/SwiftDashSDK/FFI/PlatformQueryExtensions.swift
  • packages/swift-sdk/Sources/SwiftDashSDK/Voting/SDK+DPNSContests.swift
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegisterNameView.swift
  • packages/swift-sdk/SwiftExampleApp/SwiftExampleAppTests/AvailabilityRequestGateTests.swift
  • packages/swift-sdk/SwiftTests/SwiftDashSDKTests/PlatformQueryOffMainTests.swift
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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.

@github-actions github-actions Bot added the waiting-bots Waiting for the review bots to report on this head label Sep 28, 2026
@thepastaclaw

thepastaclaw commented Sep 28, 2026 •

Copy link
Copy Markdown
Collaborator

✅ Final review complete — no blockers (commit 610c083) · triage: normal

@PastaPastaPasta PastaPastaPasta mentioned this pull request Sep 28, 2026
2 of 24 tasks

@thepastaclaw thepastaclaw 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 — Phase 1 + Phase 2

The PR correctly moves blocking Platform FFI reads off the caller’s actor and preserves FFI ownership, but the newly concurrent availability checks introduce a stale-result race in the existing registration UI. An older lookup can overwrite the availability state for the username currently being edited, enabling an incorrect registration attempt or displaying the wrong status.

🟡 1 suggestion(s)

1 finding(s) not shown inline (the lines are not part of this PR's diff)

🟡 Suggestion: Ignore stale username availability completions
packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegisterNameView.swift:361-375

dpnsCheckAvailability now runs concurrently, so checkAvailabilityAutomatically() can have multiple requests in flight. The completion unconditionally assigns isAvailable and clears isChecking, while the text-field handler only invalidates the debounce timer and does not invalidate an already-running request. For example, a slow request for available name A can complete after the user changes to taken name B and B’s request returns false, overwriting B’s state with true and enabling the Register Name button. Capture the queried normalized name together with a request generation/token, and apply success and error results only when they still correspond to the current request and username. Add a regression test that completes two availability requests out of order.

source: gpt-6-astra (phase2-reviewer: general, architecture-layering, ffi-engineer, security-auditor)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: architecture-layering); reviewer 3: muse-spark-1.3-contributor (agent: phase1-reviewer, role: ffi-engineer); reviewer 4: muse-spark-1.3-contributor (agent: phase1-reviewer, role: security-auditor); reviewer 5: gpt-6-astra (agent: phase2-reviewer, role: general); reviewer 6: gpt-6-astra (agent: phase2-reviewer, role: architecture-layering); reviewer 7: gpt-6-astra (agent: phase2-reviewer, role: ffi-engineer); reviewer 8: gpt-6-astra (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6-astra (agent: astra-verifier, role: final-verifier)

  • Triage: normal by gpt-6-astra (effort low) — The changes introduce nontrivial Swift actor isolation, concurrent FFI execution, and handle-lifetime management across several query helpers, but do not modify any critical surface such as consensus, funds movement, cryptography, network deserialization, or storage migrations.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — architecture-layering (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — ffi-engineer (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — security-auditor (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 13% left, 5h 100% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Fresh verifier: gpt-6-astra — final-verifier; agent astra-verifier
  • Phase 2 reviewers: gpt-6-astra — general (completed, effort high); agent phase2-reviewer, gpt-6-astra — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6-astra — ffi-engineer (completed, effort high); agent phase2-reviewer, gpt-6-astra — security-auditor (completed, effort high); agent phase2-reviewer
🤖 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/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegisterNameView.swift`:
- [SUGGESTION] packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegisterNameView.swift:361-375: Ignore stale username availability completions
  `dpnsCheckAvailability` now runs concurrently, so `checkAvailabilityAutomatically()` can have multiple requests in flight. The completion unconditionally assigns `isAvailable` and clears `isChecking`, while the text-field handler only invalidates the debounce timer and does not invalidate an already-running request. For example, a slow request for available name A can complete after the user changes to taken name B and B’s request returns `false`, overwriting B’s state with `true` and enabling the Register Name button. Capture the queried normalized name together with a request generation/token, and apply success and error results only when they still correspond to the current request and username. Add a regression test that completes two availability requests out of order.

@romchornyi

Copy link
Copy Markdown
Contributor Author

Stale availability results (RegisterNameView.swift:361-375, not shown inline): fixed in ba0d6ef. Each lookup is tagged by a small AvailabilityRequestGate — only the newest request, for the name still in the field, may set isAvailable / isChecking (success and error paths), and editing the name drops any request in flight. AvailabilityRequestGateTests covers two lookups completing out of order, an edited name and cancellation (4/4); SwiftExampleApp builds with warnings as errors.

@romchornyi

Copy link
Copy Markdown
Contributor Author

/self-reviewed

@thepastaclaw thepastaclaw 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.

Re-review — Final validation — Phase 1 + Phase 2

The off-main query implementation preserves SDK lifetime, FFI result ownership, and caller-actor responsiveness, and the original stale-completion race is fixed. One in-scope logic issue remains in the registration form: cancelling a lookup leaves the deduplication marker set, so editing away and back to the same name can permanently suppress the replacement lookup.

🟡 1 suggestion(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: architecture-layering); reviewer 3: muse-spark-1.3-contributor (agent: phase1-reviewer, role: ffi-engineer); reviewer 4: muse-spark-1.3-contributor (agent: phase1-reviewer, role: security-auditor); reviewer 5: gpt-6-astra (agent: phase2-reviewer, role: general); reviewer 6: gpt-6-astra (agent: phase2-reviewer, role: architecture-layering); reviewer 7: gpt-6-astra (agent: phase2-reviewer, role: ffi-engineer); reviewer 8: gpt-6-astra (agent: phase2-reviewer, role: security-auditor); reviewer 9: gpt-6-astra (agent: phase2-reviewer, role: general); reviewer 10: gpt-6-astra (agent: phase2-reviewer, role: architecture-layering); reviewer 11: gpt-6-astra (agent: phase2-reviewer, role: ffi-engineer); reviewer 12: gpt-6-astra (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6-astra (agent: astra-verifier, role: final-verifier)

  • Triage: normal by gpt-6-astra (effort low) — The diff introduces nontrivial Swift actor-isolation, concurrent FFI execution, lifetime management, and stale availability-result handling, but does not itself change any qualifying critical surface.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — architecture-layering (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — ffi-engineer (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — security-auditor (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 13% left, 5h 100% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6-astra — final-verifier; agent astra-verifier
  • Phase 2 reviewers: gpt-6-astra — general (completed, effort high); agent phase2-reviewer, gpt-6-astra — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6-astra — ffi-engineer (completed, effort high); agent phase2-reviewer, gpt-6-astra — security-auditor (completed, effort high); agent phase2-reviewer, gpt-6-astra — general (completed, effort high); agent phase2-reviewer, gpt-6-astra — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6-astra — ffi-engineer (completed, effort high); agent phase2-reviewer, gpt-6-astra — security-auditor (completed, effort high); agent phase2-reviewer
🤖 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/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegisterNameView.swift`:
- [SUGGESTION] packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegisterNameView.swift:174-177: Clear the checked-name marker when cancelling its lookup
  When the username changes, `availabilityGate.cancel()` invalidates the active request but `lastCheckedName` remains unchanged. If a lookup for `alice` is in flight, the user edits to another name, then edits back to `alice` before the debounce fires, the second edit sees `normalizedUsername == lastCheckedName` and schedules no new lookup at line 185. The original completion is rejected by the cancelled gate, leaving availability unset and registration disabled for the displayed name. Reset the deduplication marker when invalidating the lookup, or make the scheduling condition distinguish a cancelled request from an accepted result. Add a regression test covering edit-away/edit-back before the debounce fires.
Out-of-scope follow-up suggestions (1)

These are valid observations, but they are outside this PR's scope and should be handled in separate issues or author/maintainer-requested PRs rather than blocking this review.

  • Audit exclusive SDKWrapper borrows across concurrent FFI calls — Existing FFI entry points construct exclusive &mut SDKWrapper references from shared SDK handles even for operations that appear read-only. This predates the current PR and no concrete memory-corruption issue was established here, but the borrowing model should be audited before further concurrent FFI expansion.
    • Follow-up: Track separately in a maintainer-requested FFI safety audit; replace unnecessary exclusive references with shared access or establish synchronization for genuinely exclusive operations.

Comment thread packages/swift-sdk/SwiftExampleApp/SwiftExampleApp/Views/RegisterNameView.swift Outdated
@romchornyi

Copy link
Copy Markdown
Contributor Author

/self-reviewed

@thepastaclaw thepastaclaw 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.

Re-review — Final validation — Phase 1 + Phase 2

Both prior username-availability findings are fixed. The new executor nevertheless exposes overlapping shared and exclusive Rust SDK borrows between previously serialized query paths, leaving one deduplicated memory-safety blocker. All five changed files were inspected; the six current-source availability-gate tests passed in an isolated XCTest harness, and git diff --check passed; the full SDK/application suites were not rerun.

🔴 1 blocking

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: architecture-layering); reviewer 3: muse-spark-1.3-contributor (agent: phase1-reviewer, role: ffi-engineer); reviewer 4: muse-spark-1.3-contributor (agent: phase1-reviewer, role: security-auditor); reviewer 5: gpt-6-astra (agent: phase2-reviewer, role: general); reviewer 6: gpt-6-astra (agent: phase2-reviewer, role: architecture-layering); reviewer 7: gpt-6-astra (agent: phase2-reviewer, role: ffi-engineer); reviewer 8: gpt-6-astra (agent: phase2-reviewer, role: security-auditor); reviewer 9: gpt-6-astra (agent: phase2-reviewer, role: general); reviewer 10: gpt-6-astra (agent: phase2-reviewer, role: architecture-layering); reviewer 11: gpt-6-astra (agent: phase2-reviewer, role: ffi-engineer); reviewer 12: gpt-6-astra (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6-astra (agent: astra-verifier, role: final-verifier)

  • Triage: normal by gpt-6-astra (effort low) — The diff introduces nontrivial Swift actor isolation, concurrent FFI execution, lifetime management, and stale username-result handling across SDK and UI code, but does not change any of the specified critical surfaces.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — architecture-layering (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — ffi-engineer (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — security-auditor (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 13% left, 5h 100% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6-astra — final-verifier; agent astra-verifier
  • Phase 2 reviewers: gpt-6-astra — general (completed, effort high); agent phase2-reviewer, gpt-6-astra — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6-astra — ffi-engineer (completed, effort high); agent phase2-reviewer, gpt-6-astra — security-auditor (completed, effort high); agent phase2-reviewer, gpt-6-astra — general (completed, effort high); agent phase2-reviewer, gpt-6-astra — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6-astra — ffi-engineer (completed, effort high); agent phase2-reviewer, gpt-6-astra — security-auditor (completed, effort high); agent phase2-reviewer
🤖 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/swift-sdk/Sources/SwiftDashSDK/FFI/PlatformQueryExtensions.swift`:
- [BLOCKING] packages/swift-sdk/Sources/SwiftDashSDK/FFI/PlatformQueryExtensions.swift:2308-2315: Prevent shared query borrows from overlapping exclusive SDK borrows
  Moving these calls off the main actor permits an unsafe overlap on the same SDK handle. For example, start `documentList` and let another main-actor task finish a successful `documentGet` while the list request remains pending. The list's Rust contract-fetch/search paths borrow SDK state through `&SDKWrapper` across `block_on`, while `documentGet` invokes `dash_sdk_document_destroy` in its defer at line 708. That entry point constructs `&mut SDKWrapper` in `packages/rs-sdk-ffi/src/document/util.rs:31`, overlapping the live shared borrow and violating Rust's aliasing requirements. In the base revision, these two query bodies were main-actor isolated and contained no suspension points, so this particular overlap could not occur. Existing background helpers expose related pre-existing cases, but do not make this newly enabled overlap safe. `Sdk: Send + Sync` and retaining `self` protect neither against exclusive-reference aliasing. Replace unnecessary exclusive SDKWrapper borrows in conflicting entry points with shared borrows, and synchronize any genuinely exclusive access across all callers; serializing only the new queue would not coordinate it with `documentGet` or independently dispatched operations.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. and removed waiting-bots Waiting for the review bots to report on this head labels Sep 30, 2026
@romchornyi

Copy link
Copy Markdown
Contributor Author

/self-reviewed

@github-actions github-actions Bot added waiting-bots Waiting for the review bots to report on this head and removed waiting-self-review Waiting for the author to post /self-reviewed bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. labels Sep 30, 2026

@thepastaclaw thepastaclaw 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.

Re-review — Final validation — Phase 1 + Phase 2

The complete diff at the exact reviewed head is sound: off-main query execution retains the SDK safely, live FFI entry points use shared wrapper borrows, and availability results are correctly gated against stale or cancelled requests. The suggested explicit MainActor annotation is unnecessary because Swift 6 infers MainActor isolation for members of a type conforming to SwiftUI's MainActor-isolated View protocol. No in-scope defects remain.

🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: architecture-layering); reviewer 3: muse-spark-1.3-contributor (agent: phase1-reviewer, role: ffi-engineer); reviewer 4: muse-spark-1.3-contributor (agent: phase1-reviewer, role: security-auditor); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 9: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 10: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 11: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 12: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: normal by gpt-6.1-sol (effort low) — This is a cross-cutting Swift/Rust FFI concurrency change affecting numerous SDK entry points and actor isolation, but it does not modify consensus, funds movement, cryptography, key handling, peer-facing deserialization, or storage migrations.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — architecture-layering (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — ffi-engineer (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — security-auditor (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 13% left, 5h 100% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort high); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.

No unresolved findings remain from the prior review on this head.
Out-of-scope follow-up suggestions (1)

These are valid observations, but they are outside this PR's scope and should be handled in separate issues or author/maintainer-requested PRs rather than blocking this review.

  • Use the allocation destructor when releasing documentGet results — The existing documentGet cleanup calls dash_sdk_document_destroy and ignores its returned error. That entry point performs a not-implemented operation rather than freeing the document allocation, while dash_sdk_document_handle_destroy is the actual handle destructor; successful documentGet calls therefore leak the document and the allocated error. This behavior predates the reviewed changes and is not caused by this PR.
    • Follow-up: Track separately: replace the documentGet cleanup with dash_sdk_document_handle_destroy and audit other Swift callers for the same destructor mismatch.

@github-actions github-actions Bot removed the waiting-bots Waiting for the review bots to report on this head label Sep 30, 2026
@github-actions

github-actions Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Bots are done — your move: post /self-reviewed.
Full checklist in the description.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. labels Oct 2, 2026
jeanpierreroma and others added 4 commits October 3, 2026 19:05
documentList, dpnsCheckAvailability and the DPNS contest vote-state reads
were declared in `@MainActor extension SDK` and called FFI entry points that
park the calling thread in `block_on` until DAPI answers. A caller could not
move the round trip off the main thread: `Task.detached` still hops back to
the main actor for a main-actor method.

Add `performBlockingQuery(_:)`, which runs the FFI call on a concurrent
dispatch queue and resumes the caller through a checked continuation. The
SDK is strongly captured so its handle stays valid for the call; each
blocking helper keeps its C-string arguments alive for the whole call and
copies and frees the native result on the queue thread, so only Swift
values leave it.

- documentList and dpnsCheckAvailability are now `nonisolated` (same
  names and arguments; documentList returns `sending [String: Any]`).
- dpnsContestVoteStateOffMain / dpnsContestIsOpenOffMain are new async
  variants; the synchronous dpnsContestVoteState / dpnsContestIsOpen stay
  for source compatibility and share the blocking helper.

The queue is concurrent: every query takes the handle as a shared
`&SDKWrapper` over a multi-threaded runtime, and a serial queue would make
the newest availability check wait behind stale ones.

Refs #5145

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…mple app

`dpnsCheckAvailability` now runs off the main actor, so lookups started by
RegisterNameView's debounce can overlap and finish out of order. A slow
"available" answer for an earlier name could overwrite the "taken" answer for
the name being edited and enable Register Name.

Each lookup is tagged by `AvailabilityRequestGate`: only the newest one, for
the name still in the field, may set the state, and editing the name drops
any lookup in flight. `AvailabilityRequestGateTests` covers two lookups
completing out of order, an edited name, and cancellation.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…ancelled

Editing the name cancels the lookup in flight, but the "already checked"
marker kept the old name. Typing that name back before the debounce fired
scheduled nothing, the cancelled answer was rejected, and availability stayed
unset with Register disabled. The marker now lives in AvailabilityRequestGate
and cancel() clears it; `needsLookup(for:)` replaces the view's own marker.
Tests cover edit-away/edit-back and an answered lookup not being repeated.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
…y point

35 rs-sdk-ffi entry points (document, identity, data contract and token
state transitions, document fetch, and dash_sdk_document_destroy) turned
the SDK handle into `&mut SDKWrapper` although none of them mutates it:
they only read `wrapper.sdk` and call `wrapper.runtime.block_on`. Now that
the Swift SDK runs Platform queries concurrently off the caller's actor,
such a call (e.g. `dash_sdk_document_destroy` in `documentGet`'s defer)
can overlap a query holding a shared `&SDKWrapper` across `block_on`,
which aliases a live shared borrow and is undefined behaviour.

All of them now borrow `&*(sdk_handle as *const SDKWrapper)`; behaviour
and C signatures are unchanged. The only remaining exclusive access is
`dash_sdk_destroy`, which the Swift SDK calls solely from `SDK.deinit`,
unreachable while a query retains `self`. The invariant is documented on
`SDKWrapper`, `dash_sdk_destroy` and the Swift query queue.
On v5.0-dev dash_sdk_document_destroy no longer exists (#5120), so the

entry points borrowed here are the remaining live-handle ones.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@romchornyi
romchornyi force-pushed the fix/swift-sdk-queries-off-main-actor branch from b702b5c to 610c083 Compare October 3, 2026 16:07
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

🌳 GroveDB structure

This pull request changes the described GroveDB structure. Open it in the structure viewer: new nodes glow, removed ones stay as ghosts, and the tour walks through each change.

Added (10 nodes)

  • tokens.shielded_pools

Changed (1 node)

  • tokens

Compared b95849a176 with 610c0839d3. Updated at 2026-10-03T16:07:29.461Z

@romchornyi
romchornyi changed the base branch from v5.1-dev to v5.0-dev October 3, 2026 16:07
@github-actions github-actions Bot modified the milestones: v5.1.0, v5.0.0 Oct 3, 2026
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

📖 Book Preview built successfully.

Download the preview from the workflow artifacts.
To view locally: download the artifact, unzip, and open index.html.

Updated at 2026-10-03T16:07:43.264Z

@github-actions github-actions Bot added waiting-bots Waiting for the review bots to report on this head and removed waiting-self-review Waiting for the author to post /self-reviewed bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. labels Oct 3, 2026

@thepastaclaw thepastaclaw 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.

Re-review — Final validation — Phase 1 + Phase 2

At exact head 610c083, the complete diff moves the selected blocking queries off the caller’s actor while preserving SDK lifetime, FFI argument/result ownership, and existing query behavior. All three prior findings are fixed, and no actionable in-scope findings remain. Validation was static only; the supplied CI snapshot from 2026-10-03T16:42:35Z still shows Rust workspace tests running and PR Hygiene pending.

🔴 0 blocking | 🟡 0 suggestion(s) | 💬 0 nitpick(s)

Review provenance

Source: reviewer 1: muse-spark-1.3-contributor (agent: phase1-reviewer, role: general); reviewer 2: muse-spark-1.3-contributor (agent: phase1-reviewer, role: rust-quality); reviewer 3: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 4: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 5: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 6: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 7: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); reviewer 8: gpt-6.1-sol (agent: phase2-reviewer, role: general); reviewer 9: gpt-6.1-sol (agent: phase2-reviewer, role: architecture-layering); reviewer 10: gpt-6.1-sol (agent: phase2-reviewer, role: ffi-engineer); reviewer 11: gpt-6.1-sol (agent: phase2-reviewer, role: rust-quality); reviewer 12: gpt-6.1-sol (agent: phase2-reviewer, role: security-auditor); final verifier: gpt-6.1-sol (agent: sol-verifier, role: final-verifier)

  • Triage: normal by gpt-6.1-sol (effort low) — The cross-language concurrency, handle-borrowing, and UI cancellation changes require careful review but do not themselves change consensus, funds-movement logic, cryptography, network deserialization, or storage migrations.
  • Phase 1 reviewers: muse-spark-1.3-contributor — general (completed, effort xhigh); agent phase1-reviewer, muse-spark-1.3-contributor — rust-quality (completed, effort xhigh); agent phase1-reviewer
  • Phase 1 model: muse-spark-1.3-contributor — not quota-gated; passed over gemini-3.8-flash-high (antigravity below 15% reserve: weekly 15% left, 5h 100% left), glm-5.3-flash (not used above high effort; tier asks max)
  • Fresh final gate: an independent Phase-2 review ran after iterative findings were reconciled
  • Fresh verifier: gpt-6.1-sol — final-verifier; agent sol-verifier
  • Phase 2 reviewers: gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — general (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — architecture-layering (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — ffi-engineer (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — rust-quality (completed, effort high); agent phase2-reviewer, gpt-6.1-sol — security-auditor (completed, effort high); agent phase2-reviewer
🤖 Prompt for all review comments with AI agents
These findings are from an automated code review. Verify the current code and confirm that no unresolved issues remain.

No unresolved findings remain from the prior review on this head.

@github-actions

github-actions Bot commented Oct 3, 2026 •

Copy link
Copy Markdown
Contributor

Bots are done — your move: post /self-reviewed.
Full checklist in the description.

@github-actions github-actions Bot added waiting-self-review Waiting for the author to post /self-reviewed bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. and removed waiting-bots Waiting for the review bots to report on this head labels Oct 3, 2026
@romchornyi

Copy link
Copy Markdown
Contributor Author

/self-reviewed

@github-actions github-actions Bot removed the waiting-self-review Waiting for the author to post /self-reviewed label Oct 3, 2026
@romchornyi romchornyi closed this Oct 3, 2026
@romchornyi romchornyi reopened this Oct 3, 2026
@github-actions

github-actions Bot commented Oct 3, 2026

Copy link
Copy Markdown
Contributor

Ready for review — rust-sdk-ffi: lklimek or shumkov.
Full checklist in the description.

@github-actions github-actions Bot added the ready-for-human Bots have reported, the author has self-reviewed, and the build is green: this needs a human. label Oct 3, 2026
@github-actions
github-actions Bot requested review from lklimek and shumkov October 3, 2026 19:28

This branch has not been deployed

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

Labels

bot-review-skipped A required review bot did not report; it was skipped by the window or by a person. ready-for-human Bots have reported, the author has self-reviewed, and the build is green: this needs a human.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

swift-sdk: Platform query methods run blocking FFI calls on the main actor

3 participants