@@ -838,6 +838,10 @@ const CHECK_CLTV_EXPIRY_SANITY: u32 = MIN_CLTV_EXPIRY_DELTA as u32 - LATENCY_GRA
838
838
#[ allow( dead_code) ]
839
839
const CHECK_CLTV_EXPIRY_SANITY_2 : u32 = MIN_CLTV_EXPIRY_DELTA as u32 - LATENCY_GRACE_PERIOD_BLOCKS - 2 * CLTV_CLAIM_BUFFER ;
840
840
841
+ /// The number of blocks before we consider an outbound payment for expiry if it doesn't have any
842
+ /// pending HTLCs in flight.
843
+ pub ( crate ) const PAYMENT_EXPIRY_BLOCKS : u32 = 3 ;
844
+
841
845
/// Information needed for constructing an invoice route hint for this channel.
842
846
#[ derive( Clone , Debug , PartialEq ) ]
843
847
pub struct CounterpartyForwardingInfo {
@@ -2411,15 +2415,31 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2411
2415
/// Signals that no further retries for the given payment will occur.
2412
2416
///
2413
2417
/// After this method returns, any future calls to [`retry_payment`] for the given `payment_id`
2414
- /// will fail with [`PaymentSendFailure::ParameterError`].
2418
+ /// will fail with [`PaymentSendFailure::ParameterError`]. If no such event has been generated,
2419
+ /// an [`Event::PaymentFailed`] event will be generated as soon as there are no remaining
2420
+ /// pending HTLCs for this payment.
2421
+ ///
2422
+ /// Note that calling this method does *not* prevent a payment from succeeding. You must still
2423
+ /// wait until you receive either a [`Event::PaymentFailed`] or [`Event::PaymentSent`] event to
2424
+ /// determine the ultimate status of a payment.
2415
2425
///
2416
2426
/// [`retry_payment`]: Self::retry_payment
2427
+ /// [`Event::PaymentFailed`]: events::Event::PaymentFailed
2428
+ /// [`Event::PaymentSent`]: events::Event::PaymentSent
2417
2429
pub fn abandon_payment ( & self , payment_id : PaymentId ) {
2418
2430
let _persistence_guard = PersistenceNotifierGuard :: notify_on_drop ( & self . total_consistency_lock , & self . persistence_notifier ) ;
2419
2431
2420
2432
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
2421
2433
if let hash_map:: Entry :: Occupied ( mut payment) = outbounds. entry ( payment_id) {
2422
- let _ = payment. get_mut ( ) . mark_abandoned ( ) ;
2434
+ if let Ok ( ( ) ) = payment. get_mut ( ) . mark_abandoned ( ) {
2435
+ if payment. get ( ) . remaining_parts ( ) == 0 {
2436
+ self . pending_events . lock ( ) . unwrap ( ) . push ( events:: Event :: PaymentFailed {
2437
+ payment_id,
2438
+ payment_hash : payment. get ( ) . payment_hash ( ) . expect ( "PendingOutboundPayments::RetriesExceeded always has a payment hash set" ) ,
2439
+ } ) ;
2440
+ payment. remove ( ) ;
2441
+ }
2442
+ }
2423
2443
}
2424
2444
}
2425
2445
@@ -3250,22 +3270,28 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3250
3270
final_cltv_expiry_delta : path_last_hop. cltv_expiry_delta ,
3251
3271
} )
3252
3272
} else { None } ;
3253
- self . pending_events . lock ( ) . unwrap ( ) . push (
3254
- events:: Event :: PaymentPathFailed {
3255
- payment_id : Some ( payment_id) ,
3256
- payment_hash,
3257
- rejected_by_dest : false ,
3258
- network_update : None ,
3259
- all_paths_failed : payment. get ( ) . remaining_parts ( ) == 0 ,
3260
- path : path. clone ( ) ,
3261
- short_channel_id : None ,
3262
- retry,
3263
- #[ cfg( test) ]
3264
- error_code : None ,
3265
- #[ cfg( test) ]
3266
- error_data : None ,
3267
- }
3268
- ) ;
3273
+ let mut pending_events = self . pending_events . lock ( ) . unwrap ( ) ;
3274
+ pending_events. push ( events:: Event :: PaymentPathFailed {
3275
+ payment_id : Some ( payment_id) ,
3276
+ payment_hash,
3277
+ rejected_by_dest : false ,
3278
+ network_update : None ,
3279
+ all_paths_failed : payment. get ( ) . remaining_parts ( ) == 0 ,
3280
+ path : path. clone ( ) ,
3281
+ short_channel_id : None ,
3282
+ retry,
3283
+ #[ cfg( test) ]
3284
+ error_code : None ,
3285
+ #[ cfg( test) ]
3286
+ error_data : None ,
3287
+ } ) ;
3288
+ if payment. get ( ) . abandoned ( ) && payment. get ( ) . remaining_parts ( ) == 0 {
3289
+ pending_events. push ( events:: Event :: PaymentFailed {
3290
+ payment_id,
3291
+ payment_hash : payment. get ( ) . payment_hash ( ) . expect ( "PendingOutboundPayments::RetriesExceeded always has a payment hash set" ) ,
3292
+ } ) ;
3293
+ payment. remove ( ) ;
3294
+ }
3269
3295
}
3270
3296
} else {
3271
3297
log_trace ! ( self . logger, "Received duplicative fail for HTLC with payment_hash {}" , log_bytes!( payment_hash. 0 ) ) ;
@@ -3296,6 +3322,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3296
3322
session_priv_bytes. copy_from_slice ( & session_priv[ ..] ) ;
3297
3323
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
3298
3324
let mut all_paths_failed = false ;
3325
+ let mut full_failure_ev = None ;
3299
3326
if let hash_map:: Entry :: Occupied ( mut payment) = outbounds. entry ( payment_id) {
3300
3327
if !payment. get_mut ( ) . remove ( & session_priv_bytes, Some ( & path) ) {
3301
3328
log_trace ! ( self . logger, "Received duplicative fail for HTLC with payment_hash {}" , log_bytes!( payment_hash. 0 ) ) ;
@@ -3307,6 +3334,13 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3307
3334
}
3308
3335
if payment. get ( ) . remaining_parts ( ) == 0 {
3309
3336
all_paths_failed = true ;
3337
+ if payment. get ( ) . abandoned ( ) {
3338
+ full_failure_ev = Some ( events:: Event :: PaymentFailed {
3339
+ payment_id,
3340
+ payment_hash : payment. get ( ) . payment_hash ( ) . expect ( "PendingOutboundPayments::RetriesExceeded always has a payment hash set" ) ,
3341
+ } ) ;
3342
+ payment. remove ( ) ;
3343
+ }
3310
3344
}
3311
3345
} else {
3312
3346
log_trace ! ( self . logger, "Received duplicative fail for HTLC with payment_hash {}" , log_bytes!( payment_hash. 0 ) ) ;
@@ -3322,7 +3356,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3322
3356
} )
3323
3357
} else { None } ;
3324
3358
log_trace ! ( self . logger, "Failing outbound payment HTLC with payment_hash {}" , log_bytes!( payment_hash. 0 ) ) ;
3325
- match & onion_error {
3359
+
3360
+ let path_failure = match & onion_error {
3326
3361
& HTLCFailReason :: LightningError { ref err } => {
3327
3362
#[ cfg( test) ]
3328
3363
let ( network_update, short_channel_id, payment_retryable, onion_error_code, onion_error_data) = onion_utils:: process_onion_failure ( & self . secp_ctx , & self . logger , & source, err. data . clone ( ) ) ;
@@ -3331,22 +3366,20 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3331
3366
// TODO: If we decided to blame ourselves (or one of our channels) in
3332
3367
// process_onion_failure we should close that channel as it implies our
3333
3368
// next-hop is needlessly blaming us!
3334
- self . pending_events . lock ( ) . unwrap ( ) . push (
3335
- events:: Event :: PaymentPathFailed {
3336
- payment_id : Some ( payment_id) ,
3337
- payment_hash : payment_hash. clone ( ) ,
3338
- rejected_by_dest : !payment_retryable,
3339
- network_update,
3340
- all_paths_failed,
3341
- path : path. clone ( ) ,
3342
- short_channel_id,
3343
- retry,
3369
+ events:: Event :: PaymentPathFailed {
3370
+ payment_id : Some ( payment_id) ,
3371
+ payment_hash : payment_hash. clone ( ) ,
3372
+ rejected_by_dest : !payment_retryable,
3373
+ network_update,
3374
+ all_paths_failed,
3375
+ path : path. clone ( ) ,
3376
+ short_channel_id,
3377
+ retry,
3344
3378
#[ cfg( test) ]
3345
- error_code : onion_error_code,
3379
+ error_code : onion_error_code,
3346
3380
#[ cfg( test) ]
3347
- error_data : onion_error_data
3348
- }
3349
- ) ;
3381
+ error_data : onion_error_data
3382
+ }
3350
3383
} ,
3351
3384
& HTLCFailReason :: Reason {
3352
3385
#[ cfg( test) ]
@@ -3361,24 +3394,25 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3361
3394
// ChannelDetails.
3362
3395
// TODO: For non-temporary failures, we really should be closing the
3363
3396
// channel here as we apparently can't relay through them anyway.
3364
- self . pending_events . lock ( ) . unwrap ( ) . push (
3365
- events:: Event :: PaymentPathFailed {
3366
- payment_id : Some ( payment_id) ,
3367
- payment_hash : payment_hash. clone ( ) ,
3368
- rejected_by_dest : path. len ( ) == 1 ,
3369
- network_update : None ,
3370
- all_paths_failed,
3371
- path : path. clone ( ) ,
3372
- short_channel_id : Some ( path. first ( ) . unwrap ( ) . short_channel_id ) ,
3373
- retry,
3397
+ events:: Event :: PaymentPathFailed {
3398
+ payment_id : Some ( payment_id) ,
3399
+ payment_hash : payment_hash. clone ( ) ,
3400
+ rejected_by_dest : path. len ( ) == 1 ,
3401
+ network_update : None ,
3402
+ all_paths_failed,
3403
+ path : path. clone ( ) ,
3404
+ short_channel_id : Some ( path. first ( ) . unwrap ( ) . short_channel_id ) ,
3405
+ retry,
3374
3406
#[ cfg( test) ]
3375
- error_code : Some ( * failure_code) ,
3407
+ error_code : Some ( * failure_code) ,
3376
3408
#[ cfg( test) ]
3377
- error_data : Some ( data. clone ( ) ) ,
3378
- }
3379
- ) ;
3409
+ error_data : Some ( data. clone ( ) ) ,
3410
+ }
3380
3411
}
3381
- }
3412
+ } ;
3413
+ let mut pending_events = self . pending_events . lock ( ) . unwrap ( ) ;
3414
+ pending_events. push ( path_failure) ;
3415
+ if let Some ( ev) = full_failure_ev { pending_events. push ( ev) ; }
3382
3416
} ,
3383
3417
HTLCSource :: PreviousHopData ( HTLCPreviousHopData { short_channel_id, htlc_id, incoming_packet_shared_secret, .. } ) => {
3384
3418
let err_packet = match onion_error {
@@ -4907,14 +4941,19 @@ where
4907
4941
inbound_payment. expiry_time > header. time as u64
4908
4942
} ) ;
4909
4943
4944
+ let mut pending_events = self . pending_events . lock ( ) . unwrap ( ) ;
4910
4945
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
4911
- outbounds. retain ( |_, payment| {
4912
- const PAYMENT_EXPIRY_BLOCKS : u32 = 3 ;
4946
+ outbounds. retain ( |payment_id, payment| {
4913
4947
if payment. remaining_parts ( ) != 0 { return true }
4914
- if let PendingOutboundPayment :: Retryable { starting_block_height, .. } = payment {
4915
- return * starting_block_height + PAYMENT_EXPIRY_BLOCKS > height
4916
- }
4917
- true
4948
+ if let PendingOutboundPayment :: Retryable { starting_block_height, payment_hash, .. } = payment {
4949
+ if * starting_block_height + PAYMENT_EXPIRY_BLOCKS <= height {
4950
+ log_info ! ( self . logger, "Timing out payment with id {} and hash {}" , log_bytes!( payment_id. 0 ) , log_bytes!( payment_hash. 0 ) ) ;
4951
+ pending_events. push ( events:: Event :: PaymentFailed {
4952
+ payment_id : * payment_id, payment_hash : * payment_hash,
4953
+ } ) ;
4954
+ false
4955
+ } else { true }
4956
+ } else { true }
4918
4957
} ) ;
4919
4958
}
4920
4959
0 commit comments