@@ -10,13 +10,16 @@ use persist::KVStoreWalletPersister;
10
10
use crate :: logger:: { log_debug, log_error, log_info, log_trace, Logger , LdkLogger } ;
11
11
12
12
use 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 } ;
14
15
use crate :: Error ;
15
16
16
17
use lightning:: chain:: chaininterface:: BroadcasterInterface ;
18
+ use lightning:: chain:: channelmonitor:: ANTI_REORG_DELAY ;
17
19
use lightning:: chain:: { BestBlock , Listen } ;
18
20
19
21
use lightning:: events:: bump_transaction:: { Utxo , WalletSource } ;
22
+ use lightning:: ln:: channelmanager:: PaymentId ;
20
23
use lightning:: ln:: inbound_payment:: ExpandedKey ;
21
24
use lightning:: ln:: msgs:: { DecodeError , UnsignedGossipMessage } ;
22
25
use lightning:: ln:: script:: ShutdownScript ;
@@ -46,6 +49,7 @@ use bitcoin::{
46
49
47
50
use std:: ops:: Deref ;
48
51
use std:: sync:: { Arc , Mutex } ;
52
+ use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
49
53
50
54
pub ( crate ) enum OnchainSendAmount {
51
55
ExactRetainingReserve { amount_sats : u64 , cur_anchor_reserve_sats : u64 } ,
@@ -110,6 +114,11 @@ where
110
114
Error :: PersistenceFailed
111
115
} ) ?;
112
116
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
+
113
122
Ok ( ( ) )
114
123
} ,
115
124
Err ( e) => {
@@ -134,6 +143,76 @@ where
134
143
Ok ( ( ) )
135
144
}
136
145
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
+
137
216
pub ( crate ) fn create_funding_transaction (
138
217
& self , output_script : ScriptBuf , amount : Amount , confirmation_target : ConfirmationTarget ,
139
218
locktime : LockTime ,
@@ -481,7 +560,12 @@ where
481
560
}
482
561
483
562
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
+ } ,
485
569
Err ( e) => {
486
570
log_error ! (
487
571
self . logger,
0 commit comments