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