@@ -11,13 +11,16 @@ use crate::logger::{log_debug, log_error, log_info, log_trace, FilesystemLogger,
1111
1212use crate :: event:: EventQueue ;
1313use crate :: fee_estimator:: { ConfirmationTarget , FeeEstimator } ;
14- use crate :: payment:: store:: PaymentStore ;
14+ use crate :: payment:: store:: { ConfirmationStatus , PaymentStore } ;
15+ use crate :: payment:: { PaymentDetails , PaymentDirection , PaymentStatus } ;
1516use crate :: Error ;
1617
1718use lightning:: chain:: chaininterface:: BroadcasterInterface ;
19+ use lightning:: chain:: channelmonitor:: ANTI_REORG_DELAY ;
1820use lightning:: chain:: { BestBlock , Listen } ;
1921
2022use lightning:: events:: bump_transaction:: { Utxo , WalletSource } ;
23+ use lightning:: ln:: channelmanager:: PaymentId ;
2124use lightning:: ln:: inbound_payment:: ExpandedKey ;
2225use lightning:: ln:: msgs:: { DecodeError , UnsignedGossipMessage } ;
2326use lightning:: ln:: script:: ShutdownScript ;
@@ -46,6 +49,7 @@ use bitcoin::{
4649
4750use std:: ops:: Deref ;
4851use std:: sync:: { Arc , Mutex } ;
52+ use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
4953
5054pub ( crate ) enum OnchainSendAmount {
5155 ExactRetainingReserve { amount_sats : u64 , cur_anchor_reserve_sats : u64 } ,
@@ -112,6 +116,11 @@ where
112116 Error :: PersistenceFailed
113117 } ) ?;
114118
119+ self . update_payment_store ( & mut * locked_wallet) . map_err ( |e| {
120+ log_error ! ( self . logger, "Failed to update payment store: {}" , e) ;
121+ Error :: PersistenceFailed
122+ } ) ?;
123+
115124 Ok ( ( ) )
116125 } ,
117126 Err ( e) => {
@@ -136,6 +145,76 @@ where
136145 Ok ( ( ) )
137146 }
138147
148+ fn update_payment_store < ' a > (
149+ & self , locked_wallet : & ' a mut PersistedWallet < KVStoreWalletPersister > ,
150+ ) -> Result < ( ) , Error > {
151+ let latest_update_timestamp = SystemTime :: now ( )
152+ . duration_since ( UNIX_EPOCH )
153+ . unwrap_or ( Duration :: from_secs ( 0 ) )
154+ . as_secs ( ) ;
155+
156+ for wtx in locked_wallet. transactions ( ) {
157+ let id = PaymentId ( wtx. tx_node . txid . to_byte_array ( ) ) ;
158+ let txid = wtx. tx_node . txid ;
159+ let ( payment_status, confirmation_status) = match wtx. chain_position {
160+ bdk_chain:: ChainPosition :: Confirmed { anchor, .. } => {
161+ let confirmation_height = anchor. block_id . height ;
162+ let cur_height = locked_wallet. latest_checkpoint ( ) . height ( ) ;
163+ let payment_status = if cur_height >= confirmation_height + ANTI_REORG_DELAY - 1
164+ {
165+ PaymentStatus :: Succeeded
166+ } else {
167+ PaymentStatus :: Pending
168+ } ;
169+ let confirmation_status = ConfirmationStatus :: Confirmed {
170+ block_hash : anchor. block_id . hash ,
171+ height : confirmation_height,
172+ timestamp : anchor. confirmation_time ,
173+ } ;
174+ ( payment_status, confirmation_status)
175+ } ,
176+ bdk_chain:: ChainPosition :: Unconfirmed { .. } => {
177+ ( PaymentStatus :: Pending , ConfirmationStatus :: Unconfirmed )
178+ } ,
179+ } ;
180+ // TODO: It would be great to introduce additional variants for
181+ // `ChannelFunding` and `ChannelClosing`. For the former, we could just
182+ // take a reference to `ChannelManager` here and check against
183+ // `list_channels`. But for the latter the best approach is much less
184+ // clear: for force-closes/HTLC spends we should be good querying
185+ // `OutputSweeper::tracked_spendable_outputs`, but regular channel closes
186+ // (i.e., `SpendableOutputDescriptor::StaticOutput` variants) are directly
187+ // spent to a wallet address. The only solution I can come up with is to
188+ // create and persist a list of 'static pending outputs' that we could use
189+ // here to determine the `PaymentKind`, but that's not really satisfactory, so
190+ // we're punting on it until we can come up with a better solution.
191+ let kind = crate :: payment:: PaymentKind :: Onchain { txid, status : confirmation_status } ;
192+ let ( sent, received) = locked_wallet. sent_and_received ( & wtx. tx_node . tx ) ;
193+ let ( direction, amount_msat) = if sent > received {
194+ let direction = PaymentDirection :: Outbound ;
195+ let amount_msat = Some ( sent. to_sat ( ) . saturating_sub ( received. to_sat ( ) ) * 1000 ) ;
196+ ( direction, amount_msat)
197+ } else {
198+ let direction = PaymentDirection :: Inbound ;
199+ let amount_msat = Some ( received. to_sat ( ) . saturating_sub ( sent. to_sat ( ) ) * 1000 ) ;
200+ ( direction, amount_msat)
201+ } ;
202+
203+ let payment = PaymentDetails {
204+ id,
205+ kind,
206+ amount_msat,
207+ direction,
208+ status : payment_status,
209+ latest_update_timestamp,
210+ } ;
211+
212+ self . payment_store . insert_or_update ( & payment) ?;
213+ }
214+
215+ Ok ( ( ) )
216+ }
217+
139218 pub ( crate ) fn create_funding_transaction (
140219 & self , output_script : ScriptBuf , amount : Amount , confirmation_target : ConfirmationTarget ,
141220 locktime : LockTime ,
@@ -480,7 +559,12 @@ where
480559 }
481560
482561 match locked_wallet. apply_block ( block, height) {
483- Ok ( ( ) ) => ( ) ,
562+ Ok ( ( ) ) => {
563+ if let Err ( e) = self . update_payment_store ( & mut * locked_wallet) {
564+ log_error ! ( self . logger, "Failed to update payment store: {}" , e) ;
565+ return ;
566+ }
567+ } ,
484568 Err ( e) => {
485569 log_error ! (
486570 self . logger,
0 commit comments