Repository navigation
Commit c10b24b
feat(qt): DashPay usernames
IdentityFlow is the persisted, resumable state machine behind username registration: fund an asset lock, wait for its InstantSend or ChainLock, create the identity, preorder and register the DPNS name, and confirm each step by a proved re-query. A registration asks for the passphrase once: the unlock the user gives to fund the asset lock is held while the funding payment gets its InstantSend lock (at most a minute, usually seconds), and then the identity create, the DPNS preorder and domain and, when the user entered a display name in the wizard, the DashPay profile are signed in one go, each under its own kind-scoped SigningOperation, and persisted in the record before the wallet is locked again. A brand-new identity has used no contract, and Drive accepts a first identity contract nonce below 24 and each next one above the last, so the preorder and domain carry DPNS nonces 1 and 2 and the profile DashPay nonce 1. The steps then broadcast what was persisted in order, each confirmed by a proved re-query before the next goes out: the preorder by the DPNS nonce Platform has taken, the domain (sent only once the preorder's nonce is taken, which the domain's data trigger needs) by a proved resolve, the profile by a proved read. A restart resends what was persisted without prompting. The minute is a monotonic single-shot timer, so a wall clock stepped back cannot keep the wallet unlocked longer. Each transition signed ahead records the protocol version a verified read had shown when it was built. Where nothing was signed ahead (the lock did not come within the minute, an existing identity registering a name, a record of an earlier layout, a transition refused as stale or its nonce spent) or it was built under another protocol version than Platform now runs, the step signs when it gets there, the preorder together with its domain, under one prompt; when the user declines to unlock, the flow parks in NEEDS_UNLOCK and only moves again on a user action or a wallet unlock, never on the 5 s tick. No private key is held unlocked across an open-ended network wait.
The identity registers four keys, 0 AUTH/MASTER, 1 AUTH/HIGH, 2 ENCRYPTION/MEDIUM and 3 DECRYPTION/MEDIUM, with keys 2 and 3 bound to the DashPay contactRequest document type, as the mobile wallets do; every key signs its own possession proof and the funding key signs the asset lock once. The identity id comes from the built transition. Before any credits are spent on the name, a proved resolve adopts a name this identity already owns (its confirmation was lost, or another wallet with the same seed registered it) and fails on one someone else owns. Broadcast decisions are typed: success is OK or AlreadyExists; on the preorder step a DuplicateUniqueIndexError (the saltedDomainHash index) means an earlier preorder was applied, so the domain is signed at the nonce Platform shows next; on the domain step a DataTriggerConditionError means the preorder is not visible yet, so the same domain is sent again at each poll and, after the confirmation window, the username goes out again from its preorder with the persisted salt; an InvalidIdentityNonceError has the nonce read again, which Core owns; an InvalidDocumentTransitionIdError on a preorder or domain signed ahead (protocol version 14 derives document ids from the identity contract nonce) has it signed again at the same nonce, which the CheckTx refusal did not spend, instead of failing the registration. A profile signed ahead under an earlier protocol version is not sent; the user adds it from the dashboard. Confirmations are polled with a backoff (5 s growing to 30 s) for three minutes before anything is broadcast again, since Platform took over a minute to include a transition on testnet. A contested registration is funded from contested_vote_fund_credits() under the protocol version a verified read has shown, plus the base amount, instead of a constant; an existing identity registers a premium name only when its proved balance covers the vote reserve plus a documented fee reserve for the preorder and domain transitions, and the cost page says so. The registration wizard (name entry with proved availability, cost confirmation, live progress with an unlock button) and the dashboard show the flow.
Tests (test_dash-qt over FakePlatformClient): the four-key set and the contested funding amount, the consensus-code and nonce steering with the persisted salt on every DPNS build and nothing re-sent before the backoff allows, the proved-resolve confirmation refusing a name registered by another identity, a name already ours adopted without a preorder and one owned by someone else failing before any build (registrationAdoptsNameAlreadyOurs), a premium name refused for a balance equal to the vote reserve and built at exactly the reserve plus fees (contestedNameNeedsIdentityCredits), the NEEDS_UNLOCK park and resume on a locked encrypted wallet with the HIGH key scoped and the signed domain sent later without a prompt, one prompt signing the identity, preorder, domain and profile with everything persisted before the wallet is locked and a restart broadcasting it all in order without prompting (registrationSignsOnceAndResumesAfterRestart), a spent domain nonce signed again under one prompt (registrationSignsSpentStepAgain), a preorder and domain signed under an earlier protocol version or refused for their document id signed again at the same nonce with one prompt each instead of failing, and such a profile not sent (registrationSignsAgainAfterUpgrade), a failure stored by an earlier build worded like a new one and a new failure's details surviving a reload (storedFailuresAreWordedWhenShown), and the wizard entry page completing only on a proved availability answer, stating the username rule once and showing Stored as only for a valid name.
The dashboard is a header (an avatar filled from the theme's blue, green and orange, never purple, and neutral until the username is registered or up for the vote), a state card with its action under its text and the registration step, and the paused, frozen or mismatch notice in the overview's alert style. Disable DashPay… in Options stays disabled, saying why in text, while an asset lock is on chain that no identity consumed yet (funding, creating the identity, waiting for the passphrase there, or failed with the lock kept for Try again), also while a gate keeps the service from starting: the records are its only trace and seed recovery finds identities, not asset locks; the Options group names the registered username. For the same reason, rebuilding after a network change and the record-layout wipe keep that registration record and continue it on the current chain. A refusal while the records are for another network says to rebuild them rather than blaming a Platform answer. The wizard uses the masternode wizard's frame, window-modal to the main window and closed when the page is left but not when the window goes to the tray; its progress page is a checklist whose buttons are Close, Unlock and continue…, Try again… or Done, and a failure says what the attempt kept. Tests: no avatar colour is purple in either theme, the step and reassurance wording, the progress page's buttons, plain failure text and registered wording with and without a display name, the page offering no Disable button and the Options guard with its reason shown (unconsumedFundingBlocksDisable), and the funding record surviving a rebuild after a network change (networkChangeKeepsUnconsumedFunding).
The wizard's name page has an optional Display name (for a new identity), its cost page lists only the rows that apply and keeps the cost short with the balance on Dash Platform in the explanation, and its log words each step once: a step the flow goes back to while it waits for Platform is not logged again. What a failure says is worded from the stored status when it is shown, so a record written by an earlier build no longer shows a raw consensus code. The dashboard is a centred column at most 1040 px wide; its username uses the section heading size; it reads nothing while the node has pushed no evonode endpoints, and reads its balance again 30 s after a failed read (one pending retry, restarted by the next failure and stopped while paused or hidden), and once the endpoints are pushed again after a pause (endpointsAvailable) rather than only when the tab is shown again; the paused notice says DashPay is paused while network activity is off; and Try again… opens a fresh wizard even when an earlier one was left open. Headings are bold from the first paint. The Username registered page suggests adding a profile, and offers Add profile…, unless the display name chosen with the username is being published or was published: one the flow could not sign or gave up on is offered again (usernameProgressWording).
Platform balances are Dash, never credits: the header says Balance on Dash Platform: 0.00722958 tDASH in the wallet's display unit (PlatformUi::formatPlatformBalance, rounded down to a duff so it never overstates) and shows it again in a new unit when the user changes it, and the wizard, the identity flow's premium-cost failure and the error texts say balance on Dash Platform with Dash amounts. The dashboard reads its identity when the page is shown or the window becomes active (not again within 30 s), after a pause and after the user's own changes; a premium username's votes are read again on a ChainLock while the page is shown, at most every ten minutes, with a five-minute timer as the fallback, and the card says when they were last read instead of offering Refresh votes. Nothing is read while the page is hidden. The page takes the factory of its Platform client, so a test drives the page's own service over a scripted client. Tests: the balance line in DASH and again in mDASH after a unit change, the identity-ready card with the amount, and no credit wording on the page or in the failure texts (balanceShownAsDash); a premium-cost failure states Dash amounts (contestedNameNeedsIdentityCredits); with -proxy the page's own service starts, its client is configured with that proxy and per-connection isolation, and evonodes are pushed (serviceStartsThroughTheProxy).
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>1 parent 38b4a14 commit c10b24b
19 files changed
Lines changed: 5820 additions & 82 deletions
File tree
- src
- qt
- platform
- res/css
- test
- test/util
- test/lint
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
124 | 124 | | |
125 | 125 | | |
126 | 126 | | |
| 127 | + | |
127 | 128 | | |
| 129 | + | |
128 | 130 | | |
129 | 131 | | |
130 | 132 | | |
| |||
235 | 237 | | |
236 | 238 | | |
237 | 239 | | |
| 240 | + | |
238 | 241 | | |
| 242 | + | |
239 | 243 | | |
240 | 244 | | |
241 | 245 | | |
| |||
376 | 380 | | |
377 | 381 | | |
378 | 382 | | |
| 383 | + | |
379 | 384 | | |
| 385 | + | |
380 | 386 | | |
381 | 387 | | |
382 | 388 | | |
| |||
0 commit comments