@@ -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 > {
@@ -225,9 +237,21 @@ impl Wallet {
225237 ..
226238 } = payment. kind
227239 {
240+ let payment_id = payment. id ;
228241 if new_tip. height >= height + ANTI_REORG_DELAY - 1 {
229242 payment. status = PaymentStatus :: Succeeded ;
230243 self . payment_store . insert_or_update ( payment) ?;
244+
245+ // Remove any replaced transactions associated with this payment
246+ let replaced_txids = self
247+ . replaced_tx_store
248+ . list_filter ( |r| r. payment_id == payment_id)
249+ . iter ( )
250+ . map ( |p| p. new_txid )
251+ . collect :: < Vec < Txid > > ( ) ;
252+ for replaced_txid in replaced_txids {
253+ self . replaced_tx_store . remove ( & replaced_txid) ?;
254+ }
231255 }
232256 }
233257 }
@@ -248,47 +272,21 @@ impl Wallet {
248272 ) ;
249273 self . payment_store . insert_or_update ( payment) ?;
250274 } ,
251- WalletEvent :: TxReplaced { txid, tx , conflicts } => {
275+ WalletEvent :: TxReplaced { txid, conflicts , .. } => {
252276 let payment_id = self
253277 . find_payment_by_txid ( txid)
254278 . unwrap_or_else ( || PaymentId ( txid. to_byte_array ( ) ) ) ;
255279
256- if let Some ( mut payment) = self . payment_store . get ( & payment_id) {
257- if let PaymentKind :: Onchain {
258- ref mut conflicting_txids,
259- txid : current_txid,
260- ..
261- } = payment. kind
262- {
263- let existing_set: std:: collections:: HashSet < _ > =
264- conflicting_txids. iter ( ) . collect ( ) ;
265-
266- let new_conflicts: Vec < _ > = conflicts
267- . iter ( )
268- . map ( |( _, conflict_txid) | * conflict_txid)
269- . filter ( |conflict_txid| {
270- * conflict_txid != current_txid
271- && !existing_set. contains ( conflict_txid)
272- } )
273- . collect ( ) ;
274-
275- conflicting_txids. extend ( new_conflicts) ;
276- }
277- self . payment_store . insert_or_update ( payment) ?;
278- } else {
279- let conflicting_txids =
280- Some ( conflicts. iter ( ) . map ( |( _, txid) | * txid) . collect ( ) ) ;
281-
282- let payment = self . create_payment_from_tx (
283- locked_wallet,
284- txid,
285- payment_id,
286- & tx,
287- PaymentStatus :: Pending ,
288- ConfirmationStatus :: Unconfirmed ,
289- conflicting_txids,
290- ) ;
291- self . payment_store . insert_or_update ( payment) ?;
280+ // Collect all conflict txids
281+ let conflict_txids: Vec < Txid > =
282+ conflicts. iter ( ) . map ( |( _, conflict_txid) | * conflict_txid) . collect ( ) ;
283+
284+ for conflict_txid in conflict_txids {
285+ // Update the replaced transaction store
286+ let replaced_tx_details =
287+ ReplacedOnchainTransactionDetails :: new ( conflict_txid, txid, payment_id) ;
288+
289+ self . replaced_tx_store . insert_or_update ( replaced_tx_details) ?;
292290 }
293291 } ,
294292 WalletEvent :: TxDropped { txid, tx } => {
@@ -954,20 +952,16 @@ impl Wallet {
954952
955953 fn find_payment_by_txid ( & self , target_txid : Txid ) -> Option < PaymentId > {
956954 let direct_payment_id = PaymentId ( target_txid. to_byte_array ( ) ) ;
957- if self . payment_store . get ( & direct_payment_id) . is_some ( ) {
955+ if self . payment_store . contains_key ( & direct_payment_id) {
958956 return Some ( direct_payment_id) ;
959957 }
960958
961- self . payment_store
962- . list_filter ( |p| {
963- if let PaymentKind :: Onchain { txid, conflicting_txids, .. } = & p. kind {
964- * txid == target_txid || conflicting_txids. contains ( & target_txid)
965- } else {
966- false
967- }
968- } )
969- . first ( )
970- . map ( |p| p. id )
959+ // Check if this txid is a replaced transaction
960+ if let Some ( replaced_details) = self . replaced_tx_store . get ( & target_txid) {
961+ return Some ( replaced_details. payment_id ) ;
962+ }
963+
964+ None
971965 }
972966}
973967
0 commit comments