feat(qt): Dash Platform usernames, profiles, and DashPay contacts in dash-qt#49
Draft
PastaPastaPasta wants to merge 33 commits into
Draft
feat(qt): Dash Platform usernames, profiles, and DashPay contacts in dash-qt#49PastaPastaPasta wants to merge 33 commits into
PastaPastaPasta wants to merge 33 commits into
Conversation
Introduce the build and UI skeleton for Dash Platform (usernames / DashPay) support in dash-qt, keeping dashd and consensus code fully independent of Platform: - new configure flag --enable-platform-gui (default off), gating everything - depends: new optional mbedtls package (PLATFORM_GUI=1), for the future DAPI TLS client; config.site auto-enables the flag - vendor BLAKE3 1.8.5 (portable C only) under src/crypto/blake3/, used exclusively for GroveDB merk proof verification in the GUI client library - new src/platform/ Qt-free client library (libdash_platform.a, linked into dash-qt and test binaries only) seeded with per-network parameters and the well-known DPNS/DashPay system contract ids - new DashPay tab (placeholder page) wired through BitcoinGUI/WalletFrame/ WalletView following the Masternodes tab pattern, with an OptionsModel ShowPlatformTab toggle and options dialog checkbox; the tab is only offered on networks where Platform is deployed - lint/non-backported list updates for the new Dash-specific paths Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Add Dash Platform HD key derivation to the wallet, exposed to the GUI through new interfaces::Wallet methods that never hand out raw private keys (sign/pubkey/ECDH only, precedent: signSpecialTxPayload): - DIP-14 (256-bit child index) derivation: CKey::Derive256 / CPubKey::Derive256 + DIP14Hash, with BIP32 compatibility mode for sub-2^32 indexes; verified against all four official DIP-14 test vectors - wallet/platformkeys: DIP-13 identity authentication and funding paths (m/9'/coin'/5'/...) and DIP-15 friendship paths (m/9'/coin'/15'/account'/idA/idB, ids non-hardened per dashj), path walking from the wallet BIP39 seed (legacy CHDChain and descriptor wallets), and ECDH secrets using the libsecp256k1 KDF (matches dashj KeyCrypterECDH used for DashPay contact request encryption) - enable the vendored secp256k1 ECDH module when --enable-platform-gui - interfaces::Wallet: getPlatformPubKey, signPlatformDigest, platformECDHSecret, getFriendshipXpub (stubbed when the feature is compiled out); seed access follows the getMnemonic precedent and respects wallet encryption/locking Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Wallet: interfaces::Wallet::createAssetLockTransaction builds a signed TRANSACTION_ASSET_LOCK special transaction (single OP_RETURN burn output carrying the credit amount, CAssetLockPayload with one P2PKH credit output) funded via CreateTransaction and signed as a whole, ready for commitTransaction. This is the L1 leg of Platform identity funding. Node: expose locally synced data the GUI Platform client needs for verification and asset lock proofs: - LLMQ::getPlatformQuorums(llmq_type): active quorum hashes + BLS public keys (basic scheme) so Platform state-root quorum signatures can be verified against the node's own quorum list (no external trust source) - LLMQ::getInstantSendLock(txid): serialized islock for building InstantAssetLockProofs - MnEntry::getPlatformHTTPSAddrs(): evonode DAPI gateway endpoints from the extended masternode address list Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Qt-free contract between the DAPI transport implementation and the GUI service layer: async PlatformClient (every query issued with prove=true and verified before callbacks fire; endpoints from the deterministic MN list, quorum keys injected from the node) and the plain structs the GUI consumes (Identity, DpnsName, Profile, ContactRequest, contested name state, broadcast results). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…builder contract - Wallet DB: new DBKeys::PLATFORM_DATA generic key/value records (opaque to the wallet, travel with backups) with CWallet load/write/prefix-scan and interfaces::Wallet::writePlatformData/getPlatformData. The Platform GUI persists its identity/username/contact flow state here so multi-step flows survive restarts and are recoverable from backups. - src/platform/statetransitions.h: contract for DPP state transition construction (identity create from asset lock proofs, DPNS preorder/domain, DashPay profile/contactRequest), with signing delegated to wallet callbacks so keys never leave the wallet. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pure-C++ verification of DAPI GroveDB proofs, mirroring the storage-free
verify slice of dashpay/grovedb v5.0.0 and validated byte-for-byte against
vectors generated from the real Rust grovedb:
- serialize.{h,cpp}: bincode-v2 big-endian varint reader (+zigzag), LEB128
helpers, fixed-width BE readers, exception-free Result-style cursor
- proof/merk.{h,cpp}: blake3 node hashing (value/kv/kv_digest/node/combine,
sum variant), the full op-stack decoder and replay machine, and
query-completeness + absence-proof verification (a node cannot silently
omit matching results)
- proof/grovedb.{h,cpp}: Element decode (Item/Reference/Tree/SumItem/
SumTree + reference-path resolution), GroveDBProof V0/V1 envelope decode,
and recursive layered verification binding each subtree to its parent via
combine_hash(H(element), child_root)
- contrib/devtools/platform-test-vectors: Rust generator (developer tool,
not built by CI) emitting deterministic element/merk/grovedb vectors
- tests: 8 cases incl. ~2500 single-byte-flip forgery attempts, wrong-root,
truncation, and query-completeness attacks — all must fail verification
Also drop an accidentally committed generated moc file and gitignore it.
Notable finding: V0 tree-result proofs do not bind the tree element bytes;
the GUI must require V1 envelopes when a queried result is itself a tree.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pure-C++ encode/decode of Dash Platform Protocol objects and the state
transitions the GUI broadcasts, pinned to dashpay/platform v4.0.0
(protocol version 12) and validated byte-for-byte against vectors from the
real Rust rs-dpp:
- dpp/bincode: bincode-v2 big-endian varint reader/writer (zigzag signed,
versioned-enum discriminants) matching rs-platform-serialization
- dpp/document: platform Value / document property encoding and the
document id derivation used by the four GUI document types
- dpp/identity: Identity / IdentityPublicKey decode into GUI types
- dpp/statetransitions: IdentityCreate (instant + chain asset lock proofs),
DPNS preorder/domain, DashPay profile create+replace and contactRequest;
signing delegated to wallet callbacks (double-SHA256 of signable bytes,
65-byte compact recoverable ECDSA, header 27+recid+4); plus salted domain
hash, homograph-safe label normalization, and the DPNS v1 contested-name
rule (normalizedLabel ^[a-zA-Z01-]{3,19}$)
- contrib/devtools/platform-dpp-vectors: Rust vector generator (dev tool)
- tests: byte-exact signable bytes/digests/serialized STs, document ids,
salted hashes, identity ids, identity decode + tamper negatives (9 cases)
Key correction over initial notes: DPP bincode is big-endian (same config
as the grovedb envelope), and batch transitions serialize as
BatchTransition::V1 / DocumentBaseTransition::V1.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Hand-rolled DAPI transport that needs no gRPC/HTTP-2/protobuf library: - transport/protobuf: minimal protobuf wire reader/writer for the DAPI Platform messages the GUI uses (field numbers from platform.proto) - transport/tls: blocking TLS client over mbedTLS 3.6 LTS; transport certs are intentionally not chain-verified (evonodes are reached by bare IP) — integrity comes from proof + quorum-signature verification of every response, matching the reference SDKs - transport/grpcweb: unary gRPC-Web calls over HTTP/1.1 (5-byte frame header + trailers frame), including de-chunking, as served by DAPI's Envoy gateway - transport/cbor: minimal CBOR writer for getDocuments where/order_by operands Validated against live testnet evonodes: getStatus and getIdentity (prove=true, returning a 2.3 KB GroveDB proof) both round-trip correctly. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A developer harness that exercises the platform client against live Dash testnet Platform, end to end, using only the GUI's own state-transition builders and gRPC-Web transport: - faucet.py: fund a testnet address via the faucet's browser flow (Playwright) - make_assetlock.py: create + islock a TRANSACTION_ASSET_LOCK via RPC - e2e.cpp: asset lock -> IdentityCreate -> DPNS preorder -> domain -> resolve Verified on testnet (DAPI v4.0.0): registered identity 6ed0631afd75e846fd527761ca48c322553fece191bf2b96889f7ff6afdc7be8 with username 'qte2e8df49727', independently re-confirmed with prove=true from unrelated evonodes. This proves IdentityCreate/DPNS construction, signing and transport are correct against live Platform. Also fix identityflow to use the asset lock payload's credit-output index (0) rather than the OP_RETURN vout when building the asset lock proof. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Targeted decoders for the platform-serialized documents the GUI reads back: DPNS domain (label, normalizedLabel, records.identity), DashPay profile (displayName, avatarUrl), and contactRequest (toUserId, encryptedPublicKey). Extract the GUI-relevant fields over the known v1 property order; a full contract-schema-driven document deserializer is a documented follow-on. The DPNS decoder is validated against a real testnet domain document (extracts the correct resolving identity). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Complete the GUI-facing platform stack and wire it into dash-qt: - platform/drive: per-query verifiers (identity balance/revision/nonce/keys, full identity, id-by-public-key-hash) mirroring rs-drive verify functions, plus the Tenderdash quorum threshold-signature check binding a verified GroveDB root to a signed Platform block (BLS basic scheme via dashbls). Validated against vectors from the real Rust rs-drive + rs-tenderdash-abci. - platform/transport/client: the async PlatformClient — worker thread, evonode endpoint pool from the masternode list, quorum-key lookup wired to the node, and per-query verify+decode (identity reads are proof-verified; documents decoded via the DPP layer). - qt/platform: PlatformService (per-wallet orchestrator, marshals client callbacks to the GUI thread, feeds node context), resumable IdentityFlow and ContactFlow state machines persisted in wallet-DB records, the CreateUsername wizard, the DashPay dashboard page, and contact-request ECDH/AES crypto. Verified: dash-qt links the whole feature (553 platform symbols); dashd and the other binaries contain ZERO platform symbols — Core stays fully independent of Platform. All four platform test suites pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ness getIdentityKeys takes a KeyRequestType sub-message at field 2 (AllKeys) and prove at field 5, not prove at field 2 like the balance queries. With this fix the client's full-identity read verifies end to end. Add contrib/devtools/platform-e2e/readverify.cpp: proves the verified READ path against live testnet — transport fetches getIdentityBalance/ BalanceAndRevision/Keys with prove=true, the GroveDB proofs verify to one root, and the LLMQ_25_67 quorum BLS threshold signature binds that root to a signed testnet Platform block. Confirmed on the E2E-registered identity (balance 833498000 credits, 2 keys), completing the read direction to match the already-proven write direction. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Round out the DashPay GUI: - ContactsModel/ContactsPage: table of established contacts plus incoming and outgoing contact requests, refreshed from the DashPay contactRequest documents, embedded in the dashboard - UsernameSearchDialog: search-as-you-type over DPNS names to find and add contacts - ProfileDialog: view/edit the wallet's DashPay profile (display name, public message, avatar URL) and broadcast a profile state transition - PlatformService gains refreshContacts() and updateProfile() dash-qt builds with the complete feature; all four platform test suites pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The per-wallet PlatformService owns its IdentityFlow/ContactFlow state machines and the flows call back into the service — the same intentional cycle shape as qt/*tablemodel <-> qt/walletmodel. Add both to the expected circular-dependency list and remove a duplicated include. Verified the feature is optional: a full build WITHOUT --enable-platform-gui produces dashd and dash-qt with zero platform symbols. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…t document decode Fixes found while running the live-testnet contact round-trip: - Identity nonce and contract-nonce queries now request prove=true and verify the Drive proof instead of trusting the scalar value path. - Drive proofs may be signed by an older Platform quorum that is still consensus-valid; export the full keepOldKeys retained-quorum window from the node instead of only the signing-active set, and match Proof.quorum_hash in its DAPI (display) byte order explicitly. - namesOfIdentity is now implemented (was stubbed to an empty result). - Stored-document decoding follows rs-dpp DocumentV0 serialize_v0/v1/v2 exactly (bincode varints, timestamp bitmap, presence markers for optional properties) instead of the previous approximate reader. - Add contested_identity_funding_amount (0.2 DASH vote reserve plus fee headroom) to the per-network parameters. - Extend the Rust vector generators and C++ unit tests to cover the new query and decode paths. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…estinations Adds the wallet seams DashPay contact payments are built on: - importFriendshipKeychains derives the local DIP-15 receiving chain (m/9'/coin'/15'/account'/sha256(myId)'/sha256(theirId)') and imports it as a ranged private pkh descriptor. The contact's own receiving chain is deliberately NOT imported: if its scriptPubKeys were IsMine, every payment to the contact would decompose as a payment-to-self showing only the fee. Contact payment addresses are instead derived statelessly from their xpub via getFriendshipPaymentDestination, with the per-contact cursor kept in wallet platform-data records. - DescriptorScriptPubKeyMan::IsMine reports ISMINE_WATCH_ONLY rather than ISMINE_SPENDABLE for public-only descriptors mixed into a signing wallet (descriptor watch-only and external-signer wallets keep their existing semantics), with unit test coverage. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Completes the contact round-trip in the GUI and reworks the DashPay
surfaces around how a novice actually uses them:
Send tab
- The recipient field accepts DashPay usernames: a permissive entry
validator (DPNS labels are not Base58-safe), debounced proof-backed
resolution, and a trailing status icon inside the field (pending /
verified / failed with tooltip) so the form never reflows. Failed
lookups reuse the field's invalid-input treatment.
- An "@" tool button opens a picker over established contacts; the
DashPay dashboard and contacts list can also prefill the Send tab.
- Sends and receives share one address-book label ("user (DashPay)"):
the service labels the resolved destination and the first receiving
addresses, and the Label field mirrors the address book instead of
inventing its own value, so both directions match in history.
Contact flow
- Accepting a request resolves the sender's identity key, decrypts the
ECDH-encrypted friendship xpub, imports the receiving keychain,
reciprocates, and confirms via a proven re-query.
- Outgoing requests are confirmed against Drive before being reported
as sent.
DashPay tab
- Dashboard header with generated avatar, username, profile line, and
proof-verified credit balance; quick actions (send to contact, find
people, edit profile); a banner for pending incoming requests.
- Registration re-entry: the wizard reopens on its live progress page
mid-flow, and a failed registration resets and restarts from name
entry ("Try again").
- Contacts list with plain-language colored statuses, tooltips,
contextual accept/pay actions, double-click to pay, and empty-state
guidance. Username search annotates results that are yourself,
already contacts, or already invited.
- Profile loading distinguishes verified absence ("No profile yet")
from lookup failure (auto-retry) instead of showing a permanent
loading state.
- A new AmountTemporarilyUnavailable send error distinguishes
"waiting on pending funds" from a plain insufficient balance, and
UnlockContext gained a move constructor for the async accept path.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
|
Important Review skippedDraft detected. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
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. Comment |
The Rust vector-generator crates (platform-dpp-vectors, platform-drive-vectors, platform-test-vectors) are development tools that are never built by Dash Core's build system or CI; keeping them in contrib/ pulled Rust tooling into the core tree for no benefit. They now live at github.com/PastaPastaPasta/dash-platform-test-vectors. The generated fixtures remain committed under src/test/data/platform/ and the unit-test references point at the new home. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Like the vector generators, contrib/devtools/platform-e2e is developer tooling never built by Dash Core's build system or CI. It now lives at github.com/PastaPastaPasta/dash-platform-e2e, which documents how to build its drivers against a dash checkout configured with --enable-platform-gui. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The merk and grovedb proof verifiers carried two verification branches no vector executed: right-to-left traversal (the mirrored bound-proving and terminate logic in ExecuteProof) and conditional subquery branches (RecursiveQueryItems / HasSubqueryOrMatchingInPathOnKey). Regenerate the fixtures with the extended platform-test-vectors crate (all pre-existing vectors reproduce byte-identically from the pinned grovedb v5.0.0 tag): - eight left_to_right=false merk vectors (present/absent keys, ranges, limits, sum trees) plus an RTL grove query through a layered proof; - three conditional-subquery grove vectors (conditional only, conditional with default branch, conditional with a subquery_path) whose per-byte corruption sweeps now exercise those code paths; - a merk_query_completeness_rtl case proving abridged data is still detected when traversing right-to-left; - ParseGroveQuery support for the conditional_subquery_branches fixture field. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
getContestedNameState was a stub returning an empty state, so an active masternode vote (or a locked name) was indistinguishable from an available name. Implement getContestedResourceVoteState end to end: - drive::VerifyContestedVoteState mirrors rs-drive's ContestedDocumentVotePollDriveQuery::construct_path_query (VoteTally with locked/abstaining tallies) and verify_vote_poll_vote_state_proof_v0 over the votes tree [[112], [0x63], [0x70], contract, doc type, [1], index values...], including the bincode decoder for the awarded/locked ContestedDocumentVotePollStoredInfo item; - the gRPC-Web client issues the request with prove=true, verifies the GroveDB proof and binds the root to a locally known platform quorum key before any result is surfaced; - drive_query_vectors gains active/finished/absent contest fixtures built from the same synthetic Drive layout, with the stored info serialized by the real rs-dpp (the whole fixture set regenerates because the votes subtree changes the synthetic root hash; quorum_sig_vectors re-sign the new balance root); - platform_drive_tests decodes all three fixtures and rejects corrupted proofs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Use the proof-verified vote state where the GUI previously only inferred contest status from domain-document absence: - name availability for contested labels now also requires a proven-absent contest, so a name mid-vote (or locked) no longer shows as available; - IdentityFlow::checkContestedOutcome fails the registration with a clear message when masternodes lock the name or award it to another identity, instead of polling forever; - the dashboard's contested banner shows live tallies (own votes, best rival, abstain, lock) via PlatformService::checkContestedNameState. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reader::Next computed m_pos + len for a length-delimited field where len is an attacker-controlled protobuf varint up to 2^64-1. On a malicious response this wraps and passes the bound check, then subspan() reads out of bounds — reachable by any on-path attacker since the gRPC-Web transport does not authenticate the TLS peer. Compare against the remaining byte count instead (m_data.size() - m_pos never underflows because m_pos <= size()), and use the same non-overflowing form for the fixed 32/64-bit reads. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
IdentityFlow::save() ignored the wallet-DB write result, and start() broadcast the asset-lock funding transaction regardless. A DB write failure between deriving the funding key and committing the transaction left a funded identity flow with no resumable record, orphaning the asset lock from the GUI. save() now returns the write result and start() aborts before commitTransaction() when the pre-broadcast persist fails, leaving the wallet untouched. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…lopes Three related hardenings to the network verification path (TLS is unauthenticated by design, so these are reachable by any on-path attacker, not just a malicious evonode): - Root consistency: DoGetIdentity verified balance, revision, and keys as three separate DAPI proofs but never checked their GroveDB roots matched, so a peer could assemble one identity from independently valid states at different heights. Require the three roots to be equal (the invariant VerifyFullIdentity already implements); a transient block boundary makes the query retryable. - Freshness: signed proof metadata had no anchor to local chain state, so a stale-but-validly-signed response could be replayed. Add BindAndCheckFresh, which after the quorum-signature binding enforces (a) session-monotonic platform height and (b) a coarse core-ChainLock floor fed from Node::LLMQ::getBestChainLock via the new updateCoreChainLockedHeight seam. - V1 envelopes: the lenient V0 GroveDBProof format does not bind the serialized element bytes of a non-empty tree returned without a subquery, letting a downgraded proof forge those bytes under the signed root. Current Platform only emits V1, so the Drive query chokepoint (RunQuery) now rejects V0. The V0 decoder is retained for the proof-level unit tests, which assert the reported envelope version. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
sendcoinsentry.h and sendcoinsdialog.h gate members on ENABLE_PLATFORM_GUI without including config/bitcoin-config.h, so MOC (which does not otherwise see the define) omitted on_contactsButton_clicked from the meta-object. The "@" contacts button's auto-connected slot never fired, and the class layout differed between the MOC translation unit and normal compilation. Add the config include, matching bitcoingui.h / walletview.h / walletframe.h. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Make test/lint/all-lint.py pass on the platform feature: - lint-locale-dependence: replace std::tolower (ASCII fold), std::atoi (LocaleIndependentAtoi), std::to_string (ToString), and std::stoul (std::from_chars, base 16) in the gRPC-Web/TLS transport with locale-independent equivalents. - lint-qt-translation: move leading whitespace outside tr() in the username search results. - cppcheck: avoid the implementation-defined signed shift in the bincode zigzag encoder (equivalent sign-extension mask) and rename a shadowing local. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
No CI configuration exercised the optional Platform GUI, so the ~16k-line feature and its gated C++ test suites were never built or run. Add a dedicated flag-on native target (linux64_platform_gui) that builds depends with PLATFORM_GUI=1 (pulling in mbedtls), configures with --enable-platform-gui --with-gui=qt5, and runs the platform_* unit tests (functional tests are off — the feature has no dashd-only surface). Wired as depends/src/test jobs in build.yml, gated by SKIP_LINUX64_PLATFORM_GUI like the other targets. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The GroveDBProof V1 requirement takes effect at Platform protocol version 12 (drive v7 -> grovedb GROVE_V3), not protocol 4 as the comment said. No behavior change; both testnet and mainnet run well past protocol 12 so the gate is a no-op for real proofs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…point Two availability regressions from the earlier freshness/root-consistency hardening, both caused by round-robin endpoint selection interacting with a global check: - DoGetIdentity issued its balance/revision/keys sub-proofs to three different round-robin endpoints, then required all roots to match. Honest nodes a block apart produced different roots and the whole query failed; retrying just picked another three nodes. It now pins a single endpoint per attempt (transport::RetryAcrossEndpoints + CallOn) and retries the whole logical operation against another endpoint on failure, bounded by MAX_OP_ATTEMPTS. - The freshness watermark was a single session-global maximum platform height, so a lagging honest node was rejected for being one block behind the fastest node seen. It is now per-endpoint (transport::FreshnessTracker keyed by proTxHash/address): a node may not roll its own height backwards (the replay we want to catch), while honest cross-node lag is tolerated. Single-call operations thread the answering endpoint's key through. Freshness comments are corrected to describe a best-effort staleness bound (per-endpoint monotonic height + a ~288-block core-ChainLock floor, zero on cold start), not the previously-overstated "airtight" anti-rollback. Adds platform_client_tests covering the per-endpoint watermark (lag tolerated, same-node rollback rejected, core floor) and the retry driver (round-robin rotation, single-endpoint pinning per attempt, bounds) — the availability paths the proof vectors cannot reach. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The chunked-transfer decoder required the entire chunk-size line to be hexadecimal, rejecting valid lines that carry chunk extensions such as "1a;ext=value" (RFC 9112 7.1.1). Parse only the hex prefix up to any ';' and ignore the extension. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
cppcheck (variableScope, an always-enabled Dash lint category) flagged the per-event winner Identifier in the contested-vote stored-info decoder. It is parsed only to advance the reader — the authoritative winner comes from the poll status field — so move it into the branch that reads it. Unblocks the lint job the platform-gui CI build depends on. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…n test The dpns_domain test case iterated a brace-init-list of string literals with a 'const std::string&' loop variable, binding the reference to a temporary std::string constructed from each 'const char*'. This is legal C++ but GCC's -Wrange-loop-construct flags it (clang does not), and the CI build uses -Werror. This is the first CI job to actually compile platform_dpp_tests.cpp under --enable-platform-gui, which is why it was never caught before. Loop over 'const char*' instead; UniValue::operator[] already takes the implicit std::string conversion at the call site, so behavior is unchanged. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue being fixed or feature implemented
Dash-QT has long lacked first-class Dash Platform support: usernames (DPNS), DashPay profiles, and contact-to-contact payments — the feature set of the DashPay mobile wallets — without coupling Dash Core to Platform. This PR adds that as a compile-time-optional GUI feature (
--enable-platform-gui, default off): dashd and default builds contain zero Platform symbols and are behaviorally unchanged.What was done?
Pure C++ Platform client library (
src/platform/, linked only into dash-qt):prove=true; there is no trusted intermediary.src/test/platform_*_tests.cpp), including negative tests.Wallet/node seams (additive):
DescriptorScriptPubKeyMan::IsMinenow reports public-only descriptors in signing wallets as watch-only rather than spendable.GUI (
src/qt/platform/):How Has This Been Tested?
6ed0631a…be8, usernameqte2e8df49727), independently re-confirmed withprove=trueGroveDB proofs from unrelated evonodes; plus a two-wallet contact request round-trip and send-to-username exercised interactively on testnet.make checkincluding the four newplatform_*suites driven by Rust-generated vectors;test_dash-qtpasses.--enable-platform-gui; without the flag, dashd/dash-qt contain no platform symbols.lint-circular-dependencies,lint-whitespace,lint-includesclean; new Dash-specific paths added tonon-backported.txt.Breaking Changes
None. The feature is compile-time optional and off by default; consensus, dashd, and wallet behavior are unchanged when disabled. New wallet interface methods have stub implementations when the flag is off.
Checklist:
🤖 Generated with Claude Code