@@ -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 > {
@@ -229,9 +241,21 @@ impl Wallet {
229241 ..
230242 } = payment. kind
231243 {
244+ let payment_id= payment. id ;
232245 if new_tip. height >= height + ANTI_REORG_DELAY - 1 {
233246 payment. status = PaymentStatus :: Succeeded ;
234247 self . payment_store . insert_or_update ( payment) ?;
248+
249+ // Remove any replaced transactions associated with this payment
250+ let replaced_txids = self
251+ . replaced_tx_store
252+ . list_filter ( |r| r. payment_id == payment_id)
253+ . iter ( )
254+ . map ( |p| p. new_txid )
255+ . collect :: < Vec < Txid > > ( ) ;
256+ for replaced_txid in replaced_txids {
257+ self . replaced_tx_store . remove ( & replaced_txid) ?;
258+ }
235259 }
236260 }
237261 }
@@ -252,47 +276,24 @@ impl Wallet {
252276 ) ;
253277 self . payment_store . insert_or_update ( payment) ?;
254278 } ,
255- WalletEvent :: TxReplaced { txid, tx , conflicts } => {
279+ WalletEvent :: TxReplaced { txid, conflicts , .. } => {
256280 let payment_id = self
257281 . find_payment_by_txid ( * txid)
258282 . unwrap_or_else ( || PaymentId ( txid. to_byte_array ( ) ) ) ;
259283
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 ( ) ) ;
284+ // Collect all conflict txids
285+ let conflict_txids: Vec < Txid > =
286+ conflicts. iter ( ) . map ( |( _, conflict_txid) | * conflict_txid) . collect ( ) ;
285287
286- let payment = self . create_payment_from_tx (
287- 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,
288292 * txid,
289293 payment_id,
290- tx,
291- PaymentStatus :: Pending ,
292- ConfirmationStatus :: Unconfirmed ,
293- conflicting_txids,
294294 ) ;
295- self . payment_store . insert_or_update ( payment) ?;
295+
296+ self . replaced_tx_store . insert_or_update ( replaced_tx_details) ?;
296297 }
297298 } ,
298299 WalletEvent :: TxDropped { txid, tx } => {
@@ -962,16 +963,12 @@ impl Wallet {
962963 return Some ( direct_payment_id) ;
963964 }
964965
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 )
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
975972 }
976973}
977974
0 commit comments