Skip to content

Commit 6343bac

Browse files
Support sending payments with a retry strategy in ChannelManager
1 parent 5c07ed1 commit 6343bac

File tree

2 files changed

+52
-14
lines changed

2 files changed

+52
-14
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, No
4545
#[cfg(any(feature = "_test_utils", test))]
4646
use crate::ln::features::InvoiceFeatures;
4747
use crate::routing::gossip::NetworkGraph;
48-
use crate::routing::router::{DefaultRouter, InFlightHtlcs, PaymentParameters, Route, RouteHop, RoutePath, Router};
48+
use crate::routing::router::{DefaultRouter, InFlightHtlcs, PaymentParameters, Route, RouteHop, RouteParameters, RoutePath, Router};
4949
use crate::routing::scoring::ProbabilisticScorer;
5050
use crate::ln::msgs;
5151
use crate::ln::onion_utils;
@@ -2446,6 +2446,18 @@ where
24462446
self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv))
24472447
}
24482448

2449+
/// Similar to [`ChannelManager::send_payment`], but will automatically find a route based on
2450+
/// `route_params` and retry failed payment paths based on `retry_strategy`.
2451+
pub fn send_payment_with_retry(&self, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, payment_id: PaymentId, route_params: RouteParameters, retry_strategy: Retry) -> Result<(), PaymentSendFailure> {
2452+
let best_block_height = self.best_block.read().unwrap().height();
2453+
self.pending_outbound_payments
2454+
.send_payment(payment_hash, payment_secret, payment_id, retry_strategy, route_params,
2455+
&self.router, self.list_usable_channels(), self.compute_inflight_htlcs(),
2456+
&self.entropy_source, &self.node_signer, best_block_height,
2457+
|path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv|
2458+
self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv))
2459+
}
2460+
24492461
#[cfg(test)]
24502462
fn test_send_payment_internal(&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, keysend_preimage: Option<PaymentPreimage>, payment_id: PaymentId, recv_value_msat: Option<u64>, onion_session_privs: Vec<[u8; 32]>) -> Result<(), PaymentSendFailure> {
24512463
let best_block_height = self.best_block.read().unwrap().height();

lightning/src/ln/outbound_payment.rs

Lines changed: 39 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,25 @@ impl OutboundPayments {
378378
}
379379
}
380380

381+
pub(super) fn send_payment<R: Deref, ES: Deref, NS: Deref, F>(
382+
&self, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, payment_id: PaymentId,
383+
retry_strategy: Retry, route_params: RouteParameters, router: &R,
384+
first_hops: Vec<ChannelDetails>, inflight_htlcs: InFlightHtlcs, entropy_source: &ES,
385+
node_signer: &NS, best_block_height: u32, send_payment_along_path: F
386+
) -> Result<(), PaymentSendFailure>
387+
where
388+
R::Target: Router,
389+
ES::Target: EntropySource,
390+
NS::Target: NodeSigner,
391+
F: Fn(&Vec<RouteHop>, &Option<PaymentParameters>, &PaymentHash, &Option<PaymentSecret>, u64,
392+
u32, PaymentId, &Option<PaymentPreimage>, [u8; 32]) -> Result<(), APIError>,
393+
{
394+
self.pay_internal(payment_id, Some((payment_hash, payment_secret, retry_strategy)),
395+
route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer,
396+
best_block_height, &send_payment_along_path)
397+
.map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e })
398+
}
399+
381400
pub(super) fn send_payment_with_route<ES: Deref, NS: Deref, F>(
382401
&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>,
383402
payment_id: PaymentId, entropy_source: &ES, node_signer: &NS, best_block_height: u32,
@@ -391,7 +410,7 @@ impl OutboundPayments {
391410
{
392411
let onion_session_privs = self.add_new_pending_payment(payment_hash, *payment_secret, payment_id, route, Retry::Attempts(0), None, entropy_source, best_block_height)?;
393412
self.send_payment_internal(route, payment_hash, payment_secret, None, payment_id, None,
394-
onion_session_privs, node_signer, best_block_height, send_payment_along_path)
413+
onion_session_privs, node_signer, best_block_height, &send_payment_along_path)
395414
.map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e })
396415
}
397416

