@@ -48,8 +48,10 @@ use crate::config::Config;
4848use crate :: fee_estimator:: { ConfirmationTarget , FeeEstimator , OnchainFeeEstimator } ;
4949use crate :: logger:: { log_debug, log_error, log_info, log_trace, LdkLogger , Logger } ;
5050use crate :: payment:: store:: ConfirmationStatus ;
51- use crate :: payment:: { PaymentDetails , PaymentDirection , PaymentKind , PaymentStatus } ;
52- use crate :: types:: { Broadcaster , PaymentStore } ;
51+ use crate :: payment:: {
52+ PaymentDetails , PaymentDirection , PaymentKind , PaymentStatus , ReplacedOnchainTransactionDetails ,
53+ } ;
54+ use crate :: types:: { Broadcaster , PaymentStore , ReplacedTransactionStore } ;
5355use crate :: Error ;
5456
5557pub ( crate ) enum OnchainSendAmount {
@@ -70,18 +72,28 @@ pub(crate) struct Wallet {
7072 payment_store : Arc < PaymentStore > ,
7173 config : Arc < Config > ,
7274 logger : Arc < Logger > ,
75+ replaced_tx_store : Arc < ReplacedTransactionStore > ,
7376}
7477
7578impl Wallet {
7679 pub ( crate ) fn new (
7780 wallet : bdk_wallet:: PersistedWallet < KVStoreWalletPersister > ,
7881 wallet_persister : KVStoreWalletPersister , broadcaster : Arc < Broadcaster > ,
7982 fee_estimator : Arc < OnchainFeeEstimator > , payment_store : Arc < PaymentStore > ,
80- config : Arc < Config > , logger : Arc < Logger > ,
83+ config : Arc < Config > , logger : Arc < Logger > , replaced_tx_store : Arc < ReplacedTransactionStore > ,
8184 ) -> Self {
8285 let inner = Mutex :: new ( wallet) ;
8386 let persister = Mutex :: new ( wallet_persister) ;
84- Self { inner, persister, broadcaster, fee_estimator, payment_store, config, logger }
87+ Self {
88+ inner,
89+ persister,
90+ broadcaster,
91+ fee_estimator,
92+ payment_store,
93+ config,
94+ logger,
95+ replaced_tx_store,
96+ }
8597 }
8698
8799 pub ( crate ) fn get_full_scan_request ( & self ) -> FullScanRequest < KeychainKind > {
@@ -207,6 +219,17 @@ impl Wallet {
207219 None ,
208220 ) ;
209221 self . payment_store . insert_or_update ( payment) ?;
222+
223+ // Remove any replaced transactions associated with this payment
224+ let replaced_txids = self
225+ . replaced_tx_store
226+ . list_filter ( |r| r. payment_id == payment_id)
227+ . iter ( )
228+ . map ( |p| p. new_txid )
229+ . collect :: < Vec < Txid > > ( ) ;
230+ for replaced_txid in replaced_txids {
231+ self . replaced_tx_store . remove ( & replaced_txid) ?;
232+ }
210233 } ,
211234 WalletEvent :: ChainTipChanged { new_tip, .. } => {
212235 // Get all payments that are Pending with Confirmed status
@@ -251,47 +274,24 @@ impl Wallet {
251274 ) ;
252275 self . payment_store . insert_or_update ( payment) ?;
253276 } ,
254- WalletEvent :: TxReplaced { txid, tx , conflicts } => {
277+ WalletEvent :: TxReplaced { txid, conflicts , .. } => {
255278 let payment_id = self
256279 . find_payment_by_txid ( * txid)
257280 . unwrap_or_else ( || PaymentId ( txid. to_byte_array ( ) ) ) ;
258281
259- if let Some ( mut payment) = self . payment_store . get ( & payment_id) {
260- if let PaymentKind :: Onchain {
261- ref mut conflicting_txids,
262- txid : current_txid,
263- ..
264- } = payment. kind
265- {
266- let existing_set: std:: collections:: HashSet < _ > =
267- conflicting_txids. iter ( ) . collect ( ) ;
268-
269- let new_conflicts: Vec < _ > = conflicts
270- . iter ( )
271- . map ( |( _, conflict_txid) | * conflict_txid)
272- . filter ( |conflict_txid| {
273- * conflict_txid != current_txid
274- && !existing_set. contains ( conflict_txid)
275- } )
276- . collect ( ) ;
277-
278- conflicting_txids. extend ( new_conflicts) ;
279- }
280- self . payment_store . insert_or_update ( payment) ?;
281- } else {
282- let conflicting_txids =
283- Some ( conflicts. iter ( ) . map ( |( _, txid) | * txid) . collect ( ) ) ;
282+ // Collect all conflict txids
283+ let conflict_txids: Vec < Txid > =
284+ conflicts. iter ( ) . map ( |( _, conflict_txid) | * conflict_txid) . collect ( ) ;
284285
285- let payment = self . create_payment_from_tx (
286- locked_wallet,
286+ for conflict_txid in conflict_txids {
287+ // Update the replaced transaction store
288+ let replaced_tx_details = ReplacedOnchainTransactionDetails :: new (
289+ conflict_txid,
287290 * txid,
288291 payment_id,
289- tx,
290- PaymentStatus :: Pending ,
291- ConfirmationStatus :: Unconfirmed ,
292- conflicting_txids,
293292 ) ;
294- self . payment_store . insert_or_update ( payment) ?;
293+
294+ self . replaced_tx_store . insert_or_update ( replaced_tx_details) ?;
295295 }
296296 } ,
297297 WalletEvent :: TxDropped { txid, tx } => {
@@ -901,16 +901,12 @@ impl Wallet {
901901 return Some ( direct_payment_id) ;
902902 }
903903
904- self . payment_store
905- . list_filter ( |p| {
906- if let PaymentKind :: Onchain { txid, conflicting_txids, .. } = & p. kind {
907- * txid == target_txid || conflicting_txids. contains ( & target_txid)
908- } else {
909- false
910- }
911- } )
912- . first ( )
913- . map ( |p| p. id )
904+ // Check if this txid is a replaced transaction
905+ if let Some ( replaced_details) = self . replaced_tx_store . get ( & target_txid) {
906+ return Some ( replaced_details. payment_id ) ;
907+ }
908+
909+ None
914910 }
915911}
916912
0 commit comments