@@ -416,13 +416,44 @@ 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
}
@@ -1964,6 +1997,11 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
1964
1997
starting_block_height : self . best_block . read ( ) . unwrap ( ) . height ( ) ,
1965
1998
total_msat : total_value,
1966
1999
} ) ;
2000
+ if !payment. is_retryable ( ) {
2001
+ return Err ( APIError :: RouteError {
2002
+ err : "Payment already completed"
2003
+ } ) ;
2004
+ }
1967
2005
1968
2006
let err: Result < ( ) , _ > = loop {
1969
2007
let mut channel_lock = self . channel_state . lock ( ) . unwrap ( ) ;
@@ -2177,7 +2215,12 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2177
2215
return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
2178
2216
err : "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102" . to_string ( )
2179
2217
} ) )
2180
- }
2218
+ } ,
2219
+ PendingOutboundPayment :: Completed { .. } => {
2220
+ return Err ( PaymentSendFailure :: ParameterError ( APIError :: RouteError {
2221
+ err : "Payment already completed"
2222
+ } ) ) ;
2223
+ } ,
2181
2224
}
2182
2225
} else {
2183
2226
return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
@@ -3005,7 +3048,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3005
3048
session_priv_bytes. copy_from_slice ( & session_priv[ ..] ) ;
3006
3049
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
3007
3050
if let hash_map:: Entry :: Occupied ( mut payment) = outbounds. entry ( payment_id) {
3008
- if payment. get_mut ( ) . remove ( & session_priv_bytes, path. last ( ) . unwrap ( ) . fee_msat ) {
3051
+ if payment. get_mut ( ) . remove ( & session_priv_bytes, path. last ( ) . unwrap ( ) . fee_msat ) &&
3052
+ !payment. get ( ) . is_completed ( )
3053
+ {
3009
3054
self . pending_events . lock ( ) . unwrap ( ) . push (
3010
3055
events:: Event :: PaymentPathFailed {
3011
3056
payment_hash,
@@ -3054,6 +3099,10 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3054
3099
log_trace ! ( self . logger, "Received duplicative fail for HTLC with payment_hash {}" , log_bytes!( payment_hash. 0 ) ) ;
3055
3100
return ;
3056
3101
}
3102
+ if sessions. get ( ) . is_completed ( ) {
3103
+ log_trace ! ( self . logger, "Received failure of HTLC with payment_hash {} after payment completion" , log_bytes!( payment_hash. 0 ) ) ;
3104
+ return ;
3105
+ }
3057
3106
if sessions. get ( ) . remaining_parts ( ) == 0 {
3058
3107
all_paths_failed = true ;
3059
3108
}
@@ -3300,15 +3349,45 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3300
3349
} else { unreachable ! ( ) ; }
3301
3350
}
3302
3351
3352
+ fn finalize_claims ( & self , mut sources : Vec < HTLCSource > ) {
3353
+ for source in sources. drain ( ..) {
3354
+ if let HTLCSource :: OutboundRoute { session_priv, payment_id, .. } = source {
3355
+ let mut session_priv_bytes = [ 0 ; 32 ] ;
3356
+ session_priv_bytes. copy_from_slice ( & session_priv[ ..] ) ;
3357
+ let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
3358
+ if let hash_map:: Entry :: Occupied ( mut sessions) = outbounds. entry ( payment_id) {
3359
+ assert ! ( sessions. get( ) . is_completed( ) ) ;
3360
+ sessions. get_mut ( ) . remove ( & session_priv_bytes, 0 ) ; // Note that the amount is no longer tracked
3361
+ if sessions. get ( ) . remaining_parts ( ) == 0 {
3362
+ sessions. remove ( ) ;
3363
+ }
3364
+ }
3365
+ }
3366
+ }
3367
+ }
3303
3368
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 ) {
3304
3369
match source {
3305
3370
HTLCSource :: OutboundRoute { session_priv, payment_id, path, .. } => {
3306
3371
mem:: drop ( channel_state_lock) ;
3307
3372
let mut session_priv_bytes = [ 0 ; 32 ] ;
3308
3373
session_priv_bytes. copy_from_slice ( & session_priv[ ..] ) ;
3309
3374
let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
3310
- let found_payment = if let Some ( mut sessions) = outbounds. remove ( & payment_id) {
3311
- sessions. remove ( & session_priv_bytes, path. last ( ) . unwrap ( ) . fee_msat )
3375
+ let found_payment = if let hash_map:: Entry :: Occupied ( mut sessions) = outbounds. entry ( payment_id) {
3376
+ let found_payment = !sessions. get ( ) . is_completed ( ) ;
3377
+ sessions. get_mut ( ) . mark_completed ( ) ;
3378
+ if from_onchain {
3379
+ // We currently immediately remove HTLCs which were fulfilled on-chain.
3380
+ // This could potentially lead to removing a pending payment too early,
3381
+ // with a reorg of one block causing us to re-add the completed payment on
3382
+ // restart.
3383
+ // TODO: We should have a second monitor event that informs us of payments
3384
+ // irrevocably completing.
3385
+ sessions. get_mut ( ) . remove ( & session_priv_bytes, path. last ( ) . unwrap ( ) . fee_msat ) ;
3386
+ if sessions. get ( ) . remaining_parts ( ) == 0 {
3387
+ sessions. remove ( ) ;
3388
+ }
3389
+ }
3390
+ found_payment
3312
3391
} else { false } ;
3313
3392
if found_payment {
3314
3393
self . pending_events . lock ( ) . unwrap ( ) . push (
@@ -3949,6 +4028,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3949
4028
} ) ;
3950
4029
}
3951
4030
break Ok ( ( raa_updates. to_forward_htlcs , raa_updates. failed_htlcs ,
4031
+ raa_updates. finalized_claim_htlcs ,
3952
4032
chan. get ( ) . get_short_channel_id ( )
3953
4033
. expect ( "RAA should only work on a short-id-available channel" ) ,
3954
4034
chan. get ( ) . get_funding_txo ( ) . unwrap ( ) ) )
@@ -3958,11 +4038,14 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
3958
4038
} ;
3959
4039
self . fail_holding_cell_htlcs ( htlcs_to_fail, msg. channel_id ) ;
3960
4040
match res {
3961
- Ok ( ( pending_forwards, mut pending_failures, short_channel_id, channel_outpoint) ) => {
4041
+ Ok ( ( pending_forwards, mut pending_failures, finalized_claim_htlcs,
4042
+ short_channel_id, channel_outpoint) ) =>
4043
+ {
3962
4044
for failure in pending_failures. drain ( ..) {
3963
4045
self . fail_htlc_backwards_internal ( self . channel_state . lock ( ) . unwrap ( ) , failure. 0 , & failure. 1 , failure. 2 ) ;
3964
4046
}
3965
4047
self . forward_htlcs ( & mut [ ( short_channel_id, channel_outpoint, pending_forwards) ] ) ;
4048
+ self . finalize_claims ( finalized_claim_htlcs) ;
3966
4049
Ok ( ( ) )
3967
4050
} ,
3968
4051
Err ( e) => Err ( e)
@@ -5308,10 +5391,13 @@ impl_writeable_tlv_based!(PendingInboundPayment, {
5308
5391
( 8 , min_value_msat, required) ,
5309
5392
} ) ;
5310
5393
5311
- impl_writeable_tlv_based_enum ! ( PendingOutboundPayment ,
5394
+ impl_writeable_tlv_based_enum_upgradable ! ( PendingOutboundPayment ,
5312
5395
( 0 , Legacy ) => {
5313
5396
( 0 , session_privs, required) ,
5314
5397
} ,
5398
+ ( 1 , Completed ) => {
5399
+ ( 0 , session_privs, required) ,
5400
+ } ,
5315
5401
( 2 , Retryable ) => {
5316
5402
( 0 , session_privs, required) ,
5317
5403
( 2 , payment_hash, required) ,
@@ -5320,7 +5406,7 @@ impl_writeable_tlv_based_enum!(PendingOutboundPayment,
5320
5406
( 8 , pending_amt_msat, required) ,
5321
5407
( 10 , starting_block_height, required) ,
5322
5408
} ,
5323
- ; ) ;
5409
+ ) ;
5324
5410
5325
5411
impl < Signer : Sign , M : Deref , T : Deref , K : Deref , F : Deref , L : Deref > Writeable for ChannelManager < Signer , M , T , K , F , L >
5326
5412
where M :: Target : chain:: Watch < Signer > ,
@@ -5413,7 +5499,9 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
5413
5499
// For backwards compat, write the session privs and their total length.
5414
5500
let mut num_pending_outbounds_compat: u64 = 0 ;
5415
5501
for ( _, outbound) in pending_outbound_payments. iter ( ) {
5416
- num_pending_outbounds_compat += outbound. remaining_parts ( ) as u64 ;
5502
+ if !outbound. is_completed ( ) {
5503
+ num_pending_outbounds_compat += outbound. remaining_parts ( ) as u64 ;
5504
+ }
5417
5505
}
5418
5506
num_pending_outbounds_compat. write ( writer) ?;
5419
5507
for ( _, outbound) in pending_outbound_payments. iter ( ) {
@@ -5424,6 +5512,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
5424
5512
session_priv. write ( writer) ?;
5425
5513
}
5426
5514
}
5515
+ PendingOutboundPayment :: Completed { .. } => { } ,
5427
5516
}
5428
5517
}
5429
5518
@@ -5434,7 +5523,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
5434
5523
PendingOutboundPayment :: Legacy { session_privs } |
5435
5524
PendingOutboundPayment :: Retryable { session_privs, .. } => {
5436
5525
pending_outbound_payments_no_retry. insert ( * id, session_privs. clone ( ) ) ;
5437
- }
5526
+ } ,
5527
+ _ => { } ,
5438
5528
}
5439
5529
}
5440
5530
write_tlv_fields ! ( writer, {
0 commit comments