Repository navigation
Description
Expected Behavior
When send_payment broadcasts a DashPay payment and the outcome is ambiguous (BroadcastError::MaybeSent), the sender's Sent payment entry is recorded as Pending straight away. The host receives the transaction id along with the error, so it can show the payment and refuse a duplicate to the same contact.
Current Behavior
-
No entry until the next sync pass.
send_paymentmatches the broadcast result (payments.rs#L1484). For an ambiguous outcome it keeps the input fence (#L1539-L1547) and returnsErr(#L1615) before the entry is recorded (#L1651). The SPV broadcaster has already injected the transaction into the local mempool (broadcaster.rs#L201). TheSententry is therefore rebuilt only whendashpay_syncrunsreconcile_sent_payments_from_tx_history(dashpay_sync.rs#L475, payments.rs#L198-L241). Until then the host has nothing to show for the payment and nothing to gate a second one on. -
The error carries no txid.
BroadcastError::MaybeSent { reason }maps toPlatformWalletError::TransactionBroadcastUnconfirmed(String)(broadcaster.rs#L47-L57). The FFI code 20 and the SwifttransactionBroadcastUnconfirmed(String)expose only the reason, although the transaction was signed and its txid was known before dispatch. A host cannot look the transaction up, for example with the DAPI + SPV locator from fix(platform-wallet): look up the funding tx's block when a ChainLock proof has no record height #4738, or match it to the entry that appears later.
The same ambiguity for an ordinary Core send is re-owned across a restart by #4659. This issue is about the DashPay payment path's own record and what reaches the host.
Possible Solution
- In
send_payment, record theSententry withPaymentStatus::PendingonMaybeSentas well as on acceptance, persisted the same way, before returning the error.confirm_sent_dashpay_paymentalready advances it toConfirmedon an InstantSend lock or a block (payments.rs#L970). - Carry the txid in the ambiguous-broadcast error across FFI and Swift, as a structured field rather than inside the reason string.
- Do not add a time-based release. It would contradict generation.rs#L109.
- Optional, needs a maintainer decision: expose a
locate(txid)-style check for hosts. fix(platform-wallet): look up the funding tx's block when a ChainLock proof has no record height #4738'sMinedHeightLocatorispub(crate)and wired only into the asset-lock ChainLock proof.Mined/NotMinedwould prove the payment is on the network;NotFoundwould still prove nothing. - To verify: fix(platform-wallet): give an unconfirmed outgoing send an owner across a restart #4659 selects replay candidates from the TXO side and excludes only asset-lock funding rows, so a DashPay external-account payment should be covered. Confirm this with a test.
Steps to Reproduce (for bugs)
Unit level, not yet written: call send_payment with the existing AlwaysMaybeSentBroadcaster test double (test_support.rs#L106), then assert:
- the call returns
TransactionBroadcastUnconfirmed; getDashPayPaymentsfor the sender has no entry for the contact untilreconcile_sent_payments_from_tx_historyruns;- the error exposes no txid.
On a device: dashpay/dashwallet-ios#1132 (Network Link Conditioner during a contact payment).
Context
Can lead to a duplicate DashPay payment that cannot be undone. Found while reviewing dashpay/dashwallet-ios#1121. Related: #4659 (unconfirmed send owner across a restart, support ticket 32189), #4738 (DAPI + SPV transaction lookup, support ticket 32167), and dashpay/dashwallet-ios#1132.
Your Environment
- platform
v4.2-dev@7f809377db - Dash Wallet iOS PR refactor: misc changes during v0.25 review #1121 @
b863bc1c1 - testnet
Activity