Skip to content

Tracking: Dash Platform usernames and DashPay contacts in dash-qt (--enable-platform-gui) #7512

Open

Description

@PastaPastaPasta

What / why

dash-qt has no Dash Platform support. This issue tracks adding the DashPay feature set of the mobile wallets to it: usernames (DPNS), DashPay profiles, contact requests, contact-to-contact payments and seed-only recovery. It must not couple dashd to Platform, and it must interoperate with the DashPay iOS and Android wallets.

The work is landing as small, stacked, reviewable PRs across dashpay/dash and dashpay/platform. This issue is the cross-repo map.

Current status (2026-09-28)

All PRs below are open and ready for review unless noted. The whole stack was verified end to end on the live PV13 testnet on 2026-09-28, including interop with the DashPay iOS app. Screenshots and their manifest.

dashpay/platform

PR What State
dashpay/platform#5160 feat(sdk): route DAPI connections through a SOCKS5 proxy (plus an IPv6-endpoint panic fix) ready for review
dashpay/platform#4633 feat(sdk): dash-platform-cxx, a thin CXX shell over dash-sdk for C++ embedders; stacked on dashpay/platform#5160 ready for review
dashpay/platform#4964 fix(sdk): no panic in DapiClient::new on an empty address list merged
dashpay/platform#4965 test(sdk): cargo-fuzz harness over drive-proof-verifier FromProof draft (fuzz campaign running)
dashpay/platform#4963 feat(sdk): reject response metadata from an unexpected chain id closed by the maintainer; the shell does the check
dashpay/platform#4632 pure DPNS/DashPay document builders shared with embedders closed; the SDK-first shell does not need them

dashpay/dash

Each PR's head branch ends at its own commit on one linear stack. Each body says which commit to review from.

PR What Depends on
#7623 C1 build: depends builds the Dash Platform CXX bindings behind PLATFORM_GUI=1 (Rust toolchain, --enable-platform-gui, Windows DLL allowlist, linux64_platform_gui CI) —
#7763 C2 wallet: DIP-15 compact xpub, accountReference MAC and asset-lock seams — (no Rust)
#7764 C3 chainparams: Platform Tenderdash chain id — (no Rust)
#7670 C4 client library over dash-platform-cxx; sendCoins surfaces a mempool rejection; Node::isReachable C1, C2, C3
#7671 C5 DashPay tab, opt-in, privacy gating and network route C4
#7765 C6 usernames: identity and DPNS registration, dashboard C5
#7766 C7 profiles and contacts (DIP-15) C6
#7767 C8 contact payments, seed recovery and identity details C7

The Guix enablement follows as a new PR once the depends approach in #7623 is accepted.

Merged earlier: #7511 (DIP-14 Derive256), #7581 (Platform key provider, data records and DIP-15 friendship keychain seams), #7591 (masternode Platform endpoints, quorum keys and islocks through the node interface), and dashpay/platform#4344, dashpay/platform#4345 and dashpay/platform#4388.

Architecture

  • Compile-time optional: --enable-platform-gui (default off) and the depends knob PLATFORM_GUI=1, following MULTIPROCESS. A default build is unchanged. dashd, dash-cli, dash-tx, dash-wallet and the fuzz binary never link Rust, and check-no-rust.py enforces that in CI.
  • SDK-first thin shell. The Rust code lives in dashpay/platform as dash-platform-cxx, a thin cxx shell over dash-sdk with no protocol logic of its own. The SDK owns query construction, DAPI transport, retries and address banning, proof verification, protocol-version tracking and freshness. Core pins the shell by commit, and builds it in depends from two sha256-pinned archives, offline.
  • Local trust anchor. Core pushes evonode endpoints from its deterministic masternode list, the Platform quorum keys from its LLMQ store and its best ChainLock height. Every read is proved against those. There is no trusted HTTP service, no seed list and no remote quorum source. The chain id comes from CChainParams.
  • Key custody. Private keys never cross the FFI. The wallet receives the full signable preimage, hashes and checks it, and signs through a kind-scoped, move-only SigningOperation. ECDH and the accountReference MAC are computed inside the wallet, and the MASTER key is refused for both.
  • Network privacy. DashPay uses Core's own network settings. It connects to evonodes the way Core connects to peers (-proxy, -onion, -onlynet, the Tor controller), through SOCKS5 with per-connection isolation for -proxyrandomize. It never falls back to a direct connection. The opt-in states what the answering evonode can see.

Decisions log

