From fdae635952ef60faa42df97f36ce4ffbca218b70 Mon Sep 17 00:00:00 2001 From: Yeji Han Date: Sat, 14 Mar 2026 22:40:13 +0900 Subject: [PATCH 1/2] Fix inbound on-chain payment txid not updating after RBF replacement --- src/wallet/mod.rs | 45 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 0e80a46db..8190d4552 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -260,6 +260,7 @@ impl Wallet { let payment_id = self .find_payment_by_txid(txid) + .or_else(|| self.find_payment_by_conflicting_tx(locked_wallet, &tx)) .unwrap_or_else(|| PaymentId(txid.to_byte_array())); let payment = self.create_payment_from_tx( @@ -348,6 +349,7 @@ impl Wallet { WalletEvent::TxUnconfirmed { txid, tx, old_block_time: None } => { let payment_id = self .find_payment_by_txid(txid) + .or_else(|| self.find_payment_by_conflicting_tx(locked_wallet, &tx)) .unwrap_or_else(|| PaymentId(txid.to_byte_array())); let payment = self.create_payment_from_tx( @@ -396,6 +398,7 @@ impl Wallet { WalletEvent::TxDropped { txid, tx } => { let payment_id = self .find_payment_by_txid(txid) + .or_else(|| self.find_payment_by_conflicting_tx(locked_wallet, &tx)) .unwrap_or_else(|| PaymentId(txid.to_byte_array())); let payment = self.create_payment_from_tx( locked_wallet, @@ -1209,6 +1212,48 @@ impl Wallet { return Some(replaced_details.details.id); } + // Also check the payment store for onchain payments with this txid. + if let Some(payment) = self + .payment_store + .list_filter( + |p| matches!(&p.kind, PaymentKind::Onchain { txid, .. } if *txid == target_txid), + ) + .first() + { + return Some(payment.id); + } + + None + } + + fn find_payment_by_conflicting_tx( + &self, locked_wallet: &PersistedWallet, tx: &Transaction, + ) -> Option { + let target_txid = tx.compute_txid(); + let spent_outpoints: std::collections::HashSet = + tx.input.iter().map(|input| input.previous_output).collect(); + + let onchain_payments = self.payment_store.list_filter(|p| { + matches!(p.kind, PaymentKind::Onchain { .. }) && p.status != PaymentStatus::Failed + }); + + for payment in onchain_payments { + if let PaymentKind::Onchain { txid: existing_txid, .. } = &payment.kind { + if *existing_txid == target_txid { + continue; + } + if let Some(existing_tx_details) = locked_wallet.tx_details(*existing_txid) { + let shares_inputs = existing_tx_details + .tx + .input + .iter() + .any(|input| spent_outpoints.contains(&input.previous_output)); + if shares_inputs { + return Some(payment.id); + } + } + } + } None } From dbef121c71e49d5a39bc2c738551d6ca93e764c0 Mon Sep 17 00:00:00 2001 From: Yeji Han Date: Sun, 15 Mar 2026 13:12:22 +0900 Subject: [PATCH 2/2] Address PR review feedback for RBF payment lookup --- src/wallet/mod.rs | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/wallet/mod.rs b/src/wallet/mod.rs index 8190d4552..887a18831 100644 --- a/src/wallet/mod.rs +++ b/src/wallet/mod.rs @@ -1213,11 +1213,19 @@ impl Wallet { } // Also check the payment store for onchain payments with this txid. + // First try direct lookup by payment_id, then fall back to scanning by txid. + if let Some(payment) = self.payment_store.get(&direct_payment_id) { + if payment.status != PaymentStatus::Succeeded { + return Some(payment.id); + } + } + if let Some(payment) = self .payment_store - .list_filter( - |p| matches!(&p.kind, PaymentKind::Onchain { txid, .. } if *txid == target_txid), - ) + .list_filter(|p| { + matches!(&p.kind, PaymentKind::Onchain { txid, .. } if *txid == target_txid) + && p.status != PaymentStatus::Succeeded + }) .first() { return Some(payment.id); @@ -1233,12 +1241,14 @@ impl Wallet { let spent_outpoints: std::collections::HashSet = tx.input.iter().map(|input| input.previous_output).collect(); - let onchain_payments = self.payment_store.list_filter(|p| { - matches!(p.kind, PaymentKind::Onchain { .. }) && p.status != PaymentStatus::Failed + let pending_onchain_payments = self.pending_payment_store.list_filter(|p| { + matches!(p.details.kind, PaymentKind::Onchain { .. }) + && p.details.status != PaymentStatus::Failed }); - for payment in onchain_payments { - if let PaymentKind::Onchain { txid: existing_txid, .. } = &payment.kind { + for pending_payment in pending_onchain_payments { + if let PaymentKind::Onchain { txid: existing_txid, .. } = &pending_payment.details.kind + { if *existing_txid == target_txid { continue; } @@ -1249,7 +1259,7 @@ impl Wallet { .iter() .any(|input| spent_outpoints.contains(&input.previous_output)); if shares_inputs { - return Some(payment.id); + return Some(pending_payment.details.id); } } }