Skip to content

Commit b826d17

Browse files
In-line retry_with_route method
Since it's only used one place now
1 parent d471d97 commit b826d17

File tree

1 file changed

+88
-92
lines changed

1 file changed

+88
-92
lines changed

lightning/src/ln/outbound_payment.rs

Lines changed: 88 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -527,9 +527,9 @@ impl OutboundPayments {
527527
let mut retry_id_route_params = None;
528528
for (pmt_id, pmt) in outbounds.iter_mut() {
529529
if pmt.is_auto_retryable_now() {
530-
if let PendingOutboundPayment::Retryable { payment_hash, pending_amt_msat, total_msat, payment_params: Some(params), .. } = pmt {
530+
if let PendingOutboundPayment::Retryable { pending_amt_msat, total_msat, payment_params: Some(params), .. } = pmt {
531531
if pending_amt_msat < total_msat {
532-
retry_id_route_params = Some((*pmt_id, *payment_hash, RouteParameters {
532+
retry_id_route_params = Some((*pmt_id, RouteParameters {
533533
final_value_msat: *total_msat - *pending_amt_msat,
534534
final_cltv_expiry_delta:
535535
if let Some(delta) = params.final_cltv_expiry_delta { delta }
@@ -545,8 +545,8 @@ impl OutboundPayments {
545545
}
546546
}
547547
core::mem::drop(outbounds);
548-
if let Some((payment_id, payment_hash, route_params)) = retry_id_route_params {
549-
self.retry_payment_internal(payment_id, payment_hash, route_params, router, first_hops(), &inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, &send_payment_along_path)
548+
if let Some((payment_id, route_params)) = retry_id_route_params {
549+
self.retry_payment_internal(payment_id, route_params, router, first_hops(), &inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, &send_payment_along_path)
550550
} else { break }
551551
}
552552

@@ -619,10 +619,10 @@ impl OutboundPayments {
619619
}
620620

621621
fn retry_payment_internal<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
622-
&self, payment_id: PaymentId, payment_hash: PaymentHash, route_params: RouteParameters,
623-
router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: &IH, entropy_source: &ES,
624-
node_signer: &NS, best_block_height: u32, logger: &L,
625-
pending_events: &Mutex<Vec<events::Event>>, send_payment_along_path: &SP,
622+
&self, payment_id: PaymentId, route_params: RouteParameters, router: &R,
623+
first_hops: Vec<ChannelDetails>, inflight_htlcs: &IH, entropy_source: &ES, node_signer: &NS,
624+
best_block_height: u32, logger: &L, pending_events: &Mutex<Vec<events::Event>>,
625+
send_payment_along_path: &SP,
626626
)
627627
where
628628
R::Target: Router,
@@ -652,9 +652,81 @@ impl OutboundPayments {
652652
return
653653
}
654654
};
655+
for path in route.paths.iter() {
656+
if path.len() == 0 {
657+
log_error!(logger, "length-0 path in route");
658+
self.abandon_payment(payment_id, pending_events);
659+
return
660+
}
661+
}
655662

656-
let res = self.retry_payment_with_route(&route, payment_id, entropy_source, node_signer,
657-
best_block_height, send_payment_along_path);
663+
const RETRY_OVERFLOW_PERCENTAGE: u64 = 10;
664+
let mut onion_session_privs = Vec::with_capacity(route.paths.len());
665+
for _ in 0..route.paths.len() {
666+
onion_session_privs.push(entropy_source.get_secure_random_bytes());
667+
}
668+
669+
macro_rules! abandon_with_entry {
670+
($payment_id: expr, $payment_hash: expr, $payment: expr, $pending_events: expr) => {
671+
if $payment.get_mut().mark_abandoned().is_ok() && $payment.get().remaining_parts() == 0 {
672+
$pending_events.lock().unwrap().push(events::Event::PaymentFailed {
673+
payment_id: $payment_id,
674+
payment_hash: $payment_hash,
675+
});
676+
$payment.remove();
677+
}
678+
}
679+
}
680+
let (total_msat, payment_hash, payment_secret, keysend_preimage) = {
681+
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
682+
match outbounds.entry(payment_id) {
683+
hash_map::Entry::Occupied(mut payment) => {
684+
let res = match payment.get() {
685+
PendingOutboundPayment::Retryable {
686+
total_msat, payment_hash, keysend_preimage, payment_secret, pending_amt_msat, ..
687+
} => {
688+
let retry_amt_msat: u64 = route.paths.iter().map(|path| path.last().unwrap().fee_msat).sum();
689+
if retry_amt_msat + *pending_amt_msat > *total_msat * (100 + RETRY_OVERFLOW_PERCENTAGE) / 100 {
690+
log_error!(logger, "retry_amt_msat of {} will put pending_amt_msat (currently: {}) more than 10% over total_payment_amt_msat of {}", retry_amt_msat, pending_amt_msat, total_msat);
691+
let payment_hash = *payment_hash;
692+
abandon_with_entry!(payment_id, payment_hash, payment, pending_events);
693+
return
694+
}
695+
(*total_msat, *payment_hash, *payment_secret, *keysend_preimage)
696+
},
697+
PendingOutboundPayment::Legacy { .. } => {
698+
log_error!(logger, "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102");
699+
return
700+
},
701+
PendingOutboundPayment::Fulfilled { .. } => {
702+
log_error!(logger, "Payment already completed");
703+
return
704+
},
705+
PendingOutboundPayment::Abandoned { .. } => {
706+
log_error!(logger, "Payment already abandoned (with some HTLCs still pending)");
707+
return
708+
},
709+
};
710+
if !payment.get().is_retryable_now() {
711+
log_error!(logger, "Retries exhausted for payment id {}", log_bytes!(payment_id.0));
712+
abandon_with_entry!(payment_id, res.1, payment, pending_events);
713+
return
714+
}
715+
payment.get_mut().increment_attempts();
716+
for (path, session_priv_bytes) in route.paths.iter().zip(onion_session_privs.iter()) {
717+
assert!(payment.get_mut().insert(*session_priv_bytes, path));
718+
}
719+
res
720+
},
721+
hash_map::Entry::Vacant(_) => {
722+
log_error!(logger, "Payment with ID {} not found", log_bytes!(payment_id.0));
723+
return
724+
}
725+
}
726+
};
727+
let res = self.pay_route_internal(&route, payment_hash, &payment_secret, keysend_preimage,
728+
payment_id, Some(total_msat), onion_session_privs, node_signer, best_block_height,
729+
&send_payment_along_path);
658730
log_info!(logger, "Result retrying payment id {}: {:?}", log_bytes!(payment_id.0), res);
659731
if let Err(e) = res {
660732
self.handle_pay_route_err(e, payment_id, payment_hash, route, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
@@ -679,14 +751,14 @@ impl OutboundPayments {
679751
match err {
680752
PaymentSendFailure::AllFailedResendSafe(errs) => {
681753
Self::push_payment_path_failed_evs(payment_id, payment_hash, route.paths, errs.into_iter().map(|e| Err(e)), pending_events);
682-
self.retry_payment_internal(payment_id, payment_hash, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
754+
self.retry_payment_internal(payment_id, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
683755
},
684756
PaymentSendFailure::PartialFailure { failed_paths_retry: Some(retry), results, .. } => {
685757
Self::push_payment_path_failed_evs(payment_id, payment_hash, route.paths, results.into_iter(), pending_events);
686758
// Some paths were sent, even if we failed to send the full MPP value our recipient may
687759
// misbehave and claim the funds, at which point we have to consider the payment sent, so
688760
// return `Ok()` here, ignoring any retry errors.
689-
self.retry_payment_internal(payment_id, payment_hash, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
761+
self.retry_payment_internal(payment_id, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, logger, pending_events, send_payment_along_path);
690762
},
691763
PaymentSendFailure::PartialFailure { failed_paths_retry: None, .. } => {
692764
// This may happen if we send a payment and some paths fail, but only due to a temporary
@@ -736,82 +808,6 @@ impl OutboundPayments {
736808
}
737809
}
738810

739-
pub(super) fn retry_payment_with_route<ES: Deref, NS: Deref, F>(
740-
&self, route: &Route, payment_id: PaymentId, entropy_source: &ES, node_signer: &NS, best_block_height: u32,
741-
send_payment_along_path: F
742-
) -> Result<(), PaymentSendFailure>
743-
where
744-
ES::Target: EntropySource,
745-
NS::Target: NodeSigner,
746-
F: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
747-
u32, PaymentId, &Option<PaymentPreimage>, [u8; 32]) -> Result<(), APIError>
748-
{
749-
const RETRY_OVERFLOW_PERCENTAGE: u64 = 10;
750-
for path in route.paths.iter() {
751-
if path.len() == 0 {
752-
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
753-
err: "length-0 path in route".to_string()
754-
}))
755-
}
756-
}
757-
758-
let mut onion_session_privs = Vec::with_capacity(route.paths.len());
759-
for _ in 0..route.paths.len() {
760-
onion_session_privs.push(entropy_source.get_secure_random_bytes());
761-
}
762-
763-
let (total_msat, payment_hash, payment_secret, keysend_preimage) = {
764-
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
765-
match outbounds.get_mut(&payment_id) {
766-
Some(payment) => {
767-
let res = match payment {
768-
PendingOutboundPayment::Retryable {
769-
total_msat, payment_hash, keysend_preimage, payment_secret, pending_amt_msat, ..
770-
} => {
771-
let retry_amt_msat: u64 = route.paths.iter().map(|path| path.last().unwrap().fee_msat).sum();
772-
if retry_amt_msat + *pending_amt_msat > *total_msat * (100 + RETRY_OVERFLOW_PERCENTAGE) / 100 {
773-
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
774-
err: format!("retry_amt_msat of {} will put pending_amt_msat (currently: {}) more than 10% over total_payment_amt_msat of {}", retry_amt_msat, pending_amt_msat, total_msat).to_string()
775-
}))
776-
}
777-
(*total_msat, *payment_hash, *payment_secret, *keysend_preimage)
778-
},
779-
PendingOutboundPayment::Legacy { .. } => {
780-
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
781-
err: "Unable to retry payments that were initially sent on LDK versions prior to 0.0.102".to_string()
782-
}))
783-
},
784-
PendingOutboundPayment::Fulfilled { .. } => {
785-
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
786-
err: "Payment already completed".to_owned()
787-
}));
788-
},
789-
PendingOutboundPayment::Abandoned { .. } => {
790-
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
791-
err: "Payment already abandoned (with some HTLCs still pending)".to_owned()
792-
}));
793-
},
794-
};
795-
if !payment.is_retryable_now() {
796-
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
797-
err: format!("Retries exhausted for payment id {}", log_bytes!(payment_id.0)),
798-
}))
799-
}
800-
payment.increment_attempts();
801-
for (path, session_priv_bytes) in route.paths.iter().zip(onion_session_privs.iter()) {
802-
assert!(payment.insert(*session_priv_bytes, path));
803-
}
804-
res
805-
},
806-
None =>
807-
return Err(PaymentSendFailure::ParameterError(APIError::APIMisuseError {
808-
err: format!("Payment with ID {} not found", log_bytes!(payment_id.0)),
809-
})),
810-
}
811-
};
812-
self.pay_route_internal(route, payment_hash, &payment_secret, keysend_preimage, payment_id, Some(total_msat), onion_session_privs, node_signer, best_block_height, &send_payment_along_path)
813-
}
814-
815811
pub(super) fn send_probe<ES: Deref, NS: Deref, F>(
816812
&self, hops: Vec<RouteHop>, probing_cookie_secret: [u8; 32], entropy_source: &ES,
817813
node_signer: &NS, best_block_height: u32, send_payment_along_path: F
@@ -1403,8 +1399,8 @@ mod tests {
14031399
&Route { paths: vec![], payment_params: None }, Some(Retry::Attempts(1)),
14041400
Some(expired_route_params.payment_params.clone()), &&keys_manager, 0).unwrap();
14051401
outbound_payments.retry_payment_internal(
1406-
PaymentId([0; 32]), PaymentHash([0; 32]), expired_route_params, &&router, vec![],
1407-
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
1402+
PaymentId([0; 32]), expired_route_params, &&router, vec![], &|| InFlightHtlcs::new(),
1403+
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
14081404
&|_, _, _, _, _, _, _, _, _| Ok(()));
14091405
let events = pending_events.lock().unwrap();
14101406
assert_eq!(events.len(), 1);
@@ -1449,8 +1445,8 @@ mod tests {
14491445
&Route { paths: vec![], payment_params: None }, Some(Retry::Attempts(1)),
14501446
Some(route_params.payment_params.clone()), &&keys_manager, 0).unwrap();
14511447
outbound_payments.retry_payment_internal(
1452-
PaymentId([0; 32]), PaymentHash([0; 32]), route_params, &&router, vec![],
1453-
&|| InFlightHtlcs::new(), &&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
1448+
PaymentId([0; 32]), route_params, &&router, vec![], &|| InFlightHtlcs::new(),
1449+
&&keys_manager, &&keys_manager, 0, &&logger, &pending_events,
14541450
&|_, _, _, _, _, _, _, _, _| Ok(()));
14551451
let events = pending_events.lock().unwrap();
14561452
assert_eq!(events.len(), 1);

0 commit comments

Comments
 (0)