@@ -51,8 +51,10 @@ use crate::config::Config;
5151use crate :: fee_estimator:: { ConfirmationTarget , FeeEstimator , OnchainFeeEstimator } ;
5252use crate :: logger:: { log_debug, log_error, log_info, log_trace, LdkLogger , Logger } ;
5353use crate :: payment:: store:: ConfirmationStatus ;
54- use crate :: payment:: { PaymentDetails , PaymentDirection , PaymentKind , PaymentStatus } ;
55- use crate :: types:: { Broadcaster , PaymentStore } ;
54+ use crate :: payment:: {
55+ PaymentDetails , PaymentDirection , PaymentKind , PaymentStatus , ReplacedOnchainTransactionDetails ,
56+ } ;
57+ use crate :: types:: { Broadcaster , PaymentStore , ReplacedTransactionStore } ;
5658use crate :: Error ;
5759
5860pub ( crate ) enum OnchainSendAmount {
@@ -73,18 +75,28 @@ pub(crate) struct Wallet {
7375 payment_store : Arc < PaymentStore > ,
7476 config : Arc < Config > ,
7577 logger : Arc < Logger > ,
78+ replaced_tx_store : Arc < ReplacedTransactionStore > ,
7679}
7780
7881impl Wallet {
7982 pub ( crate ) fn new (
8083 wallet : bdk_wallet:: PersistedWallet < KVStoreWalletPersister > ,
8184 wallet_persister : KVStoreWalletPersister , broadcaster : Arc < Broadcaster > ,
8285 fee_estimator : Arc < OnchainFeeEstimator > , payment_store : Arc < PaymentStore > ,
83- config : Arc < Config > , logger : Arc < Logger > ,
86+ config : Arc < Config > , logger : Arc < Logger > , replaced_tx_store : Arc < ReplacedTransactionStore > ,
8487 ) -> Self {
8588 let inner = Mutex :: new ( wallet) ;
8689 let persister = Mutex :: new ( wallet_persister) ;
87- Self { inner, persister, broadcaster, fee_estimator, payment_store, config, logger }
90+ Self {
91+ inner,
92+ persister,
93+ broadcaster,
94+ fee_estimator,
95+ payment_store,
96+ config,
97+ logger,
98+ replaced_tx_store,
99+ }
88100 }
89101
90102 pub ( crate ) fn get_full_scan_request ( & self ) -> FullScanRequest < KeychainKind > {
@@ -209,6 +221,17 @@ impl Wallet {
209221 None ,
210222 ) ;
211223 self . payment_store . insert_or_update ( payment) ?;
224+
225+ // Remove any replaced transactions associated with this payment
226+ let replaced_txids = self
227+ . replaced_tx_store
228+ . list_filter ( |r| r. payment_id == payment_id)
229+ . iter ( )
230+ . map ( |p| p. new_txid )
231+ . collect :: < Vec < Txid > > ( ) ;
232+ for replaced_txid in replaced_txids {
233+ self . replaced_tx_store . remove ( & replaced_txid) ?;
234+ }
212235 } ,
213236 WalletEvent :: ChainTipChanged { new_tip, .. } => {
214237 // Get all payments that are Pending with Confirmed status
@@ -253,47 +276,24 @@ impl Wallet {
253276 ) ;
254277 self . payment_store . insert_or_update ( payment) ?;
255278 } ,
256- WalletEvent :: TxReplaced { txid, tx , conflicts } => {
279+ WalletEvent :: TxReplaced { txid, conflicts , .. } => {
257280 let payment_id = self
258281 . find_payment_by_txid ( * txid)
259282 . unwrap_or_else ( || PaymentId ( txid. to_byte_array ( ) ) ) ;
260283
261- if let Some ( mut payment) = self . payment_store . get ( & payment_id) {
262- if let PaymentKind :: Onchain {
263- ref mut conflicting_txids,
264- txid : current_txid,
265- ..
266- } = payment. kind
267- {
268- let existing_set: std:: collections:: HashSet < _ > =
269- conflicting_txids. iter ( ) . collect ( ) ;
270-
271- let new_conflicts: Vec < _ > = conflicts
272- . iter ( )
273- . map ( |( _, conflict_txid) | * conflict_txid)
274- . filter ( |conflict_txid| {
275- * conflict_txid != current_txid
276- && !existing_set. contains ( conflict_txid)
277- } )
278- . collect ( ) ;
279-
280- conflicting_txids. extend ( new_conflicts) ;
281- }
282- self . payment_store . insert_or_update ( payment) ?;
283- } else {
284- let conflicting_txids =
285- Some ( conflicts. iter ( ) . map ( |( _, txid) | * txid) . collect ( ) ) ;
284+ // Collect all conflict txids
285+ let conflict_txids: Vec < Txid > =
286+ conflicts. iter ( ) . map ( |( _, conflict_txid) | * conflict_txid) . collect ( ) ;
286287
287- let payment = self . create_payment_from_tx (
288- locked_wallet,
288+ for conflict_txid in conflict_txids {
289+ // Update the replaced transaction store
290+ let replaced_tx_details = ReplacedOnchainTransactionDetails :: new (
291+ conflict_txid,
289292 * txid,
290293 payment_id,
291- tx,
292- PaymentStatus :: Pending ,
293- ConfirmationStatus :: Unconfirmed ,
294- conflicting_txids,
295294 ) ;
296- self . payment_store . insert_or_update ( payment) ?;
295+
296+ self . replaced_tx_store . insert_or_update ( replaced_tx_details) ?;
297297 }
298298 } ,
299299 WalletEvent :: TxDropped { txid, tx } => {
@@ -963,16 +963,12 @@ impl Wallet {
963963 return Some ( direct_payment_id) ;
964964 }
965965
966- self . payment_store
967- . list_filter ( |p| {
968- if let PaymentKind :: Onchain { txid, conflicting_txids, .. } = & p. kind {
969- * txid == target_txid || conflicting_txids. contains ( & target_txid)
970- } else {
971- false
972- }
973- } )
974- . first ( )
975- . map ( |p| p. id )
966+ // Check if this txid is a replaced transaction
967+ if let Some ( replaced_details) = self . replaced_tx_store . get ( & target_txid) {
968+ return Some ( replaced_details. payment_id ) ;
969+ }
970+
971+ None
976972 }
977973}
978974
0 commit comments