Skip to content

Commit acf9292

Browse files
Support sending payments with a retry strategy in ChannelManager
1 parent d776dee commit acf9292

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);
@@ -451,17 +470,19 @@ impl OutboundPayments {
451470
}
452471
if let Some((payment_id, route_params)) = retry_id_route_params {
453472
core::mem::drop(outbounds);
454-
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) {
473+
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) {
455474
log_trace!(logger, "Errored retrying payment: {:?}", e);
456475
}
457476
} else { break }
458477
}
459478
}
460479

461480
fn pay_internal<R: Deref, NS: Deref, ES: Deref, F>(
462-
&self, payment_id: PaymentId, route_params: RouteParameters, router: &R,
463-
first_hops: Vec<ChannelDetails>, inflight_htlcs: InFlightHtlcs, entropy_source: &ES,
464-
node_signer: &NS, best_block_height: u32, send_payment_along_path: &F
481+
&self, payment_id: PaymentId,
482+
initial_send_info: Option<(PaymentHash, &Option<PaymentSecret>, Retry)>,
483+
route_params: RouteParameters, router: &R, first_hops: Vec<ChannelDetails>,
484+
inflight_htlcs: InFlightHtlcs, entropy_source: &ES, node_signer: &NS, best_block_height: u32,
485+
send_payment_along_path: &F
465486
) -> Result<(), PaymentSendFailure>
466487
where
467488
R::Target: Router,
@@ -485,7 +506,12 @@ impl OutboundPayments {
485506
err: format!("Failed to find a route for payment {}: {:?}", log_bytes!(payment_id.0), e), // TODO: add APIError::RouteNotFound
486507
}))?;
487508

488-
let res = self.retry_payment_with_route(&route, payment_id, entropy_source, node_signer, best_block_height, send_payment_along_path);
509+
let res = if let Some((payment_hash, payment_secret, retry_strategy)) = initial_send_info {
510+
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)?;
511+
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)
512+
} else {
513+
self.retry_payment_with_route(&route, payment_id, entropy_source, node_signer, best_block_height, send_payment_along_path)
514+
};
489515
match res {
490516
Err(PaymentSendFailure::AllFailedResendSafe(_)) => {
491517
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
@@ -496,7 +522,7 @@ impl OutboundPayments {
496522
} else { return res }
497523
} else { return res }
498524
core::mem::drop(outbounds);
499-
self.pay_internal(payment_id, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path)
525+
self.pay_internal(payment_id, None, route_params, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path)
500526
},
501527
Err(PaymentSendFailure::PartialFailure { failed_paths_retry: Some(retry), results, .. }) => {
502528
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
@@ -511,7 +537,7 @@ impl OutboundPayments {
511537
// Some paths were sent, even if we failed to send the full MPP value our recipient may
512538
// misbehave and claim the funds, at which point we have to consider the payment sent, so
513539
// return `Ok()` here, ignoring any retry errors.
514-
let _ = self.pay_internal(payment_id, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path);
540+
let _ = self.pay_internal(payment_id, None, retry, router, first_hops, inflight_htlcs, entropy_source, node_signer, best_block_height, send_payment_along_path);
515541
Ok(())
516542
},
517543
Err(PaymentSendFailure::PartialFailure { failed_paths_retry: None, .. }) => {
@@ -591,7 +617,7 @@ impl OutboundPayments {
591617
})),
592618
}
593619
};
594-
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)
620+
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)
595621
}
596622

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

620-
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) {
646+
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) {
621647
Ok(()) => Ok((payment_hash, payment_id)),
622648
Err(e) => {
623649
self.remove_outbound_if_all_failed(payment_id, &e);
@@ -674,7 +700,7 @@ impl OutboundPayments {
674700
&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>,
675701
keysend_preimage: Option<PaymentPreimage>, payment_id: PaymentId, recv_value_msat: Option<u64>,
676702
onion_session_privs: Vec<[u8; 32]>, node_signer: &NS, best_block_height: u32,
677-
send_payment_along_path: F
703+
send_payment_along_path: &F
678704
) -> Result<(), PaymentSendFailure>
679705
where
680706
NS::Target: NodeSigner,
@@ -789,7 +815,7 @@ impl OutboundPayments {
789815
{
790816
self.send_payment_internal(route, payment_hash, payment_secret, keysend_preimage, payment_id,
791817
recv_value_msat, onion_session_privs, node_signer, best_block_height,
792-
send_payment_along_path)
818+
&send_payment_along_path)
793819
.map_err(|e| { self.remove_outbound_if_all_failed(payment_id, &e); e })
794820
}
795821

0 commit comments

Comments
 (0)