Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
d3af15e
fix(key-wallet): resolve trusted self-sends across the whole wallet
jeanpierreroma Aug 13, 2026
0611ba6
fix(key-wallet): drop the outputs of a transaction that lost its inputs
jeanpierreroma Aug 13, 2026
157b9d9
feat(key-wallet): abandon a dead transaction and everything built on it
jeanpierreroma Aug 13, 2026
b45603c
feat(key-wallet): let the abandon cascade follow an external spend view
jeanpierreroma Aug 13, 2026
90b6f0d
Merge branch 'dev' into fix/phantom-unconfirmed-balance
romchornyi Aug 13, 2026
4db8334
docs(key-wallet): fix the two broken intra-doc links on abandon_trans…
jeanpierreroma Aug 13, 2026
241f7cf
fix(key-wallet): address the review findings on the abandon path
jeanpierreroma Aug 13, 2026
15a597f
fix(key-wallet): close four gaps in the conflict sweep and the cascade
jeanpierreroma Aug 13, 2026
ba0ad6f
fix(key-wallet): three deeper review findings on the sweep and abandon
jeanpierreroma Aug 13, 2026
d8c9911
fix(key-wallet): restore the doc block, and make three assertions loa…
jeanpierreroma Aug 13, 2026
9944d6e
fix(key-wallet): InstantSend finality, wallet-wide abandon, targeted …
jeanpierreroma Aug 13, 2026
127ed34
fix(key-wallet): make the conflict sweep wallet-wide and ungated
jeanpierreroma Aug 13, 2026
800b043
feat(key-wallet-manager): expose abandon, and pin the rescan-recovery…
jeanpierreroma Aug 13, 2026
cf7ed1f
feat(key-wallet-manager): report swept transactions so mirrors can de…
jeanpierreroma Aug 14, 2026
6aa7b55
fix(key-wallet): stop the sweep freeing the outpoint the winner spends
jeanpierreroma Aug 14, 2026
ed360cc
feat(dash-spv-ffi): expose the sweep as a C callback
jeanpierreroma Aug 14, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion key-wallet/src/managed_account/managed_account_collection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
//! This module provides a structure for managing multiple accounts
//! across different networks in a hierarchical manner.

use std::collections::BTreeMap;
use std::collections::{BTreeMap, BTreeSet};

use dashcore::blockdata::transaction::OutPoint;
use dashcore::Transaction;

use crate::account::account_collection::{DashpayAccountKey, PlatformPaymentAccountKey};
use crate::gap_limit::DIP17_GAP_LIMIT;
Expand Down Expand Up @@ -934,6 +937,27 @@ impl ManagedAccountCollection {
accounts
}

/// Union, across every funds-bearing account, of the outpoints among
/// `tx`'s inputs that the wallet holds as final UTXOs.
///
/// A single account can only answer this for the coins it owns, but
/// pooled funding (asset locks draw from BIP44 + BIP32 + the DashPay
/// contact-receiving accounts) routinely spreads one transaction's inputs
/// across several. The union is what makes the trusted-self-send check in
/// [`ManagedCoreFundsAccount::record_transaction`] see the whole wallet.
///
/// Must be taken before any account processes `tx` — `update_utxos`
/// removes spent parents as it goes.
pub(crate) fn final_parents_of(&self, tx: &Transaction) -> BTreeSet<OutPoint> {
let mut parents = BTreeSet::new();
for account in self.all_accounts() {
if let ManagedAccountRef::Funds(funds) = account {
funds.collect_final_parents(tx, &mut parents);
}
}
parents
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/// Get all accounts in the collection as mutable
/// [`ManagedAccountRefMut`] values.
pub fn all_accounts_mut(&mut self) -> Vec<ManagedAccountRefMut<'_>> {
Expand Down
34 changes: 27 additions & 7 deletions key-wallet/src/managed_account/managed_account_ref.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ use crate::Network;
use dashcore::blockdata::transaction::OutPoint;
use dashcore::prelude::CoreBlockHeight;
use dashcore::{Address, ScriptBuf, Transaction, Txid};
use std::collections::BTreeMap;
use std::collections::{BTreeMap, BTreeSet};

/// Immutable reference to a managed core account, either funds-bearing or
/// keys-only.
Expand Down Expand Up @@ -314,25 +314,35 @@ impl<'a> ManagedAccountRefMut<'a> {
context,
transaction_type,
&BTreeMap::new(),
&BTreeSet::new(),
)
}

/// Record a new transaction, reconciling it against `observed_spent` —
/// the wallet-level `observed_spent_outpoints` view
/// (dashpay/rust-dashcore#649); only the funds variant consults it (keys
/// accounts track no UTXOs/output details).
///
/// `external_final_parents` is the wallet-level view of input parents held
/// by sibling accounts, used for the trusted-self-send determination.
pub(crate) fn record_transaction_with_observed_spends(
&mut self,
tx: &Transaction,
account_match: &AccountMatch,
context: TransactionContext,
transaction_type: TransactionType,
observed_spent: &BTreeMap<OutPoint, CoreBlockHeight>,
external_final_parents: &BTreeSet<OutPoint>,
) -> TransactionRecord {
match self {
ManagedAccountRefMut::Funds(a) => {
a.record_transaction(tx, account_match, context, transaction_type, observed_spent)
}
ManagedAccountRefMut::Funds(a) => a.record_transaction(
tx,
account_match,
context,
transaction_type,
observed_spent,
external_final_parents,
),
ManagedAccountRefMut::Keys(a) => {
a.record_transaction(tx, account_match, context, transaction_type)
}
Expand Down Expand Up @@ -361,24 +371,34 @@ impl<'a> ManagedAccountRefMut<'a> {
context,
transaction_type,
&BTreeMap::new(),
&BTreeSet::new(),
)
}

/// Re-process an existing transaction, reconciling refreshed UTXO state
/// against `observed_spent` — the wallet-level `observed_spent_outpoints`
/// view (dashpay/rust-dashcore#649); only the funds variant consults it.
///
/// `external_final_parents` is the wallet-level view of input parents held
/// by sibling accounts, used for the trusted-self-send determination.
pub(crate) fn confirm_transaction_with_observed_spends(
&mut self,
tx: &Transaction,
account_match: &AccountMatch,
context: TransactionContext,
transaction_type: TransactionType,
observed_spent: &BTreeMap<OutPoint, CoreBlockHeight>,
external_final_parents: &BTreeSet<OutPoint>,
) -> Option<TransactionRecord> {
match self {
ManagedAccountRefMut::Funds(a) => {
a.confirm_transaction(tx, account_match, context, transaction_type, observed_spent)
}
ManagedAccountRefMut::Funds(a) => a.confirm_transaction(
tx,
account_match,
context,
transaction_type,
observed_spent,
external_final_parents,
),
ManagedAccountRefMut::Keys(a) => {
a.confirm_transaction(tx, account_match, context, transaction_type)
}
Expand Down
Loading
Loading