@@ -412,7 +431,7 @@ impl OutboundPayments {
412431
let payment_hash = PaymentHash(Sha256::hash(&preimage.0).into_inner());
413432
let onion_session_privs = self.add_new_pending_payment(payment_hash, None, payment_id, &route, Retry::Attempts(0), None, entropy_source, best_block_height)?;
414433

415-
match self.send_payment_internal(route, payment_hash, &None, Some(preimage), payment_id, None, onion_session_privs, node_signer, best_block_height, send_payment_along_path) {
434+
match self.send_payment_internal(route, payment_hash, &None, Some(preimage), payment_id, None, onion_session_privs, node_signer, best_block_height, &send_payment_along_path) {
416435
Ok(()) => Ok(payment_hash),
417436
Err(e) => {
418437
self.remove_outbound_if_all_failed(payment_id, &e);
@@ -450,17 +469,19 @@ impl OutboundPayments {
450469
}
451470
if let Some((payment_id, route_params)) = retry_id_route_params {
452471
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) {
472+
if let Err(e) = self.pay_internal(payment_id, None, route_params, router, first_hops(), inflight_htlcs(), entropy_source, node_signer, best_block_height, &send_payment_along_path) {
454473
log_trace!(logger, "Errored retrying payment: {:?}", e);
455474
}
456475
} else { break }
457476
}
458477
}
459478

460479
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
480+
&self, payment_id: PaymentId,
481+
initial_send_info: Option<(PaymentHash, &Option<PaymentSecret>, Retry)>,
482+
route_params: RouteParameters, router: &R, first_hops: Vec<ChannelDetails>,
483+
inflight_htlcs: InFlightHtlcs, entropy_source: &ES, node_signer: &NS, best_block_height: u32,
484+
send_payment_along_path: &F
464485
) -> Result<(), PaymentSendFailure>
465486
where
466487
R::Target: Router,
@@ -484,7 +505,12 @@ impl OutboundPayments {
484505
err: format!("Failed to find a route for payment {}: {:?}", log_bytes!(payment_id.0), e), // TODO: add APIError::RouteNotFound
485506
}))?;
486507

487-
let res = self.retry_payment_with_route(&route, payment_id, entropy_source, node_signer, best_block_height, send_payment_along_path);
508+
let res = if let Some((payment_hash, payment_secret, retry_strategy)) = initial_send_info {
509+
let onion_session_privs = self.add_new_pending_payment(payment_hash, *payment_secret, payment_id, &route, retry_strategy, Some(route_params.clone()), entropy_source, best_block_height)?;
510+
self.send_payment_internal(&route, payment_hash, payment_secret, None, payment_id, None, onion_session_privs, node_signer, best_block_height, send_payment_along_path)
511+
} else {
512+
self.retry_payment_with_route(&route, payment_id, entropy_source, node_signer, best_block_height, send_payment_along_path)
513+
};
488514
match res {
489515
Err(PaymentSendFailure::AllFailedResendSafe(_)) => {
490516
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
@@ -495,7 +521,7 @@ impl OutboundPayments {
495521
} else { return res }
496522
} else { return res }
497523
core::mem::drop(outbounds);
498-
self.pay_internal(payment_id, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path)
524+
self.pay_internal(payment_id, None, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path)
499525
},
500526
Err(PaymentSendFailure::PartialFailure { failed_paths_retry: Some(retry), results, .. }) => {
501527
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
@@ -510,7 +536,7 @@ impl OutboundPayments {
510536
// Some paths were sent, even if we failed to send the full MPP value our recipient may
511537
// misbehave and claim the funds, at which point we have to consider the payment sent, so
512538
// return `Ok()` here, ignoring any retry errors.
513-
let _ = self.pay_internal(payment_id, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path);
539+
let _ = self.pay_internal(payment_id, None, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path);
514540
Ok(())
515541
},
516542
Err(PaymentSendFailure::PartialFailure { failed_paths_retry: None, .. }) => {
@@ -590,7 +616,7 @@ impl OutboundPayments {
590616
})),
591617
}
592618
};
593-
self.send_payment_internal(route, payment_hash, &payment_secret, None, payment_id, Some(total_msat), onion_session_privs, node_signer, best_block_height, send_payment_along_path)
619+
self.send_payment_internal(route, payment_hash, &payment_secret, None, payment_id, Some(total_msat), onion_session_privs, node_signer, best_block_height, &send_payment_along_path)
594620
}
595621

596622
pub(super) fn send_probe<ES: Deref, NS: Deref, F>(
@@ -616,7 +642,7 @@ impl OutboundPayments {
616642
let route = Route { paths: vec![hops], payment_params: None };
617643
let onion_session_privs = self.add_new_pending_payment(payment_hash, None, payment_id, &route, Retry::Attempts(0), None, entropy_source, best_block_height)?;
618644

619-
match self.send_payment_internal(&route, payment_hash, &None, None, payment_id, None, onion_session_privs, node_signer, best_block_height, send_payment_along_path) {
645+
match self.send_payment_internal(&route, payment_hash, &None, None, payment_id, None, onion_session_privs, node_signer, best_block_height, &send_payment_along_path) {
620646
Ok(()) => Ok((payment_hash, payment_id)),
621647
Err(e) => {
622648
self.remove_outbound_if_all_failed(payment_id, &e);
@@ -673,7 +699,7 @@ impl OutboundPayments {
673699
&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>,
674700
keysend_preimage: Option<PaymentPreimage>, payment_id: PaymentId, recv_value_msat: Option<u64>,
675701
onion_session_privs: Vec<[u8; 32]>, node_signer: &NS, best_block_height: u32,
676-
send_payment_along_path: F
702+
send_payment_along_path: &F
677703
) -> Result<(), PaymentSendFailure>
678704
where
679705
NS::Target: NodeSigner,
@@ -788,7 +814,7 @@ impl OutboundPayments {
788814
{
789815
self.send_payment_internal(route, payment_hash, payment_secret, keysend_preimage, payment_id,
790816
recv_value_msat, onion_session_privs, node_signer, best_block_height,
791-
send_payment_along_path)
817+
&send_payment_along_path)
792818
.map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e })
793819
}
794820

0 commit comments

Comments
 (0)