@@ -10,13 +10,16 @@ use persist::KVStoreWalletPersister;
10
10
use crate :: logger:: { log_debug, log_error, log_info, log_trace, FilesystemLogger , Logger } ;
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 ;
@@ -45,6 +48,7 @@ use bitcoin::{
45
48
46
49
use std:: ops:: Deref ;
47
50
use std:: sync:: { Arc , Mutex } ;
51
+ use std:: time:: { Duration , SystemTime , UNIX_EPOCH } ;
48
52
49
53
pub ( crate ) enum OnchainSendAmount {
50
54
ExactRetainingReserve { amount_sats : u64 , cur_anchor_reserve_sats : u64 } ,
@@ -109,6 +113,11 @@ where
109
113
Error :: PersistenceFailed
110
114
} ) ?;
111
115
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
+
112
121
Ok ( ( ) )
113
122
} ,
114
123
Err ( e) => {
@@ -133,6 +142,76 @@ where
133
142
Ok ( ( ) )
134
143
}
135
144
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
+
136
215
pub ( crate ) fn create_funding_transaction (
137
216
& self , output_script : ScriptBuf , amount : Amount , confirmation_target : ConfirmationTarget ,
138
217
locktime : LockTime ,
@@ -477,7 +556,12 @@ where
477
556
}
478
557
479
558
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
+ } ,
481
565
Err ( e) => {
482
566
log_error ! (
483
567
self . logger,
0 commit comments