@@ -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 ;
@@ -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 } ,
@@ -110,6 +114,11 @@ where
110114 Error :: PersistenceFailed
111115 } ) ?;
112116
117+ self . update_payment_store ( & mut * locked_wallet) . map_err ( |e| {
118+ log_error ! ( self . logger, "Failed to update payment store: {}" , e) ;
119+ Error :: PersistenceFailed
120+ } ) ?;
121+
113122 Ok ( ( ) )
114123 } ,
115124 Err ( e) => {
@@ -134,6 +143,76 @@ where
134143 Ok ( ( ) )
135144 }
136145
146+ fn update_payment_store < ' a > (
147+ & self , locked_wallet : & ' a mut PersistedWallet < KVStoreWalletPersister > ,
148+ ) -> Result < ( ) , Error > {
149+ let latest_update_timestamp = SystemTime :: now ( )
150+ . duration_since ( UNIX_EPOCH )
151+ . unwrap_or ( Duration :: from_secs ( 0 ) )
152+ . as_secs ( ) ;
153+
154+ for wtx in locked_wallet. transactions ( ) {
155+ let id = PaymentId ( wtx. tx_node . txid . to_byte_array ( ) ) ;
156+ let txid = wtx. tx_node . txid ;
157+ let ( payment_status, confirmation_status) = match wtx. chain_position {
158+ bdk_chain:: ChainPosition :: Confirmed { anchor, .. } => {
159+ let confirmation_height = anchor. block_id . height ;
160+ let cur_height = locked_wallet. latest_checkpoint ( ) . height ( ) ;
161+ let payment_status = if cur_height >= confirmation_height + ANTI_REORG_DELAY - 1
162+ {
163+ PaymentStatus :: Succeeded
164+ } else {
165+ PaymentStatus :: Pending
166+ } ;
167+ let confirmation_status = ConfirmationStatus :: Confirmed {
168+ block_hash : anchor. block_id . hash ,
169+ height : confirmation_height,
170+ timestamp : anchor. confirmation_time ,
171+ } ;
172+ ( payment_status, confirmation_status)
173+ } ,
174+ bdk_chain:: ChainPosition :: Unconfirmed { .. } => {
175+ ( PaymentStatus :: Pending , ConfirmationStatus :: Unconfirmed )
176+ } ,
177+ } ;
178+ // TODO: It would be great to introduce additional variants for
179+ // `ChannelFunding` and `ChannelClosing`. For the former, we could just
180+ // take a reference to `ChannelManager` here and check against
181+ // `list_channels`. But for the latter the best approach is much less
182+ // clear: for force-closes/HTLC spends we should be good querying
183+ // `OutputSweeper::tracked_spendable_outputs`, but regular channel closes
184+ // (i.e., `SpendableOutputDescriptor::StaticOutput` variants) are directly
185+ // spent to a wallet address. The only solution I can come up with is to
186+ // create and persist a list of 'static pending outputs' that we could use
187+ // here to determine the `PaymentKind`, but that's not really satisfactory, so
188+ // we're punting on it until we can come up with a better solution.
189+ let kind = crate :: payment:: PaymentKind :: Onchain { txid, status : confirmation_status } ;
190+ let ( sent, received) = locked_wallet. sent_and_received ( & wtx. tx_node . tx ) ;
191+ let ( direction, amount_msat) = if sent > received {
192+ let direction = PaymentDirection :: Outbound ;
193+ let amount_msat = Some ( sent. to_sat ( ) . saturating_sub ( received. to_sat ( ) ) * 1000 ) ;
194+ ( direction, amount_msat)
195+ } else {
196+ let direction = PaymentDirection :: Inbound ;
197+ let amount_msat = Some ( received. to_sat ( ) . saturating_sub ( sent. to_sat ( ) ) * 1000 ) ;
198+ ( direction, amount_msat)
199+ } ;
200+
201+ let payment = PaymentDetails {
202+ id,
203+ kind,
204+ amount_msat,
205+ direction,
206+ status : payment_status,
207+ latest_update_timestamp,
208+ } ;
209+
210+ self . payment_store . insert_or_update ( & payment) ?;
211+ }
212+
213+ Ok ( ( ) )
214+ }
215+
137216 pub ( crate ) fn create_funding_transaction (
138217 & self , output_script : ScriptBuf , amount : Amount , confirmation_target : ConfirmationTarget ,
139218 locktime : LockTime ,
@@ -481,7 +560,12 @@ where
481560 }
482561
483562 match locked_wallet. apply_block ( block, height) {
484- Ok ( ( ) ) => ( ) ,
563+ Ok ( ( ) ) => {
564+ if let Err ( e) = self . update_payment_store ( & mut * locked_wallet) {
565+ log_error ! ( self . logger, "Failed to update payment store: {}" , e) ;
566+ return ;
567+ }
568+ } ,
485569 Err ( e) => {
486570 log_error ! (
487571 self . logger,
0 commit comments