Skip to content

feat(swift-example-app): enable SPV on devnet#3761

Closed
shumkov wants to merge 3 commits into
v3.1-devfrom
chore/bump-rust-dashcore-eb889af1
Closed

feat(swift-example-app): enable SPV on devnet#3761
shumkov wants to merge 3 commits into
v3.1-devfrom
chore/bump-rust-dashcore-eb889af1

Conversation

@shumkov
Copy link
Copy Markdown
Collaborator

@shumkov shumkov commented May 28, 2026

Issue being fixed or feature implemented

The example app could already create an SDK against a devnet, but Start Sync would either fail or connect to the wrong peers because the SPV start path never told dash-spv it was running against a devnet. This PR enables SPV on devnet end-to-end.

What was done?

Example app — devnet identity is now part of the SPV start config

  • OptionsView: new "Devnet Name" text field next to the existing Quorum URL field, backed by platformDevnetName UserDefaults.
  • CoreContentView.startSync: when currentNetwork == .devnet, reads platformDevnetName and passes it to PlatformSpvStartConfig.devnetName. Without this the FFI rejects the start with "devnet_name is required when network=Devnet".

FFI — migrated to the new dash-spv::DevnetConfig surface

  • packages/rs-platform-wallet-ffi/src/spv.rs: replaced the removed ClientConfig::llmq_devnet_params field with ClientConfig.devnet = Some(DevnetConfig::new(name).with_llmq_params(...)).
  • packages/rs-platform-wallet/src/wallet/platform_wallet_traits.rs: implemented the new WalletInfoInterface::monitored_script_pubkeys required method by delegating to the inner ManagedWalletInfo.
  • packages/rs-platform-wallet/src/spv/mod.rs: re-exported DevnetConfig from dash_spv so the FFI layer can build it without depending on dash-spv directly.

Dependency bump (the enabler)

How Has This Been Tested?

  • cargo check -p platform-wallet -p platform-wallet-ffi against the bumped revision is clean.
  • Manual UAT to follow: enter platformQuorumURL + platformDevnetName in Options on devnet, hit "Start Sync" on the Wallet tab, confirm SPV reaches the masternodes auto-discovered from {quorumURL}/masternodes and that headers / filters / masternodes progress all advance.

Breaking Changes

