@@ -145,7 +145,7 @@ pub(super) enum HTLCForwardInfo {
145
145
}
146
146
147
147
/// Tracks the inbound corresponding to an outbound HTLC
148
- #[ derive( Clone , PartialEq ) ]
148
+ #[ derive( Clone , Hash , PartialEq , Eq ) ]
149
149
pub ( crate ) struct HTLCPreviousHopData {
150
150
short_channel_id : u64 ,
151
151
htlc_id : u64 ,
@@ -189,7 +189,8 @@ impl Readable for PaymentId {
189
189
}
190
190
}
191
191
/// Tracks the inbound corresponding to an outbound HTLC
192
- #[ derive( Clone , PartialEq ) ]
192
+ #[ allow( clippy:: derive_hash_xor_eq) ] // Our Hash is faithful to the data, we just don't have SecretKey::hash
193
+ #[ derive( Clone , PartialEq , Eq ) ]
193
194
pub ( crate ) enum HTLCSource {
194
195
PreviousHopData ( HTLCPreviousHopData ) ,
195
196
OutboundRoute {
@@ -202,6 +203,24 @@ pub(crate) enum HTLCSource {
202
203
payment_secret : Option < PaymentSecret > ,
203
204
} ,
204
205
}
206
+ impl core:: hash:: Hash for HTLCSource {
207
+ fn hash < H : core:: hash:: Hasher > ( & self , hasher : & mut H ) {
208
+ match self {
209
+ HTLCSource :: PreviousHopData ( prev_hop_data) => {
210
+ 0u8 . hash ( hasher) ;
211
+ prev_hop_data. hash ( hasher) ;
212
+ } ,
213
+ HTLCSource :: OutboundRoute { path, session_priv, payment_id, payment_secret, first_hop_htlc_msat } => {
214
+ 1u8 . hash ( hasher) ;
215
+ path. hash ( hasher) ;
216
+ session_priv[ ..] . hash ( hasher) ;
217
+ payment_id. hash ( hasher) ;
218
+ payment_secret. hash ( hasher) ;
219
+ first_hop_htlc_msat. hash ( hasher) ;
220
+ } ,
221
+ }
222
+ }
223
+ }
205
224
#[ cfg( test) ]
206
225
impl HTLCSource {
207
226
pub fn dummy ( ) -> Self {
@@ -5846,6 +5865,49 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
5846
5865
outbounds. insert ( id, PendingOutboundPayment :: Legacy { session_privs } ) ;
5847
5866
}
5848
5867
pending_outbound_payments = Some ( outbounds) ;
5868
+ } else {
5869
+ // If we're tracking pending payments, ensure we haven't lost any by looking at the
5870
+ // ChannelMonitor data for any channels for which we do not have authorative state
5871
+ // (i.e. those for which we just force-closed above or we otherwise don't have a
5872
+ // corresponding `Channel` at all).
5873
+ // This avoids several edge-cases where we would otherwise "forget" about pending
5874
+ // payments which are still in-flight via their on-chain state.
5875
+ // We only rebuild the pending payments map if we were most recently serialized by
5876
+ // 0.0.102+
5877
+ for ( _, monitor) in args. channel_monitors {
5878
+ if by_id. get ( & monitor. get_funding_txo ( ) . 0 . to_channel_id ( ) ) . is_none ( ) {
5879
+ for ( htlc_source, htlc) in monitor. get_pending_htlcs ( ) {
5880
+ if let HTLCSource :: OutboundRoute { payment_id, session_priv, path, payment_secret, .. } = htlc_source {
5881
+ if path. is_empty ( ) {
5882
+ log_error ! ( args. logger, "Got an empty path for a pending payment" ) ;
5883
+ return Err ( DecodeError :: InvalidValue ) ;
5884
+ }
5885
+ let path_amt = path. last ( ) . unwrap ( ) . fee_msat ;
5886
+ let mut session_priv_bytes = [ 0 ; 32 ] ;
5887
+ session_priv_bytes[ ..] . copy_from_slice ( & session_priv[ ..] ) ;
5888
+ match pending_outbound_payments. as_mut ( ) . unwrap ( ) . entry ( payment_id) {
5889
+ hash_map:: Entry :: Occupied ( mut entry) => {
5890
+ let readded = entry. get_mut ( ) . insert ( session_priv_bytes, path_amt) ;
5891
+ log_info ! ( args. logger, "{} a pending payment path for {} msat for session priv {} on an existing pending payment with payment hash {}" ,
5892
+ if readded { "Added" } else { "Had" } , path_amt, log_bytes!( session_priv_bytes) , log_bytes!( htlc. payment_hash. 0 ) ) ;
5893
+ } ,
5894
+ hash_map:: Entry :: Vacant ( entry) => {
5895
+ entry. insert ( PendingOutboundPayment :: Retryable {
5896
+ session_privs : [ session_priv_bytes] . iter ( ) . map ( |a| * a) . collect ( ) ,
5897
+ payment_hash : htlc. payment_hash ,
5898
+ payment_secret,
5899
+ pending_amt_msat : path_amt,
5900
+ total_msat : path_amt,
5901
+ starting_block_height : best_block_height,
5902
+ } ) ;
5903
+ log_info ! ( args. logger, "Added a pending payment for {} msat with payment hash {} for path with session priv {}" ,
5904
+ path_amt, log_bytes!( htlc. payment_hash. 0 ) , log_bytes!( session_priv_bytes) ) ;
5905
+ }
5906
+ }
5907
+ }
5908
+ }
5909
+ }
5910
+ }
5849
5911
}
5850
5912
5851
5913
let mut secp_ctx = Secp256k1 :: new ( ) ;
0 commit comments