@@ -416,13 +416,44 @@ pub(crate) enum PendingOutboundPayment {
416
416
/// Our best known block height at the time this payment was initiated.
417
417
starting_block_height : u32 ,
418
418
} ,
419
+ /// When a payment completes, we continue tracking it until all pendings HTLCs have been
420
+ /// resolved. This ensures we don't look up pending payments in ChannelMonitors on restart and
421
+ /// add a pending payment that was already completed.
422
+ Completed {
423
+ session_privs : HashSet < [ u8 ; 32 ] > ,
424
+ } ,
419
425
}
420
426
421
427
impl PendingOutboundPayment {
428
+ fn is_retryable ( & self ) -> bool {
429
+ match self {
430
+ PendingOutboundPayment :: Retryable { .. } => true ,
431
+ _ => false ,
432
+ }
433
+ }
434
+ fn is_completed ( & self ) -> bool {
435
+ match self {
436
+ PendingOutboundPayment :: Completed { .. } => true ,
437
+ _ => false ,
438
+ }
439
+ }
440
+
441
+ fn mark_completed ( & mut self ) {
442
+ let mut session_privs = HashSet :: new ( ) ;
443
+ core:: mem:: swap ( & mut session_privs, match self {
444
+ PendingOutboundPayment :: Legacy { session_privs } |
445
+ PendingOutboundPayment :: Retryable { session_privs, .. } |
446
+ PendingOutboundPayment :: Completed { session_privs }
447
+ => session_privs
448
+ } ) ;
449
+ * self = PendingOutboundPayment :: Completed { session_privs } ;
450
+ }
451
+
422
452
fn remove ( & mut self , session_priv : & [ u8 ; 32 ] , part_amt_msat : u64 ) -> bool {
423
453
let remove_res = match self {
424
454
PendingOutboundPayment :: Legacy { session_privs } |
425
- PendingOutboundPayment :: Retryable { session_privs, .. } => {
455
+ PendingOutboundPayment :: Retryable { session_privs, .. } |
456
+ PendingOutboundPayment :: Completed { session_privs } => {
426
457
session_privs. remove ( session_priv)
427
458
}
428
459
} ;
@@ -440,6 +471,7 @@ impl PendingOutboundPayment {
440
471
PendingOutboundPayment :: Retryable { session_privs, .. } => {
441
472
session_privs. insert ( session_priv)
442
473
}
474
+ PendingOutboundPayment :: Completed { .. } => false
443
475
} ;
444
476
if insert_res {
445
477
if let PendingOutboundPayment :: Retryable { ref mut pending_amt_msat, .. } = self {
@@ -452,7 +484,8 @@ impl PendingOutboundPayment {
452
484
fn remaining_parts ( & self ) -> usize {
453
485
match self {
454
486
PendingOutboundPayment :: Legacy { session_privs } |
455
- PendingOutboundPayment :: Retryable { session_privs, .. } => {
487
+ PendingOutboundPayment :: Retryable { session_privs, .. } |
488
+ PendingOutboundPayment :: Completed { session_privs } => {
456
489
session_privs. len ( )
457
490
}
458
491
}
@@ -1958,6 +1991,15 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
1958
1991
let onion_packet = onion_utils:: construct_onion_packet ( onion_payloads, onion_keys, prng_seed, payment_hash) ;
1959
1992
1960
1993
let _persistence_guard = PersistenceNotifierGuard :: notify_on_drop ( & self . total_consistency_lock , & self . persistence_notifier ) ;
1994
+ let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1995
+ let payment_entry = pending_outbounds. entry ( payment_id) ;
1996
+ if let hash_map:: Entry :: Occupied ( payment) = & payment_entry {
1997
+ if !payment. get ( ) . is_retryable ( ) {
1998
+ return Err ( APIError :: RouteError {
1999
+ err : "Payment already completed"
2000
+ } ) ;
2001
+ }
2002
+ }
1961
2003
1962
2004
let err: Result < ( ) , _ > = loop {
1963
2005
let mut channel_lock = self . channel_state . lock ( ) . unwrap ( ) ;
@@ -1985,8 +2027,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
1985
2027
} , onion_packet, & self . logger) ,
1986
2028
channel_state, chan) ;
1987
2029
1988
- let mut pending_outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
1989
- let payment = pending_outbounds. entry ( payment_id) . or_insert_with ( || PendingOutboundPayment :: Retryable {
2030
+ let payment = payment_entry. or_insert_with ( || PendingOutboundPayment :: Retryable {
1990
2031
session_privs : HashSet :: new ( ) ,
1991
2032
pending_amt_msat : 0 ,
1992
2033
payment_hash : * payment_hash,
@@ -2182,7 +2223,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2182
2223
return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
2183
2224
err : "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" . to_string ( )
2184
2225
} ) )
2185
- }
2226
+ } ,
2227
+ PendingOutboundPayment :: Completed { .. } => {
2228
+ return Err ( PaymentSendFailure :: ParameterError ( APIError :: RouteError {
2229
+ err : "Payment already completed"
2230
+ } ) ) ;
2231
+ } ,
2186
2232
}
2187
2233
} else {
2188
2234
return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
@@ -3010,7 +3056,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3010
3056
session_priv_bytes. copy_from_slice ( & session_priv[ ..] ) ;
3011
3057
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
3012
3058
if let hash_map:: Entry :: Occupied ( mut payment) = outbounds. entry ( payment_id) {
3013
- if payment. get_mut ( ) . remove ( & session_priv_bytes, path. last ( ) . unwrap ( ) . fee_msat ) {
3059
+ if payment. get_mut ( ) . remove ( & session_priv_bytes, path. last ( ) . unwrap ( ) . fee_msat ) &&
3060
+ !payment. get ( ) . is_completed ( )
3061
+ {
3014
3062
self . pending_events . lock ( ) . unwrap ( ) . push (
3015
3063
events:: Event :: PaymentPathFailed {
3016
3064
payment_hash,
@@ -3059,6 +3107,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3059
3107
log_trace ! ( self . logger, "Received duplicative fail for HTLC with payment_hash {}" , log_bytes!( payment_hash. 0 ) ) ;
3060
3108
return ;
3061
3109
}
3110
+ if sessions. get ( ) . is_completed ( ) {
3111
+ log_trace ! ( self . logger, "Received failure of HTLC with payment_hash {} after payment completion" , log_bytes!( payment_hash. 0 ) ) ;
3112
+ return ;
3113
+ }
3062
3114
if sessions. get ( ) . remaining_parts ( ) == 0 {
3063
3115
all_paths_failed = true ;
3064
3116
}
@@ -3305,15 +3357,45 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3305
3357
} else { unreachable ! ( ) ; }
3306
3358
}
3307
3359
3360
+ fn finalize_claims ( & self , mut sources : Vec < HTLCSource > ) {
3361
+ for source in sources. drain ( ..) {
3362
+ if let HTLCSource :: OutboundRoute { session_priv, payment_id, .. } = source {
3363
+ let mut session_priv_bytes = [ 0 ; 32 ] ;
3364
+ session_priv_bytes. copy_from_slice ( & session_priv[ ..] ) ;
3365
+ let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
3366
+ if let hash_map:: Entry :: Occupied ( mut sessions) = outbounds. entry ( payment_id) {
3367
+ assert ! ( sessions. get( ) . is_completed( ) ) ;
3368
+ sessions. get_mut ( ) . remove ( & session_priv_bytes, 0 ) ; // Note that the amount is no longer tracked
3369
+ if sessions. get ( ) . remaining_parts ( ) == 0 {
3370
+ sessions. remove ( ) ;
3371
+ }
3372
+ }
3373
+ }
3374
+ }
3375
+ }
3308
3376
fn claim_funds_internal ( & self , mut channel_state_lock : MutexGuard < ChannelHolder < Signer > > , source : HTLCSource , payment_preimage : PaymentPreimage , forwarded_htlc_value_msat : Option < u64 > , from_onchain : bool ) {
3309
3377
match source {
3310
3378
HTLCSource :: OutboundRoute { session_priv, payment_id, path, .. } => {
3311
3379
mem:: drop ( channel_state_lock) ;
3312
3380
let mut session_priv_bytes = [ 0 ; 32 ] ;
3313
3381
session_priv_bytes. copy_from_slice ( & session_priv[ ..] ) ;
3314
3382
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
3315
- let found_payment = if let Some ( mut sessions) = outbounds. remove ( & payment_id) {
3316
- sessions. remove ( & session_priv_bytes, path. last ( ) . unwrap ( ) . fee_msat )
3383
+ let found_payment = if let hash_map:: Entry :: Occupied ( mut sessions) = outbounds. entry ( payment_id) {
3384
+ let found_payment = !sessions. get ( ) . is_completed ( ) ;
3385
+ sessions. get_mut ( ) . mark_completed ( ) ;
3386
+ if from_onchain {
3387
+ // We currently immediately remove HTLCs which were fulfilled on-chain.
3388
+ // This could potentially lead to removing a pending payment too early,
3389
+ // with a reorg of one block causing us to re-add the completed payment on
3390
+ // restart.
3391
+ // TODO: We should have a second monitor event that informs us of payments
3392
+ // irrevocably completing.
3393
+ sessions. get_mut ( ) . remove ( & session_priv_bytes, path. last ( ) . unwrap ( ) . fee_msat ) ;
3394
+ if sessions. get ( ) . remaining_parts ( ) == 0 {
3395
+ sessions. remove ( ) ;
3396
+ }
3397
+ }
3398
+ found_payment
3317
3399
} else { false } ;
3318
3400
if found_payment {
3319
3401
self . pending_events . lock ( ) . unwrap ( ) . push (
@@ -3954,6 +4036,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3954
4036
} ) ;
3955
4037
}
3956
4038
break Ok ( ( raa_updates. to_forward_htlcs , raa_updates. failed_htlcs ,
4039
+ raa_updates. finalized_claim_htlcs ,
3957
4040
chan. get ( ) . get_short_channel_id ( )
3958
4041
. expect ( "RAA should only work on a short-id-available channel" ) ,
3959
4042
chan. get ( ) . get_funding_txo ( ) . unwrap ( ) ) )
@@ -3963,11 +4046,14 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3963
4046
} ;
3964
4047
self . fail_holding_cell_htlcs ( htlcs_to_fail, msg. channel_id ) ;
3965
4048
match res {
3966
- Ok ( ( pending_forwards, mut pending_failures, short_channel_id, channel_outpoint) ) => {
4049
+ Ok ( ( pending_forwards, mut pending_failures, finalized_claim_htlcs,
4050
+ short_channel_id, channel_outpoint) ) =>
4051
+ {
3967
4052
for failure in pending_failures. drain ( ..) {
3968
4053
self . fail_htlc_backwards_internal ( self . channel_state . lock ( ) . unwrap ( ) , failure. 0 , & failure. 1 , failure. 2 ) ;
3969
4054
}
3970
4055
self . forward_htlcs ( & mut [ ( short_channel_id, channel_outpoint, pending_forwards) ] ) ;
4056
+ self . finalize_claims ( finalized_claim_htlcs) ;
3971
4057
Ok ( ( ) )
3972
4058
} ,
3973
4059
Err ( e) => Err ( e)
@@ -5313,10 +5399,13 @@ impl_writeable_tlv_based!(PendingInboundPayment, {
5313
5399
( 8 , min_value_msat, required) ,
5314
5400
} ) ;
5315
5401
5316
- impl_writeable_tlv_based_enum ! ( PendingOutboundPayment ,
5402
+ impl_writeable_tlv_based_enum_upgradable ! ( PendingOutboundPayment ,
5317
5403
( 0 , Legacy ) => {
5318
5404
( 0 , session_privs, required) ,
5319
5405
} ,
5406
+ ( 1 , Completed ) => {
5407
+ ( 0 , session_privs, required) ,
5408
+ } ,
5320
5409
( 2 , Retryable ) => {
5321
5410
( 0 , session_privs, required) ,
5322
5411
( 2 , payment_hash, required) ,
@@ -5325,7 +5414,7 @@ impl_writeable_tlv_based_enum!(PendingOutboundPayment,
5325
5414
( 8 , pending_amt_msat, required) ,
5326
5415
( 10 , starting_block_height, required) ,
5327
5416
} ,
5328
- ; ) ;
5417
+ ) ;
5329
5418
5330
5419
impl < Signer : Sign , M : Deref , T : Deref , K : Deref , F : Deref , L : Deref > Writeable for ChannelManager < Signer , M , T , K , F , L >
5331
5420
where M :: Target : chain:: Watch < Signer > ,
@@ -5418,7 +5507,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
5418
5507
// For backwards compat, write the session privs and their total length.
5419
5508
let mut num_pending_outbounds_compat: u64 = 0 ;
5420
5509
for ( _, outbound) in pending_outbound_payments. iter ( ) {
5421
- num_pending_outbounds_compat += outbound. remaining_parts ( ) as u64 ;
5510
+ if !outbound. is_completed ( ) {
5511
+ num_pending_outbounds_compat += outbound. remaining_parts ( ) as u64 ;
5512
+ }
5422
5513
}
5423
5514
num_pending_outbounds_compat. write ( writer) ?;
5424
5515
for ( _, outbound) in pending_outbound_payments. iter ( ) {
@@ -5429,6 +5520,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
5429
5520
session_priv. write ( writer) ?;
5430
5521
}
5431
5522
}
5523
+ PendingOutboundPayment :: Completed { .. } => { } ,
5432
5524
}
5433
5525
}
5434
5526
@@ -5439,7 +5531,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
5439
5531
PendingOutboundPayment :: Legacy { session_privs } |
5440
5532
PendingOutboundPayment :: Retryable { session_privs, .. } => {
5441
5533
pending_outbound_payments_no_retry. insert ( * id, session_privs. clone ( ) ) ;
5442
- }
5534
+ } ,
5535
+ _ => { } ,
5443
5536
}
5444
5537
}
5445
5538
write_tlv_fields ! ( writer, {
0 commit comments