@@ -10,13 +10,16 @@ use persist::KVStoreWalletPersister;
1010use crate :: logger:: { log_debug, log_error, log_info, log_trace, FilesystemLogger , Logger } ;
1111
1212use crate :: fee_estimator:: { ConfirmationTarget , FeeEstimator } ;
13- use crate :: payment:: store:: PaymentStore ;
13+ use crate :: payment:: store:: { ConfirmationStatus , PaymentStore } ;
14+ use crate :: payment:: { PaymentDetails , PaymentDirection , PaymentStatus } ;
1415use crate :: Error ;
1516
1617use lightning:: chain:: chaininterface:: BroadcasterInterface ;
18+ use lightning:: chain:: channelmonitor:: ANTI_REORG_DELAY ;
1719use lightning:: chain:: { BestBlock , Listen } ;
1820
1921use lightning:: events:: bump_transaction:: { Utxo , WalletSource } ;
22+ use lightning:: ln:: channelmanager:: PaymentId ;
2023use lightning:: ln:: inbound_payment:: ExpandedKey ;
2124use lightning:: ln:: msgs:: { DecodeError , UnsignedGossipMessage } ;
2225use lightning:: ln:: script:: ShutdownScript ;
@@ -45,6 +48,7 @@ use bitcoin::{
4548
4649use std:: ops:: Deref ;
4750use std:: sync:: { Arc , Mutex } ;
51+ use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
4852
4953pub ( crate ) enum OnchainSendAmount {
5054 ExactRetainingReserve { amount_sats : u64 , cur_anchor_reserve_sats : u64 } ,
@@ -109,6 +113,11 @@ where
109113 Error :: PersistenceFailed
110114 } ) ?;
111115
116+ self . update_payment_store ( & mut * locked_wallet) . map_err ( |e| {
117+ log_error ! ( self . logger, "Failed to update payment store: {}" , e) ;
118+ Error :: PersistenceFailed
119+ } ) ?;
120+
112121 Ok ( ( ) )
113122 } ,
114123 Err ( e) => {
@@ -133,6 +142,76 @@ where
133142 Ok ( ( ) )
134143 }
135144
145+ fn update_payment_store < ' a > (
146+ & self , locked_wallet : & ' a mut PersistedWallet < KVStoreWalletPersister > ,
147+ ) -> Result < ( ) , Error > {
148+ let latest_update_timestamp = SystemTime :: now ( )
149+ . duration_since ( UNIX_EPOCH )
150+ . unwrap_or ( Duration :: from_secs ( 0 ) )
151+ . as_secs ( ) ;
152+
153+ for wtx in locked_wallet. transactions ( ) {
154+ let id = PaymentId ( wtx. tx_node . txid . to_byte_array ( ) ) ;
155+ let txid = wtx. tx_node . txid ;
156+ let ( payment_status, confirmation_status) = match wtx. chain_position {
157+ bdk_chain:: ChainPosition :: Confirmed { anchor, .. } => {
158+ let confirmation_height = anchor. block_id . height ;
159+ let cur_height = locked_wallet. latest_checkpoint ( ) . height ( ) ;
160+ let payment_status = if cur_height >= confirmation_height + ANTI_REORG_DELAY - 1
161+ {
162+ PaymentStatus :: Succeeded
163+ } else {
164+ PaymentStatus :: Pending
165+ } ;
166+ let confirmation_status = ConfirmationStatus :: Confirmed {
167+ block_hash : anchor. block_id . hash ,
168+ height : confirmation_height,
169+ timestamp : anchor. confirmation_time ,
170+ } ;
171+ ( payment_status, confirmation_status)
172+ } ,
173+ bdk_chain:: ChainPosition :: Unconfirmed { .. } => {
174+ ( PaymentStatus :: Pending , ConfirmationStatus :: Unconfirmed )
175+ } ,
176+ } ;
177+ // TODO: It would be great to introduce additional variants for
178+ // `ChannelFunding` and `ChannelClosing`. For the former, we could just
179+ // take a reference to `ChannelManager` here and check against
180+ // `list_channels`. But for the latter the best approach is much less
181+ // clear: for force-closes/HTLC spends we should be good querying
182+ // `OutputSweeper::tracked_spendable_outputs`, but regular channel closes
183+ // (i.e., `SpendableOutputDescriptor::StaticOutput` variants) are directly
184+ // spent to a wallet address. The only solution I can come up with is to
185+ // create and persist a list of 'static pending outputs' that we could use
186+ // here to determine the `PaymentKind`, but that's not really satisfactory, so
187+ // we're punting on it until we can come up with a better solution.
188+ let kind = crate :: payment:: PaymentKind :: Onchain { txid, status : confirmation_status } ;
189+ let ( sent, received) = locked_wallet. sent_and_received ( & wtx. tx_node . tx ) ;
190+ let ( direction, amount_msat) = if sent > received {
191+ let direction = PaymentDirection :: Outbound ;
192+ let amount_msat = Some ( sent. to_sat ( ) . saturating_sub ( received. to_sat ( ) ) * 1000 ) ;
193+ ( direction, amount_msat)
194+ } else {
195+ let direction = PaymentDirection :: Inbound ;
196+ let amount_msat = Some ( received. to_sat ( ) . saturating_sub ( sent. to_sat ( ) ) * 1000 ) ;
197+ ( direction, amount_msat)
198+ } ;
199+
200+ let payment = PaymentDetails {
201+ id,
202+ kind,
203+ amount_msat,
204+ direction,
205+ status : payment_status,
206+ latest_update_timestamp,
207+ } ;
208+
209+ self . payment_store . insert_or_update ( & payment) ?;
210+ }
211+
212+ Ok ( ( ) )
213+ }
214+
136215 pub ( crate ) fn create_funding_transaction (
137216 & self , output_script : ScriptBuf , amount : Amount , confirmation_target : ConfirmationTarget ,
138217 locktime : LockTime ,
@@ -477,7 +556,12 @@ where
477556 }
478557
479558 match locked_wallet. apply_block ( block, height) {
480- Ok ( ( ) ) => ( ) ,
559+ Ok ( ( ) ) => {
560+ if let Err ( e) = self . update_payment_store ( & mut * locked_wallet) {
561+ log_error ! ( self . logger, "Failed to update payment store: {}" , e) ;
562+ return ;
563+ }
564+ } ,
481565 Err ( e) => {
482566 log_error ! (
483567 self . logger,
0 commit comments