None for downstream consumers. The Swift PlatformSpvStartConfig.devnetName parameter was already public (added in #3758); this PR just starts using it.

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 made corresponding changes to the documentation

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

  • New Features

    • Added a persistent "Devnet Name" setting and UI field for configuring devnet identity.
    • SPV startup now accepts and validates an optional devnet name, enabling devnet-specific behavior and user-agent embedding on next sync.
  • Bug Fixes

    • Wallet info now exposes monitored script pubkeys for improved wallet visibility.
  • Chores

    • Updated internal dependency revisions.

Review Change Stack

Brings in 2 commits since 58d61ea5:
- eb889af1 feat(dash-spv): consolidate devnet config into `DevnetConfig` struct (#788)
- 9655ea38 refactor: avoid rebuilding `script_pubkey`s for BIP158 filter matching (#781)
@shumkov shumkov requested a review from QuantumExplorer as a code owner May 28, 2026 06:12
@github-actions github-actions Bot added this to the v3.1.0 milestone May 28, 2026
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 28, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1e2465dd-01ac-4928-a1c0-116f12806992

📥 Commits

Reviewing files that changed from the base of the PR and between 5811761 and 9036567.

📒 Files selected for processing (1)
  • packages/rs-platform-wallet-ffi/src/spv.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/rs-platform-wallet-ffi/src/spv.rs

📝 Walkthrough

Walkthrough

Bumps workspace rust-dashcore dependency revisions; routes SPV devnet identity and optional LLMQ overrides through a DevnetConfig exposed to the FFI and Swift example, and adds a WalletInfoInterface delegation for monitored script pubkeys.

Changes

Platform SPV / Devnet wiring

Layer / File(s) Summary
Rust re-exports and FFI imports
packages/rs-platform-wallet/src/spv/mod.rs, packages/rs-platform-wallet-ffi/src/spv.rs
Re-export DevnetConfig alongside ClientConfig and import DevnetConfig into the FFI bindings.
FFI SPV start: DevnetConfig wiring
packages/rs-platform-wallet-ffi/src/spv.rs
platform_wallet_manager_spv_start validates devnet_name, constructs and assigns a DevnetConfig (and optionally LlmqDevnetParams) to ClientConfig.devnet instead of setting config.llmq_devnet_params directly.
WalletInfoInterface delegation
packages/rs-platform-wallet/src/wallet/platform_wallet_traits.rs
Adds monitored_script_pubkeys method delegating to the inner core_wallet and imports ScriptBuf.
Swift example: devnet name storage & start
packages/swift-sdk/SwiftExampleApp/.../CoreContentView.swift, .../Views/OptionsView.swift
Adds platformDevnetName AppStorage and Devnet Name UI; trims/normalizes the value and passes optional devnetName into PlatformSpvStartConfig when starting SPV.

Workspace Dependency Revision Update

Layer / File(s) Summary
rust-dashcore crates revision update
Cargo.toml
Eight workspace dependencies from https://github.com/dashpay/rust-dashcore are bumped to commit eb889af13f667ed39c35e8e8a0830eeedf523476.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • QuantumExplorer

Poem

🐰 I nibble configs, hash by hash,
Hop devnet fields into the SPV cache,
Swift names trimmed, FFI listens with glee,
LLMQ params tucked where devnet can see,
Hooray — builds hop forward, light and brash!

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: enabling SPV functionality on devnet in the Swift example app, which is supported by changes across FFI, configuration, and UI layers.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ 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 chore/bump-rust-dashcore-eb889af1

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown
Collaborator

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

Verified codex-general's blocker against upstream source at eb889af1 and against cargo check. The workspace does not compile against the pinned revision: dash-spv's ClientConfig no longer exposes llmq_devnet_params (replaced by devnet: Option<DevnetConfig>), and key-wallet's WalletInfoInterface trait gained a required monitored_script_pubkeys method that PlatformWalletInfo does not implement. The PR cannot land as-is without follow-up callsite updates. Both Claude agents missed these regressions.

🔴 2 blocking

2 additional finding(s) omitted (not in diff).

🤖 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-platform-wallet-ffi/src/spv.rs`:
- [BLOCKING] packages/rs-platform-wallet-ffi/src/spv.rs:317-322: `platform-wallet-ffi` references `ClientConfig::llmq_devnet_params` removed at eb889af1
  Verified against the upstream source at rev `eb889af1` (cargo git checkout `rust-dashcore-c6b13647c01f74b9/eb889af`): `dash_spv::ClientConfig` no longer exposes a `llmq_devnet_params` field. The devnet surface was consolidated into a single `pub devnet: Option<DevnetConfig>` field (see `dash-spv/src/client/config.rs:25` and `:76`, with `with_devnet(DevnetConfig)` as the builder API at `:191`). This file still does `config.llmq_devnet_params = Some(LlmqDevnetParams { size, threshold })`, which fails to compile against the pinned revision and will block the entire workspace build (and any transitive consumer such as the Swift SDK). The import of `dashcore::sml::llmq_type::LlmqDevnetParams` at line 6 is now also dead code at this callsite. Callsite needs to be migrated to construct a `DevnetConfig` (e.g. `DevnetConfig::new(name).with_llmq_params(LlmqDevnetParams { size, threshold })`) and assign it via `config.devnet = Some(...)` / `with_devnet(...)`. Note: the codex agent flagged this; the Claude agents missed it.

In `packages/rs-platform-wallet/src/wallet/platform_wallet_traits.rs`:
- [BLOCKING] packages/rs-platform-wallet/src/wallet/platform_wallet_traits.rs:33: `PlatformWalletInfo` is missing `monitored_script_pubkeys` required by updated `WalletInfoInterface`
  Confirmed by running `cargo check -p platform-wallet-ffi` against the pinned revision: `error[E0046]: not all trait items implemented, missing: 'monitored_script_pubkeys'`. At `eb889af1`, `key_wallet::wallet::managed_wallet_info::wallet_info_interface::WalletInfoInterface` adds a required method `fn monitored_script_pubkeys(&self) -> Vec<ScriptBuf>` (see `key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs:87`). `PlatformWalletInfo` only implements the older surface, so `platform-wallet` fails to compile — which prevents reaching the `llmq_devnet_params` error above. The natural fix is to delegate to the inner `ManagedWalletInfo` (which already implements it at `:310`): `fn monitored_script_pubkeys(&self) -> Vec<ScriptBuf> { self.core_wallet.monitored_script_pubkeys() }`. Treating as a co-symptom of the same revision bump.

@shumkov shumkov changed the title chore(deps): bump rust-dashcore to dev HEAD (eb889af1) chore(deps): update rust-dashcore to latest version May 28, 2026
@shumkov shumkov changed the title chore(deps): update rust-dashcore to latest version chore: update rust-dashcore to latest version May 28, 2026
@shumkov shumkov self-assigned this May 28, 2026
@shumkov shumkov moved this to In review / testing in Platform team May 28, 2026
Wires the devnet identity through the example app so users can run
the SPV client against a `dashd -devnet=<name>` peer set:

- OptionsView: new "Devnet Name" text field under the existing
  Quorum URL field, backed by `platformDevnetName` UserDefaults.
- CoreContentView.startSync: reads the saved name and passes it
  to `PlatformSpvStartConfig.devnetName` when the active network
  is devnet. Without this the FFI now rejects the start with
  "devnet_name is required when network=Devnet".

Migrates `platform-wallet-ffi` and `platform-wallet` to the new
`dash-spv::DevnetConfig` surface (PR #788 upstream): the legacy
`ClientConfig::llmq_devnet_params` field is gone and the
`WalletInfoInterface` trait grew a `monitored_script_pubkeys`
method.
@shumkov shumkov changed the title chore: update rust-dashcore to latest version feat(swift-example-app): enable SPV on devnet May 28, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 28, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 87.33%. Comparing base (551241e) to head (9036567).
⚠️ Report is 1 commits behind head on v3.1-dev.

Additional details and impacted files
@@             Coverage Diff              @@
##           v3.1-dev    #3761      +/-   ##
============================================
+ Coverage     87.17%   87.33%   +0.15%     
============================================
  Files          2607     2590      -17     
  Lines        319589   317082    -2507     
============================================
- Hits         278602   276911    -1691     
+ Misses        40987    40171     -816     
Components Coverage Δ
dpp 87.73% <ø> (ø)
drive 85.95% <ø> (ø)
drive-abci 89.60% <ø> (ø)
sdk ∅ <ø> (∅)
dapi-client ∅ <ø> (∅)
platform-version ∅ <ø> (∅)
platform-value 92.17% <ø> (ø)
platform-wallet ∅ <ø> (∅)
drive-proof-verifier 49.14% <ø> (ø)
🚀 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.

Copy link
Copy Markdown
Collaborator

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

Cumulative incremental review at head 5811761. Both prior blocking findings from the 056ab3e review are FIXED at this head: (1) platform-wallet-ffi now constructs DevnetConfig::new(name).with_llmq_params(...) and assigns it via config.devnet = Some(devnet) at spv.rs:319-328, replacing the removed ClientConfig::llmq_devnet_params; (2) PlatformWalletInfo now implements the required monitored_script_pubkeys by delegating to core_wallet at platform_wallet_traits.rs:100-102. The new latest-delta surface (Swift platformDevnetName UserDefaults → PlatformSpvStartConfig.devnetName → FFI devnet_name C string) is wired end-to-end and the FFI already enforces network/devnet pairing and matched llmq params. One in-scope hardening suggestion remains: the FFI accepts empty ("") and BIP14-reserved-character devnet names from C callers, which would produce a malformed (devnet.devnet-) user agent. The Swift example app filters empty strings to nil before calling, so this PR's immediate path is unaffected; the public C ABI is the chokepoint where future callers (other language bindings, integration tests) cannot pre-filter.

🟡 1 suggestion(s)

1 additional finding(s) omitted (not in diff).

🤖 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-platform-wallet-ffi/src/spv.rs`:
- [SUGGESTION] packages/rs-platform-wallet-ffi/src/spv.rs:239-256: FFI accepts empty/whitespace `devnet_name` and produces malformed devnet user agent
  `platform_wallet_manager_spv_start` validates that `devnet_name` is non-null and that network/llmq pairing is consistent, but it does not reject an empty C string. A caller passing a valid pointer to `""` (or whitespace-only) enters the devnet branch, constructs `DevnetConfig::new("")`, and at line 279 rewrites the user agent to `/<base>(devnet.devnet-)/` — a substring Dash Core devnet peers will not accept, which is the exact failure mode this PR aims to eliminate. The Swift caller in `CoreContentView.startSync` happens to trim and convert empty to `nil` (CoreContentView.swift:591-596), so the example-app path is safe, but this C ABI is the only chokepoint for other consumers (future bindings, Rust integration tests, the `dash-spv` binary equivalent). Reject empty names at the same validation step that rejects null/wrong-network so the failure is synchronous on the FFI return rather than asynchronous after `spawn_in_background`. Optionally also reject BIP14-reserved characters (`/`, `(`, `)`) since they would similarly corrupt the user-agent string.

Without this guard the FFI accepts a `""` C string and constructs
`DevnetConfig::new("")`, which produces a `(devnet.devnet-)` user
agent that Dash Core devnet peers silently drop. The Swift example
caller already filters empties to `nil`, but the C ABI is the
chokepoint for future consumers without a pre-filter (other
language bindings, integration tests).

Mirrors `dash_spv::DevnetConfig::validate` so the rejection is
synchronous on the FFI return rather than asynchronous from
`spawn_in_background`.
@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented May 28, 2026

✅ 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: "7929f177d536b65aca3ae09fb60760905b4c95e229c63ab18687fa31fe9d9476"
)

Xcode manual integration:

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

Copy link
Copy Markdown
Collaborator

@thepastaclaw thepastaclaw left a comment

Choose a reason for hiding this comment

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

Code Review

The prior FFI validation finding was only partially fixed at head 9036567. Empty-string devnet_name is now rejected, but the explicit whitespace-only half of the prior finding remains valid because the new check only uses name.is_empty() and does not trim before building the devnet user agent and DevnetConfig.

🟡 1 suggestion(s)

🤖 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-platform-wallet-ffi/src/spv.rs`:
- [SUGGESTION] packages/rs-platform-wallet-ffi/src/spv.rs:264: FFI still accepts whitespace-only `devnet_name` values and produces a malformed devnet identity
  This change only rejects `name.is_empty()` and `name.contains('/')`. A whitespace-only C string such as `"   "` survives `CStr::to_str()?.to_string()`, is not empty, contains no slash, and therefore passes validation. It is then appended into the devnet user agent and passed to `DevnetConfig::new(name)`, so the prior finding's explicit whitespace-only case is still reproducible at the exported FFI surface even though the empty-string case is fixed. Trim before validating, or treat `name.trim().is_empty()` as invalid so whitespace-only input is rejected synchronously like the prior finding requested.

// integration tests) from a `(devnet.devnet-)` user agent that
// Dash Core peers silently drop.
if let Some(name) = devnet_name_str.as_deref() {
if name.is_empty() {
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.

🟡 Suggestion: FFI still accepts whitespace-only devnet_name values and produces a malformed devnet identity

This change only rejects name.is_empty() and name.contains('/'). A whitespace-only C string such as " " survives CStr::to_str()?.to_string(), is not empty, contains no slash, and therefore passes validation. It is then appended into the devnet user agent and passed to DevnetConfig::new(name), so the prior finding's explicit whitespace-only case is still reproducible at the exported FFI surface even though the empty-string case is fixed. Trim before validating, or treat name.trim().is_empty() as invalid so whitespace-only input is rejected synchronously like the prior finding requested.

source: unknown

@shumkov
Copy link
Copy Markdown
Collaborator Author

shumkov commented May 28, 2026

Superseded by #3763 — the dashcore bump + Rust API migrations identical to my first two commits already landed via #3762, so the unique value of this PR (Swift example-app devnet wiring + FFI hardening with whitespace trim) was carved out and reopened as a clean PR on top of v3.1-dev.

@shumkov shumkov closed this May 28, 2026
@github-project-automation github-project-automation Bot moved this from In review / testing to Done in Platform team May 28, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

2 participants