Skip to content

Commit dcd98a7

Browse files
On initial send retries, avoid previously failed scids
Previously, we could have tried the same failed channels over and over until retries are exhausted.
1 parent 24ef02c commit dcd98a7

File tree

2 files changed

+25
-17
lines changed

2 files changed

+25
-17
lines changed

lightning/src/ln/outbound_payment.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -732,8 +732,8 @@ impl OutboundPayments {
732732

733733
fn handle_pay_route_err<R: Deref, NS: Deref, ES: Deref, IH, SP, L: Deref>(
734734
&self, err: PaymentSendFailure, payment_id: PaymentId, payment_hash: PaymentHash, route: Route,
735-
route_params: RouteParameters, router: &R, first_hops: Vec<ChannelDetails>, inflight_htlcs: &IH,
736-
entropy_source: &ES, node_signer: &NS, best_block_height: u32, logger: &L,
735+
mut route_params: RouteParameters, router: &R, first_hops: Vec<ChannelDetails>,
736+
inflight_htlcs: &IH, entropy_source: &ES, node_signer: &NS, best_block_height: u32, logger: &L,
737737
pending_events: &Mutex<Vec<events::Event>>, send_payment_along_path: &SP,
738738
)
739739
where
@@ -747,11 +747,11 @@ impl OutboundPayments {
747747
{
748748
match err {
749749
PaymentSendFailure::AllFailedResendSafe(errs) => {
750-
Self::push_payment_path_failed_evs(payment_id, payment_hash, route.paths, errs.into_iter().map(|e| Err(e)), pending_events);
750+
Self::push_path_failed_evs_and_scids(payment_id, payment_hash, &mut route_params, route.paths, errs.into_iter().map(|e| Err(e)), pending_events);
751751
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);
752752
},
753-
PaymentSendFailure::PartialFailure { failed_paths_retry: Some(retry), results, .. } => {
754-
Self::push_payment_path_failed_evs(payment_id, payment_hash, route.paths, results.into_iter(), pending_events);
753+
PaymentSendFailure::PartialFailure { failed_paths_retry: Some(mut retry), results, .. } => {
754+
Self::push_path_failed_evs_and_scids(payment_id, payment_hash, &mut retry, route.paths, results.into_iter(), pending_events);
755755
// Some paths were sent, even if we failed to send the full MPP value our recipient may
756756
// misbehave and claim the funds, at which point we have to consider the payment sent, so
757757
// return `Ok()` here, ignoring any retry errors.
@@ -763,7 +763,7 @@ impl OutboundPayments {
763763
// initial HTLC-Add messages yet.
764764
},
765765
PaymentSendFailure::PathParameterError(results) => {
766-
Self::push_payment_path_failed_evs(payment_id, payment_hash, route.paths, results.into_iter(), pending_events);
766+
Self::push_path_failed_evs_and_scids(payment_id, payment_hash, &mut route_params, route.paths, results.into_iter(), pending_events);
767767
self.abandon_payment(payment_id, pending_events);
768768
},
769769
PaymentSendFailure::ParameterError(e) => {
@@ -774,9 +774,9 @@ impl OutboundPayments {
774774
}
775775
}
776776

777-
fn push_payment_path_failed_evs<I: ExactSizeIterator + Iterator<Item = Result<(), APIError>>>(
778-
payment_id: PaymentId, payment_hash: PaymentHash, paths: Vec<Vec<RouteHop>>, path_results: I,
779-
pending_events: &Mutex<Vec<events::Event>>
777+
fn push_path_failed_evs_and_scids<I: ExactSizeIterator + Iterator<Item = Result<(), APIError>>>(
778+
payment_id: PaymentId, payment_hash: PaymentHash, route_params: &mut RouteParameters,
779+
paths: Vec<Vec<RouteHop>>, path_results: I, pending_events: &Mutex<Vec<events::Event>>
780780
) {
781781
let mut events = pending_events.lock().unwrap();
782782
debug_assert_eq!(paths.len(), path_results.len());
@@ -785,7 +785,9 @@ impl OutboundPayments {
785785
let failed_scid = if let APIError::InvalidRoute { .. } = e {
786786
None
787787
} else {
788-
Some(path[0].short_channel_id)
788+
let scid = path[0].short_channel_id;
789+
route_params.payment_params.previously_failed_channels.push(scid);
790+
Some(scid)
789791
};
790792
events.push(events::Event::PaymentPathFailed {
791793
payment_id: Some(payment_id),

lightning/src/ln/payment_tests.rs

+13-7
Original file line numberDiff line numberDiff line change
@@ -1857,13 +1857,15 @@ fn auto_retry_partial_failure() {
18571857
payment_params: Some(route_params.payment_params.clone()),
18581858
};
18591859
nodes[0].router.expect_find_route(route_params.clone(), Ok(send_route));
1860+
let mut payment_params = route_params.payment_params.clone();
1861+
payment_params.previously_failed_channels.push(chan_2_id);
18601862
nodes[0].router.expect_find_route(RouteParameters {
1861-
payment_params: route_params.payment_params.clone(),
1862-
final_value_msat: amt_msat / 2, final_cltv_expiry_delta: TEST_FINAL_CLTV
1863+
payment_params, final_value_msat: amt_msat / 2, final_cltv_expiry_delta: TEST_FINAL_CLTV
18631864
}, Ok(retry_1_route));
1865+
let mut payment_params = route_params.payment_params.clone();
1866+
payment_params.previously_failed_channels.push(chan_3_id);
18641867
nodes[0].router.expect_find_route(RouteParameters {
1865-
payment_params: route_params.payment_params.clone(),
1866-
final_value_msat: amt_msat / 4, final_cltv_expiry_delta: TEST_FINAL_CLTV
1868+
payment_params, final_value_msat: amt_msat / 4, final_cltv_expiry_delta: TEST_FINAL_CLTV
18671869
}, Ok(retry_2_route));
18681870

18691871
// Send a payment that will partially fail on send, then partially fail on retry, then succeed.
@@ -2113,8 +2115,10 @@ fn retry_multi_path_single_failed_payment() {
21132115
// On retry, split the payment across both channels.
21142116
route.paths[0][0].fee_msat = 50_000_001;
21152117
route.paths[1][0].fee_msat = 50_000_000;
2118+
let mut pay_params = route.payment_params.clone().unwrap();
2119+
pay_params.previously_failed_channels.push(chans[1].short_channel_id.unwrap());
21162120
nodes[0].router.expect_find_route(RouteParameters {
2117-
payment_params: route.payment_params.clone().unwrap(),
2121+
payment_params: pay_params,
21182122
// Note that the second request here requests the amount we originally failed to send,
21192123
// not the amount remaining on the full payment, which should be changed.
21202124
final_value_msat: 100_000_001, final_cltv_expiry_delta: TEST_FINAL_CLTV
@@ -2196,9 +2200,11 @@ fn immediate_retry_on_failure() {
21962200
route.paths[0][0].short_channel_id = chans[1].short_channel_id.unwrap();
21972201
route.paths[0][0].fee_msat = 50_000_000;
21982202
route.paths[1][0].fee_msat = 50_000_001;
2203+
let mut pay_params = route_params.payment_params.clone();
2204+
pay_params.previously_failed_channels.push(chans[0].short_channel_id.unwrap());
21992205
nodes[0].router.expect_find_route(RouteParameters {
2200-
payment_params: route_params.payment_params.clone(),
2201-
final_value_msat: amt_msat, final_cltv_expiry_delta: TEST_FINAL_CLTV
2206+
payment_params: pay_params, final_value_msat: amt_msat,
2207+
final_cltv_expiry_delta: TEST_FINAL_CLTV
22022208
}, Ok(route.clone()));
22032209

22042210
nodes[0].node.send_payment_with_retry(payment_hash, &Some(payment_secret), PaymentId(payment_hash.0), route_params, Retry::Attempts(1)).unwrap();

0 commit comments

Comments
 (0)