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