@@ -15,10 +15,10 @@ use bitcoin::secp256k1::{self, Secp256k1, SecretKey};
15
15
16
16
use crate :: chain:: keysinterface:: { EntropySource , NodeSigner , Recipient } ;
17
17
use crate :: ln:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
18
- use crate :: ln:: channelmanager:: { HTLCSource , IDEMPOTENCY_TIMEOUT_TICKS , MIN_HTLC_RELAY_HOLDING_CELL_MILLIS , PaymentId } ;
18
+ use crate :: ln:: channelmanager:: { ChannelDetails , HTLCSource , IDEMPOTENCY_TIMEOUT_TICKS , MIN_HTLC_RELAY_HOLDING_CELL_MILLIS , PaymentId } ;
19
19
use crate :: ln:: msgs:: DecodeError ;
20
20
use crate :: ln:: onion_utils:: HTLCFailReason ;
21
- use crate :: routing:: router:: { PaymentParameters , Route , RouteHop , RouteParameters , RoutePath } ;
21
+ use crate :: routing:: router:: { InFlightHtlcs , PaymentParameters , Route , RouteHop , RouteParameters , RoutePath , Router } ;
22
22
use crate :: util:: errors:: APIError ;
23
23
use crate :: util:: events;
24
24
use crate :: util:: logger:: Logger ;
@@ -237,6 +237,16 @@ impl Retry {
237
237
}
238
238
}
239
239
240
+ #[ cfg( feature = "std" ) ]
241
+ pub ( super ) fn has_expired ( route_params : & RouteParameters ) -> bool {
242
+ if let Some ( expiry_time) = route_params. payment_params . expiry_time {
243
+ if let Ok ( elapsed) = std:: time:: SystemTime :: UNIX_EPOCH . elapsed ( ) {
244
+ return elapsed > core:: time:: Duration :: from_secs ( expiry_time)
245
+ }
246
+ }
247
+ false
248
+ }
249
+
240
250
pub ( crate ) type PaymentAttempts = PaymentAttemptsUsingTime < ConfiguredTime > ;
241
251
242
252
/// Storing minimal payment attempts information required for determining if a outbound payment can
@@ -411,6 +421,104 @@ impl OutboundPayments {
411
421
}
412
422
}
413
423
424
+ pub ( super ) fn check_retry_payments < R : Deref , ES : Deref , NS : Deref , SP , IH , FH , L : Deref > (
425
+ & self , router : & R , first_hops : FH , inflight_htlcs : IH , entropy_source : & ES , node_signer : & NS ,
426
+ best_block_height : u32 , logger : & L , send_payment_along_path : SP ,
427
+ )
428
+ where
429
+ R :: Target : Router ,
430
+ ES :: Target : EntropySource ,
431
+ NS :: Target : NodeSigner ,
432
+ SP : Fn ( & Vec < RouteHop > , & Option < PaymentParameters > , & PaymentHash , & Option < PaymentSecret > , u64 ,
433
+ u32 , PaymentId , & Option < PaymentPreimage > , [ u8 ; 32 ] ) -> Result < ( ) , APIError > ,
434
+ IH : Fn ( ) -> InFlightHtlcs ,
435
+ FH : Fn ( ) -> Vec < ChannelDetails > ,
436
+ L :: Target : Logger ,
437
+ {
438
+ loop {
439
+ let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
440
+ let mut retry_id_route_params = None ;
441
+ for ( pmt_id, pmt) in outbounds. iter_mut ( ) {
442
+ if pmt. is_retryable_now ( ) {
443
+ if let PendingOutboundPayment :: Retryable { pending_amt_msat, total_msat, route_params : Some ( params) , .. } = pmt {
444
+ if pending_amt_msat < total_msat {
445
+ retry_id_route_params = Some ( ( * pmt_id, params. clone ( ) ) ) ;
446
+ }
447
+ }
448
+ }
449
+ if retry_id_route_params. is_some ( ) { pmt. increment_attempts ( ) ; break }
450
+ }
451
+ if let Some ( ( payment_id, route_params) ) = retry_id_route_params {
452
+ core:: mem:: drop ( outbounds) ;
453
+ if let Err ( e) = self . pay_internal ( payment_id, route_params, router, first_hops ( ) , inflight_htlcs ( ) , entropy_source, node_signer, best_block_height, & send_payment_along_path) {
454
+ log_trace ! ( logger, "Errored retrying payment: {:?}" , e) ;
455
+ }
456
+ } else { break }
457
+ }
458
+ }
459
+
460
+ fn pay_internal < R : Deref , NS : Deref , ES : Deref , F > (
461
+ & self , payment_id : PaymentId , route_params : RouteParameters , router : & R ,
462
+ first_hops : Vec < ChannelDetails > , inflight_htlcs : InFlightHtlcs , entropy_source : & ES ,
463
+ node_signer : & NS , best_block_height : u32 , send_payment_along_path : & F
464
+ ) -> Result < ( ) , PaymentSendFailure >
465
+ where
466
+ R :: Target : Router ,
467
+ ES :: Target : EntropySource ,
468
+ NS :: Target : NodeSigner ,
469
+ F : Fn ( & Vec < RouteHop > , & Option < PaymentParameters > , & PaymentHash , & Option < PaymentSecret > , u64 ,
470
+ u32 , PaymentId , & Option < PaymentPreimage > , [ u8 ; 32 ] ) -> Result < ( ) , APIError >
471
+ {
472
+ #[ cfg( feature = "std" ) ] {
473
+ if has_expired ( & route_params) {
474
+ return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
475
+ err : format ! ( "Invoice expired for payment id {}" , log_bytes!( payment_id. 0 ) ) ,
476
+ } ) )
477
+ }
478
+ }
479
+
480
+ let route = router. find_route (
481
+ & node_signer. get_node_id ( Recipient :: Node ) . unwrap ( ) , & route_params,
482
+ Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , & inflight_htlcs
483
+ ) . map_err ( |e| PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
484
+ err : format ! ( "Failed to find a route for payment {}: {:?}" , log_bytes!( payment_id. 0 ) , e) , // TODO: add APIError::RouteNotFound
485
+ } ) ) ?;
486
+
487
+ let res = self . retry_payment_with_route ( & route, payment_id, entropy_source, node_signer, best_block_height, send_payment_along_path) ;
488
+ match res {
489
+ Err ( PaymentSendFailure :: AllFailedResendSafe ( _) ) | Err ( PaymentSendFailure :: PartialFailure { .. } ) => {
490
+ let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
491
+ if let Some ( payment) = outbounds. get_mut ( & payment_id) {
492
+ let retryable = payment. is_retryable_now ( ) ;
493
+ if retryable {
494
+ payment. increment_attempts ( ) ;
495
+ } else { return res }
496
+ } else { return res }
497
+ }
498
+ res => return res
499
+ }
500
+ match res {
501
+ Err ( PaymentSendFailure :: AllFailedResendSafe ( _) ) => {
502
+ self . pay_internal ( payment_id, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path)
503
+ } ,
504
+ Err ( PaymentSendFailure :: PartialFailure { failed_paths_retry, .. } ) => {
505
+ if let Some ( retry) = failed_paths_retry {
506
+ // Some paths were sent, even if we failed to send the full MPP value our recipient may
507
+ // misbehave and claim the funds, at which point we have to consider the payment sent, so
508
+ // return `Ok()` here, ignoring any retry errors.
509
+ let _ = self . pay_internal ( payment_id, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path) ;
510
+ Ok ( ( ) )
511
+ } else {
512
+ // This may happen if we send a payment and some paths fail, but only due to a temporary
513
+ // monitor failure or the like, implying they're really in-flight, but we haven't sent the
514
+ // initial HTLC-Add messages yet.
515
+ Ok ( ( ) )
516
+ }
517
+ } ,
518
+ res => res,
519
+ }
520
+ }
521
+
414
522
pub ( super ) fn retry_payment_with_route < ES : Deref , NS : Deref , F > (
415
523
& self , route : & Route , payment_id : PaymentId , entropy_source : & ES , node_signer : & NS , best_block_height : u32 ,
416
524
send_payment_along_path : F
0 commit comments