Open asks

  1. Core maintainer decision on build: build the Dash Platform CXX bindings in depends behind PLATFORM_GUI=1 #7623: can depends carry a prebuilt, sha256-pinned Rust toolchain behind PLATFORM_GUI=1 (default builds unchanged, Rust only in dash-qt)? The C4–C8 PRs build on this answer. The C2 and C3 PRs are useful either way.
  2. Depends mirror upload: before build: build the Dash Platform CXX bindings in depends behind PLATFORM_GUI=1 #7623 merges, a maintainer needs to put the Platform source tarball and the crate bundle for the pinned commit on the depends sources mirror. The file names and sha256s are in build: build the Dash Platform CXX bindings in depends behind PLATFORM_GUI=1 #7623.
  3. Guix PR: after (1), a new PR enables PLATFORM_GUI=1 in Guix release builds and runs the two-builder reproducibility check.
  4. Platform review: feat(sdk): route DAPI connections through a SOCKS5 proxy platform#5160, then feat(sdk): add dash-sdk-cxx, a C++ binding of dash-sdk for Dash Core platform#4633.

Known gaps

  • In Add contact, the "Can't receive contact requests" note appears only after the row is selected. The DashPay iOS app checks each row as it scrolls into view. This is a minor UX gap.
  • A superseding contact request that cannot be decrypted leaves the contact on its old chain, without an error on the row, until a newer request arrives. The payment effect matches the mobile wallets' behaviour.
  • Not yet run: Guix and armhf, ppc64 and riscv64 builds of the bindings (the Guix PR's job), or a Tor round with the proxy passthrough.

Activity

  1. PastaPastaPasta commented on Aug 13, 2026

    @PastaPastaPasta
    MemberAuthor

    Seed-only recovery of Platform state — design answer

    Raised at the 2026-08-12 dev sync (kwvg): DashPay wallet data is stored as opaque per-wallet records — how does mnemonic-only recovery restore Platform state? Investigated against both the current implementation and the mobile wallets' shared recovery policy (rs-platform-wallet, the crate behind dashwallet-ios/android). Design below ships in v24 with the wallet wave; implementation is on the reference branch (PastaPastaPasta#67) first, then extracted into the train.

    What is derivable from seed alone: every private key (identity auth m/9'/coin'/5'/0'/0'/i'/k', asset-lock funding, DIP-15 friendship chains). What is not: the local records — identity id/state, contact set, payment cursors, and the DPNS preorder salt (CSPRNG).

    Recovery flow (auto-probe on wallet load when a seed exists but no identity record; bounded ~20s, never blocks wallet function; mirrors mobile's policy):

    1. Identity: scan MASTER auth keys (key index 0, identity index gap limit 5) via the proof-verified getIdentityByPublicKeyHash query, with a three-way outcome — found / proven-absent / network-incomplete — so an outage is never misreported as "no identity". Materialize the full on-chain key set with per-key verification against published pubkeys.
    2. Username: namesOfIdentity (+ contested-state check) rebuilds the registration record.
    3. Contacts: contact requests fetched in both directions (the sent side is what turns established contacts back from bare incoming requests); xpubs decrypted via the seed-derived ECDH keys; friendship receiving keychains re-imported as private descriptors.
    4. Rescan from the earliest contact-request core height, so pre-restore inbound DashPay payments appear.
    5. Payment cursors: rebuilt by matching derived outbound scripts (5× the DIP-15 gap = 100 per contact, scriptPubKey-based) against wallet tx history.

    Documented limitation (same as both mobile wallets): an in-flight DPNS registration (preorder broadcast, domain not yet) is not recoverable seed-only — the salt is random. A REGISTERED identity recovers fully; mid-registration needs the full backup. Follow-up idea recorded, not v24: derive the salt deterministically (e.g. HMAC of an auth key and the normalized label) — consensus-transparent, would make even mid-registration state recoverable, and no client does it today.

    Full backup/restore (backupwallet/restorewallet) remains the complete-state path and is unaffected.


    🤖 Posted autonomously by Claude on behalf of pasta.

  2. PastaPastaPasta commented on Aug 13, 2026

    @PastaPastaPasta
    MemberAuthor

    Guix reproducibility confirmed for the Rust/Platform-enabled build.

    Two independent builders built commit c9d6fbd459d9 with PLATFORM_GUI=1 HOSTS=x86_64-linux-gnu — the GitHub-hosted ubuntu-24.04-arm runner (workflow run 31720606525) and a local OrbStack container — and all three artifacts are bit-identical, including the debug tarball:

    ee1a85a060178923b6eb10a84d3781a087103b1393657be3f726a2199f8c3701  dashcore-23.1.8-1380-gc9d6fbd459d9.tar.gz
    620f0b732db138ac637001266e488c6e80437858a36e417a1c3ec06d190ec64a  dashcore-23.1.8-1380-gc9d6fbd459d9-x86_64-linux-gnu-debug.tar.gz
    c1033b0e6a92968a4e41766fdc41db1329ebc5f1625875457f8ddc4eef078f4e  dashcore-23.1.8-1380-gc9d6fbd459d9-x86_64-linux-gnu.tar.gz
    

    Scope of the claim: both builders are aarch64 hosts cross-compiling to x86_64-linux-gnu, so this proves host-to-host reproducibility between independent environments, not yet reproducibility across differing build architectures — an x86_64-host run of the same commit would close that gap.

    Getting there required five bring-up fixes on this branch, all of which are Guix-environment issues rather than Rust-integration ones: patchelf and zlib added to the Guix manifest (the prebuilt rust toolchain's ELF interpreter fix silently skipped without patchelf, and rustc needs libz at runtime), lbzip2 added (mbedtls is the first .tar.bz2 depends package to reach the Guix path), the rustc sysroot lib dir on LD_LIBRARY_PATH for cargo build scripts (the Guix ld wrapper strips RPATH by design), and an archive rescan for the cxxbridge↔dashrust mutual references.

    One latent hazard worth recording: Rust does not get a --remap-path-prefix equivalent to the C++ -ffile-prefix-map. It cannot bite in the standard flow because every builder compiles at the same in-container path, but a builder using a non-canonical mount point would see a differing debug tarball while the stripped tarball still matched.


    🤖 Posted autonomously by Claude on behalf of pasta.

  3. PastaPastaPasta commented on Aug 20, 2026

    @PastaPastaPasta
    MemberAuthor

    Status update (2026-08-20): the train has been restructured around the Platform-owned CXX architecture — all Rust/CXX bindings now live in dashpay/platform (dashpay/platform#4416, packages/rs-platform-cxx) and Core consumes the prebuilt archive through depends. #7580 is closed as superseded.

    Merged: #7581 (Platform key provider, records, DIP-15 friendship seams — reworked to the typed PlatformKeyResult API, descriptor-root derivation), #7591 (node seams), #7600/#7616 (provider tx interfaces).

    In flight: #7617 (wallet UTXO reconcile fix).

    The remaining series, extracted from the composite integration branch (PastaPastaPasta#67, CI fully green):

    Gates: dashpay/platform#4388 → #4389 → #4416 for the depends pin; a descriptor-wallet E2E rerun before #7627 undrafts; a PLATFORM_GUI Guix run before #7628 undrafts.


    🤖 Posted autonomously by Claude on behalf of pasta.

  4. PastaPastaPasta commented on Sep 8, 2026

    @PastaPastaPasta
    MemberAuthor

    Platform-side status update (2026-09-07): the earlier platform stack (dashpay/platform#4478, #4389, #4433, #4416, plus #4464) is closed and replaced by three PRs rebuilt to reuse the workspace's existing patterns after review:

    Core-side consequences for #7623 and up: re-pin platform_cxx to a commit on the #4620 branch; set_context now takes (network, platform_quorum_type, protocol_version, activation_height) and update_quorum_keys no longer takes a per-call quorum type; the standalone/ build directory and install.sh are gone — build -p dash-platform-cxx from the workspace root and install target/<profile>/include + libdash_platform_cxx.a. The DashConnect bridge additions still need porting onto the new crate.


    🤖 Posted autonomously by Claude on behalf of pasta.

  5. PastaPastaPasta commented on Sep 8, 2026

    @PastaPastaPasta
    MemberAuthor

    SDK-first rebuild of the Platform GUI integration (2026-09-08)

    QuantumExplorer's question on dashpay/platform#4618 ("why are you not just using the SDK?") was tested rather than argued. Result: the normal dash-sdk, networking included, passes Core's requirements, so the series is rebuilt around it. The transport-free design (C++ transport + wire-request reverse decoding) is superseded.

    Measured before choosing (Platform v4.2-dev @ e037d42dd6, Rust 1.92):

    • Cross cargo check of dash-sdk (no default features): x86_64/aarch64-linux-musl, x86_64-pc-windows-gnu, and riscv64gc-unknown-linux-gnu (in a container with a pinned protoc; the distro protoc version string breaks tenderdash-proto's build script, same as depends already handles). PowerPC and armhf are outside rust_stdlib.mk's target list in either design.
    • Live testnet from a release-built C++ driver over the real bridge: getIdentity, nonce, DPNS resolve (registered + proven absent), names-of-identity, prefix search, profile, contact requests, contested vote state and a rejected broadcast, all proof-verified against quorum keys exported from a synced node, 0.3 to 2 s each; bit-flipped quorum keys fail at the BLS check. A statically linked x86_64-unknown-linux-musl build of the driver ran under emulation with identical results.
    • Cost: 337 crates vs 281 for the transport-free crate; stripped C++ binary delta 6.5 MB (was ~2.5 MB); macOS needs Security + CoreFoundation (rustls native roots; SystemConfiguration from the August note is not needed), Windows ws2_32 bcrypt crypt32 userenv ntdll. All within symbol-check.py's allowlists.
    • Vendoring: cargo vendor --locked fails on v4.2-dev for reasons unrelated to networking (two dual-source packages); fixed in build: make the workspace lockfile vendorable with --locked platform#4631. Whole-workspace vendor: 840 crates, 150 MB archive.
    • What the SDK lacked and now has in the crate: chain-id binding and the ChainLock staleness floor (the SDK only had a signed-time window + monotonic height); SOCKS/Tor routing is still absent from rs-dapi-client (tonic's connector can take one; upstream follow-up).
    • Unknown until run: Guix reproducibility of the SDK archive across independent builders and build architectures.

    New series (each N+1 is a draft until its base is ready):

    Disposition of the old series (nothing closed yet):

    PR Disposition
    dashpay/platform#4618 Not needed for Core: the SDK retains the rich query it built and verifies against it, so no wire request is reconstructed. Its dpp bound fix is #4629's. No other consumer of platform-query-wire found. Superseded once #4633 lands.
    dashpay/platform#4619 Builders half carried into #4632 verbatim; FromProof<GetDocumentsRequest> half not needed. Superseded.
    dashpay/platform#4620 Superseded by #4633 (same crate name, provider/signer/builders reused, verify-from-bytes layer replaced by the SDK).
    dashpay/platform#4629 Independent, still valid, unchanged.
    #7626 Superseded by #7670. Transport/verify code and its unit tests retired; DPP byte-exactness tests, wallet-key tests and decoder fuzz targets kept. Its security fixes map to: chunk/overflow/timeouts → SDK transport; freshness floor + chain-id → dash-platform-cxx::client; "empty == proven absent" → SDK FromProof + client.
    #7627 Superseded by #7671 (7 lines changed at the seam).
    #7628 Superseded by #7672 (drops lbzip2, otherwise identical).

    🤖 Posted autonomously by Claude on behalf of pasta.

  6. PastaPastaPasta commented on Sep 25, 2026

    @PastaPastaPasta
    MemberAuthor

    Update on follow-up P1 (SdkBuilder::with_expected_chain_id in rs-sdk): dashpay/platform#4963 is closed and won't be merged.

    Reasoning (full version on #4963): the chain id is already covered by the quorum signature, so the check adds no security. Forging a different chain id breaks the signature. Other networks' quorums aren't in our Core chain. Mainnet has only ever had one Platform chain (evo1). The only case it covers is operational and testnet-only: after a Platform reset, a stale node serving the old chain can confuse a long-running client's height watermark. That isn't worth a breaking change to StaleNodeError in rs-sdk.

    Effect on this tracker: none on the critical path. P1 was never a blocker. The design keeps the chain-id check in the rs-platform-cxx shell: after signature verification, metadata.chain_id is compared with CChainParams::platform.chain_id (C3), before the shell's own height watermark. The SDK's own height watermark stays off (with_height_tolerance(None)), so a foreign-chain proof can't advance any SDK state. The platform/chain-id wallet record and PLATFORM_NETWORK_CHANGED (C5) stay as designed, since they handle the testnet-reset UX. The one thing that changes is the step "when P1 merges, delete the shell check and re-enable the SDK watermark"; that step is dropped.


    🤖 Posted autonomously by Claude on behalf of pasta.

  7. PastaPastaPasta commented on Sep 28, 2026

    @PastaPastaPasta
    MemberAuthor

    The Platform GUI stack is now published and ready for review. It is rebuilt SDK-first and verified end to end on the live testnet on 2026-09-28, including interop with the DashPay iOS app.

    dashpay/dash (from PastaPastaPasta/dash, stacked in this order):

    dashpay/platform:

    Closed as superseded: #7669 (folded into #7623) and #7672 (Guix; a new PR follows once #7623's approach is accepted).

    Screenshots: https://github.com/PastaPastaPasta/dash-ui-artifacts/tree/main/dashpay-gui-2026-09-final


    🤖 Posted autonomously by Claude on behalf of pasta.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions