@@ -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
@@ -418,6 +428,104 @@ impl OutboundPayments {
418
428
}
419
429
}
420
430
431
+ pub ( super ) fn check_retry_payments < R : Deref , ES : Deref , NS : Deref , SP , IH , FH , L : Deref > (
432
+ & self , router : & R , first_hops : FH , inflight_htlcs : IH , entropy_source : & ES , node_signer : & NS ,
433
+ best_block_height : u32 , logger : & L , send_payment_along_path : SP ,
434
+ )
435
+ where
436
+ R :: Target : Router ,
437
+ ES :: Target : EntropySource ,
438
+ NS :: Target : NodeSigner ,
439
+ SP : Fn ( & Vec < RouteHop > , & Option < PaymentParameters > , & PaymentHash , & Option < PaymentSecret > , u64 ,
440
+ u32 , PaymentId , & Option < PaymentPreimage > , [ u8 ; 32 ] ) -> Result < ( ) , APIError > ,
441
+ IH : Fn ( ) -> InFlightHtlcs ,
442
+ FH : Fn ( ) -> Vec < ChannelDetails > ,
443
+ L :: Target : Logger ,
444
+ {
445
+ loop {
446
+ let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
447
+ let mut retry_id_route_params = None ;
448
+ for ( pmt_id, pmt) in outbounds. iter_mut ( ) {
449
+ if pmt. is_retryable ( ) {
450
+ if let PendingOutboundPayment :: Retryable { pending_amt_msat, total_msat, route_params : Some ( params) , .. } = pmt {
451
+ if pending_amt_msat < total_msat {
452
+ retry_id_route_params = Some ( ( * pmt_id, params. clone ( ) ) ) ;
453
+ }
454
+ }
455
+ }
456
+ if retry_id_route_params. is_some ( ) { pmt. increment_attempts ( ) ; break }
457
+ }
458
+ if let Some ( ( payment_id, route_params) ) = retry_id_route_params {
459
+ core:: mem:: drop ( outbounds) ;
460
+ 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) {
461
+ log_trace ! ( logger, "Errored retrying payment: {:?}" , e) ;
462
+ }
463
+ } else { break }
464
+ }
465
+ }
466
+
467
+ fn pay_internal < R : Deref , NS : Deref , ES : Deref , F > (
468
+ & self , payment_id : PaymentId , route_params : RouteParameters , router : & R ,
469
+ first_hops : Vec < ChannelDetails > , inflight_htlcs : InFlightHtlcs , entropy_source : & ES ,
470
+ node_signer : & NS , best_block_height : u32 , send_payment_along_path : & F
471
+ ) -> Result < ( ) , PaymentSendFailure >
472
+ where
473
+ R :: Target : Router ,
474
+ ES :: Target : EntropySource ,
475
+ NS :: Target : NodeSigner ,
476
+ F : Fn ( & Vec < RouteHop > , & Option < PaymentParameters > , & PaymentHash , & Option < PaymentSecret > , u64 ,
477
+ u32 , PaymentId , & Option < PaymentPreimage > , [ u8 ; 32 ] ) -> Result < ( ) , APIError >
478
+ {
479
+ #[ cfg( feature = "std" ) ] {
480
+ if has_expired ( & route_params) {
481
+ return Err ( PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
482
+ err : format ! ( "Invoice expired for payment id {}" , log_bytes!( payment_id. 0 ) ) ,
483
+ } ) )
484
+ }
485
+ }
486
+
487
+ let route = router. find_route (
488
+ & node_signer. get_node_id ( Recipient :: Node ) . unwrap ( ) , & route_params,
489
+ Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , & inflight_htlcs
490
+ ) . map_err ( |e| PaymentSendFailure :: ParameterError ( APIError :: APIMisuseError {
491
+ err : format ! ( "Failed to find a route for payment {}: {:?}" , log_bytes!( payment_id. 0 ) , e) , // TODO: add APIError::RouteNotFound
492
+ } ) ) ?;
493
+
494
+ let res = self . retry_payment_with_route ( & route, payment_id, entropy_source, node_signer, best_block_height, send_payment_along_path) ;
495
+ match res {
496
+ Err ( PaymentSendFailure :: AllFailedResendSafe ( _) ) | Err ( PaymentSendFailure :: PartialFailure { .. } ) => {
497
+ let mut outbounds = self . pending_outbound_payments . lock ( ) . unwrap ( ) ;
498
+ if let Some ( payment) = outbounds. get_mut ( & payment_id) {
499
+ let retryable = payment. is_retryable ( ) ;
500
+ if retryable {
501
+ payment. increment_attempts ( ) ;
502
+ } else { return res }
503
+ } else { return res }
504
+ }
505
+ res => return res
506
+ }
507
+ match res {
508
+ Err ( PaymentSendFailure :: AllFailedResendSafe ( _) ) => {
509
+ self . pay_internal ( payment_id, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path)
510
+ } ,
511
+ Err ( PaymentSendFailure :: PartialFailure { failed_paths_retry, .. } ) => {
512
+ if let Some ( retry) = failed_paths_retry {
513
+ // Some paths were sent, even if we failed to send the full MPP value our recipient may
514
+ // misbehave and claim the funds, at which point we have to consider the payment sent, so
515
+ // return `Ok()` here, ignoring any retry errors.
516
+ let _ = self . pay_internal ( payment_id, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path) ;
517
+ Ok ( ( ) )
518
+ } else {
519
+ // This may happen if we send a payment and some paths fail, but only due to a temporary
520
+ // monitor failure or the like, implying they're really in-flight, but we haven't sent the
521
+ // initial HTLC-Add messages yet.
522
+ Ok ( ( ) )
523
+ }
524
+ } ,
525
+ res => res,
526
+ }
527
+ }
528
+
421
529
pub ( super ) fn retry_payment_with_route < ES : Deref , NS : Deref , F > (
422
530
& self , route : & Route , payment_id : PaymentId , entropy_source : & ES , node_signer : & NS , best_block_height : u32 ,
423
531
send_payment_along_path : F
0 commit comments