Skip to content

Commit 30b9d9f

Browse files
authored
Merge pull request #2008 from valentinewallace/2023-02-remove-manual-retries
Abandon payments on behalf of the user and remove manual retries
2 parents 5e9e68a + da34ada commit 30b9d9f

11 files changed

+316
-362
lines changed

fuzz/src/chanmon_consistency.rs

+1
Original file line numberDiff line numberDiff line change
@@ -914,6 +914,7 @@ pub fn do_test<Out: Output>(data: &[u8], underlying_out: Out) {
914914
events::Event::PaymentClaimed { .. } => {},
915915
events::Event::PaymentPathSuccessful { .. } => {},
916916
events::Event::PaymentPathFailed { .. } => {},
917+
events::Event::PaymentFailed { .. } => {},
917918
events::Event::ProbeSuccessful { .. } | events::Event::ProbeFailed { .. } => {
918919
// Even though we don't explicitly send probes, because probes are
919920
// detected based on hashing the payment hash+preimage, its rather

lightning/src/ln/chanmon_update_fail_tests.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -1752,12 +1752,18 @@ fn test_monitor_update_on_pending_forwards() {
17521752
commitment_signed_dance!(nodes[0], nodes[1], bs_updates.commitment_signed, false, true);
17531753

17541754
let events = nodes[0].node.get_and_clear_pending_events();
1755-
assert_eq!(events.len(), 2);
1755+
assert_eq!(events.len(), 3);
17561756
if let Event::PaymentPathFailed { payment_hash, payment_failed_permanently, .. } = events[0] {
17571757
assert_eq!(payment_hash, payment_hash_1);
17581758
assert!(payment_failed_permanently);
17591759
} else { panic!("Unexpected event!"); }
17601760
match events[1] {
1761+
Event::PaymentFailed { payment_hash, .. } => {
1762+
assert_eq!(payment_hash, payment_hash_1);
1763+
},
1764+
_ => panic!("Unexpected event"),
1765+
}
1766+
match events[2] {
17611767
Event::PendingHTLCsForwardable { .. } => { },
17621768
_ => panic!("Unexpected event"),
17631769
};

lightning/src/ln/channelmanager.rs

+16-37
Original file line numberDiff line numberDiff line change
@@ -1190,9 +1190,9 @@ pub enum RecentPaymentDetails {
11901190
/// made before LDK version 0.0.104.
11911191
payment_hash: Option<PaymentHash>,
11921192
},
1193-
/// After a payment is explicitly abandoned by calling [`ChannelManager::abandon_payment`], it
1194-
/// is marked as abandoned until an [`Event::PaymentFailed`] is generated. A payment could also
1195-
/// be marked as abandoned if pathfinding fails repeatedly or retries have been exhausted.
1193+
/// After a payment's retries are exhausted per the provided [`Retry`], or it is explicitly
1194+
/// abandoned via [`ChannelManager::abandon_payment`], it is marked as abandoned until all
1195+
/// pending HTLCs for this payment resolve and an [`Event::PaymentFailed`] is generated.
11961196
Abandoned {
11971197
/// Hash of the payment that we have given up trying to send.
11981198
payment_hash: PaymentHash,
@@ -1718,7 +1718,7 @@ where
17181718
///
17191719
/// This can be useful for payments that may have been prepared, but ultimately not sent, as a
17201720
/// result of a crash. If such a payment exists, is not listed here, and an
1721-
/// [`Event::PaymentSent`] has not been received, you may consider retrying the payment.
1721+
/// [`Event::PaymentSent`] has not been received, you may consider resending the payment.
17221722
///
17231723
/// [`Event::PaymentSent`]: events::Event::PaymentSent
17241724
pub fn list_recent_payments(&self) -> Vec<RecentPaymentDetails> {
@@ -2475,8 +2475,8 @@ where
24752475
/// If a pending payment is currently in-flight with the same [`PaymentId`] provided, this
24762476
/// method will error with an [`APIError::InvalidRoute`]. Note, however, that once a payment
24772477
/// is no longer pending (either via [`ChannelManager::abandon_payment`], or handling of an
2478-
/// [`Event::PaymentSent`]) LDK will not stop you from sending a second payment with the same
2479-
/// [`PaymentId`].
2478+
/// [`Event::PaymentSent`] or [`Event::PaymentFailed`]) LDK will not stop you from sending a
2479+
/// second payment with the same [`PaymentId`].
24802480
///
24812481
/// Thus, in order to ensure duplicate payments are not sent, you should implement your own
24822482
/// tracking of payments, including state to indicate once a payment has completed. Because you
@@ -2521,6 +2521,7 @@ where
25212521
/// [`Route`], we assume the invoice had the basic_mpp feature set.
25222522
///
25232523
/// [`Event::PaymentSent`]: events::Event::PaymentSent
2524+
/// [`Event::PaymentFailed`]: events::Event::PaymentFailed
25242525
/// [`PeerManager::process_events`]: crate::ln::peer_handler::PeerManager::process_events
25252526
/// [`ChannelMonitorUpdateStatus::InProgress`]: crate::chain::ChannelMonitorUpdateStatus::InProgress
25262527
pub fn send_payment(&self, route: &Route, payment_hash: PaymentHash, payment_secret: &Option<PaymentSecret>, payment_id: PaymentId) -> Result<(), PaymentSendFailure> {
@@ -2558,48 +2559,25 @@ where
25582559
}
25592560

25602561

2561-
/// Retries a payment along the given [`Route`].
2562+
/// Signals that no further retries for the given payment should occur. Useful if you have a
2563+
/// pending outbound payment with retries remaining, but wish to stop retrying the payment before
2564+
/// retries are exhausted.
25622565
///
2563-
/// Errors returned are a superset of those returned from [`send_payment`], so see
2564-
/// [`send_payment`] documentation for more details on errors. This method will also error if the
2565-
/// retry amount puts the payment more than 10% over the payment's total amount, if the payment
2566-
/// for the given `payment_id` cannot be found (likely due to timeout or success), or if
2567-
/// further retries have been disabled with [`abandon_payment`].
2568-
///
2569-
/// [`send_payment`]: [`ChannelManager::send_payment`]
2570-
/// [`abandon_payment`]: [`ChannelManager::abandon_payment`]
2571-
pub fn retry_payment(&self, route: &Route, payment_id: PaymentId) -> Result<(), PaymentSendFailure> {
2572-
let best_block_height = self.best_block.read().unwrap().height();
2573-
self.pending_outbound_payments.retry_payment_with_route(route, payment_id, &self.entropy_source, &self.node_signer, best_block_height,
2574-
|path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv|
2575-
self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv))
2576-
}
2577-
2578-
/// Signals that no further retries for the given payment will occur.
2579-
///
2580-
/// After this method returns, no future calls to [`retry_payment`] for the given `payment_id`
2581-
/// are allowed. If no [`Event::PaymentFailed`] event had been generated before, one will be
2582-
/// generated as soon as there are no remaining pending HTLCs for this payment.
2566+
/// If no [`Event::PaymentFailed`] event had been generated before, one will be generated as soon
2567+
/// as there are no remaining pending HTLCs for this payment.
25832568
///
25842569
/// Note that calling this method does *not* prevent a payment from succeeding. You must still
25852570
/// wait until you receive either a [`Event::PaymentFailed`] or [`Event::PaymentSent`] event to
25862571
/// determine the ultimate status of a payment.
25872572
///
25882573
/// If an [`Event::PaymentFailed`] event is generated and we restart without this
2589-
/// [`ChannelManager`] having been persisted, the payment may still be in the pending state
2590-
/// upon restart. This allows further calls to [`retry_payment`] (and requiring a second call
2591-
/// to [`abandon_payment`] to mark the payment as failed again). Otherwise, future calls to
2592-
/// [`retry_payment`] will fail with [`PaymentSendFailure::ParameterError`].
2574+
/// [`ChannelManager`] having been persisted, another [`Event::PaymentFailed`] may be generated.
25932575
///
2594-
/// [`abandon_payment`]: Self::abandon_payment
2595-
/// [`retry_payment`]: Self::retry_payment
25962576
/// [`Event::PaymentFailed`]: events::Event::PaymentFailed
25972577
/// [`Event::PaymentSent`]: events::Event::PaymentSent
25982578
pub fn abandon_payment(&self, payment_id: PaymentId) {
25992579
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(&self.total_consistency_lock, &self.persistence_notifier);
2600-
if let Some(payment_failed_ev) = self.pending_outbound_payments.abandon_payment(payment_id) {
2601-
self.pending_events.lock().unwrap().push(payment_failed_ev);
2602-
}
2580+
self.pending_outbound_payments.abandon_payment(payment_id, &self.pending_events);
26032581
}
26042582

26052583
/// Send a spontaneous payment, which is a payment that does not require the recipient to have
@@ -3372,7 +3350,8 @@ where
33723350

33733351
let best_block_height = self.best_block.read().unwrap().height();
33743352
self.pending_outbound_payments.check_retry_payments(&self.router, || self.list_usable_channels(),
3375-
|| self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer, best_block_height, &self.logger,
3353+
|| self.compute_inflight_htlcs(), &self.entropy_source, &self.node_signer, best_block_height,
3354+
&self.pending_events, &self.logger,
33763355
|path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv|
33773356
self.send_payment_along_path(path, payment_params, payment_hash, payment_secret, total_value, cur_height, payment_id, keysend_preimage, session_priv));
33783357

lightning/src/ln/functional_test_utils.rs

+22-35
Original file line numberDiff line numberDiff line change
@@ -1800,17 +1800,18 @@ macro_rules! expect_payment_failed {
18001800
}
18011801

18021802
pub fn expect_payment_failed_conditions_event<'a, 'b, 'c, 'd, 'e>(
1803-
node: &'a Node<'b, 'c, 'd>, payment_failed_event: Event, expected_payment_hash: PaymentHash,
1803+
payment_failed_events: Vec<Event>, expected_payment_hash: PaymentHash,
18041804
expected_payment_failed_permanently: bool, conditions: PaymentFailedConditions<'e>
18051805
) {
1806-
let expected_payment_id = match payment_failed_event {
1806+
if conditions.expected_mpp_parts_remain { assert_eq!(payment_failed_events.len(), 1); } else { assert_eq!(payment_failed_events.len(), 2); }
1807+
let expected_payment_id = match &payment_failed_events[0] {
18071808
Event::PaymentPathFailed { payment_hash, payment_failed_permanently, path, retry, payment_id, network_update, short_channel_id,
18081809
#[cfg(test)]
18091810
error_code,
18101811
#[cfg(test)]
18111812
error_data, .. } => {
1812-
assert_eq!(payment_hash, expected_payment_hash, "unexpected payment_hash");
1813-
assert_eq!(payment_failed_permanently, expected_payment_failed_permanently, "unexpected payment_failed_permanently value");
1813+
assert_eq!(*payment_hash, expected_payment_hash, "unexpected payment_hash");
1814+
assert_eq!(*payment_failed_permanently, expected_payment_failed_permanently, "unexpected payment_failed_permanently value");
18141815
assert!(retry.is_some(), "expected retry.is_some()");
18151816
assert_eq!(retry.as_ref().unwrap().final_value_msat, path.last().unwrap().fee_msat, "Retry amount should match last hop in path");
18161817
assert_eq!(retry.as_ref().unwrap().payment_params.payee_pubkey, path.last().unwrap().pubkey, "Retry payee node_id should match last hop in path");
@@ -1839,7 +1840,7 @@ pub fn expect_payment_failed_conditions_event<'a, 'b, 'c, 'd, 'e>(
18391840
},
18401841
Some(NetworkUpdate::ChannelFailure { short_channel_id, is_permanent }) if chan_closed => {
18411842
if let Some(scid) = conditions.expected_blamed_scid {
1842-
assert_eq!(short_channel_id, scid);
1843+
assert_eq!(*short_channel_id, scid);
18431844
}
18441845
assert!(is_permanent);
18451846
},
@@ -1853,10 +1854,7 @@ pub fn expect_payment_failed_conditions_event<'a, 'b, 'c, 'd, 'e>(
18531854
_ => panic!("Unexpected event"),
18541855
};
18551856
if !conditions.expected_mpp_parts_remain {
1856-
node.node.abandon_payment(expected_payment_id);
1857-
let events = node.node.get_and_clear_pending_events();
1858-
assert_eq!(events.len(), 1);
1859-
match events[0] {
1857+
match &payment_failed_events[1] {
18601858
Event::PaymentFailed { ref payment_hash, ref payment_id } => {
18611859
assert_eq!(*payment_hash, expected_payment_hash, "unexpected second payment_hash");
18621860
assert_eq!(*payment_id, expected_payment_id);
@@ -1870,9 +1868,8 @@ pub fn expect_payment_failed_conditions<'a, 'b, 'c, 'd, 'e>(
18701868
node: &'a Node<'b, 'c, 'd>, expected_payment_hash: PaymentHash, expected_payment_failed_permanently: bool,
18711869
conditions: PaymentFailedConditions<'e>
18721870
) {
1873-
let mut events = node.node.get_and_clear_pending_events();
1874-
assert_eq!(events.len(), 1);
1875-
expect_payment_failed_conditions_event(node, events.pop().unwrap(), expected_payment_hash, expected_payment_failed_permanently, conditions);
1871+
let events = node.node.get_and_clear_pending_events();
1872+
expect_payment_failed_conditions_event(events, expected_payment_hash, expected_payment_failed_permanently, conditions);
18761873
}
18771874

18781875
pub fn send_along_route_with_secret<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, route: Route, expected_paths: &[&[&Node<'a, 'b, 'c>]], recv_value: u64, our_payment_hash: PaymentHash, our_payment_secret: PaymentSecret) -> PaymentId {
@@ -2157,22 +2154,6 @@ pub fn fail_payment_along_route<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expe
21572154
}
21582155

21592156
pub fn pass_failed_payment_back<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_paths_slice: &[&[&Node<'a, 'b, 'c>]], skip_last: bool, our_payment_hash: PaymentHash) {
2160-
let expected_payment_id = pass_failed_payment_back_no_abandon(origin_node, expected_paths_slice, skip_last, our_payment_hash);
2161-
if !skip_last {
2162-
origin_node.node.abandon_payment(expected_payment_id.unwrap());
2163-
let events = origin_node.node.get_and_clear_pending_events();
2164-
assert_eq!(events.len(), 1);
2165-
match events[0] {
2166-
Event::PaymentFailed { ref payment_hash, ref payment_id } => {
2167-
assert_eq!(*payment_hash, our_payment_hash, "unexpected second payment_hash");
2168-
assert_eq!(*payment_id, expected_payment_id.unwrap());
2169-
}
2170-
_ => panic!("Unexpected second event"),
2171-
}
2172-
}
2173-
}
2174-
2175-
pub fn pass_failed_payment_back_no_abandon<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_paths_slice: &[&[&Node<'a, 'b, 'c>]], skip_last: bool, our_payment_hash: PaymentHash) -> Option<PaymentId> {
21762157
let mut expected_paths: Vec<_> = expected_paths_slice.iter().collect();
21772158
check_added_monitors!(expected_paths[0].last().unwrap(), expected_paths.len());
21782159

@@ -2196,8 +2177,6 @@ pub fn pass_failed_payment_back_no_abandon<'a, 'b, 'c>(origin_node: &Node<'a, 'b
21962177
per_path_msgs.sort_unstable_by(|(_, node_id_a), (_, node_id_b)| node_id_a.cmp(node_id_b));
21972178
expected_paths.sort_unstable_by(|path_a, path_b| path_a[path_a.len() - 2].node.get_our_node_id().cmp(&path_b[path_b.len() - 2].node.get_our_node_id()));
21982179

2199-
let mut expected_payment_id = None;
2200-
22012180
for (i, (expected_route, (path_msgs, next_hop))) in expected_paths.iter().zip(per_path_msgs.drain(..)).enumerate() {
22022181
let mut next_msgs = Some(path_msgs);
22032182
let mut expected_next_node = next_hop;
@@ -2245,8 +2224,9 @@ pub fn pass_failed_payment_back_no_abandon<'a, 'b, 'c>(origin_node: &Node<'a, 'b
22452224
assert!(origin_node.node.get_and_clear_pending_msg_events().is_empty());
22462225
commitment_signed_dance!(origin_node, prev_node, next_msgs.as_ref().unwrap().1, false);
22472226
let events = origin_node.node.get_and_clear_pending_events();
2248-
assert_eq!(events.len(), 1);
2249-
expected_payment_id = Some(match events[0] {
2227+
if i == expected_paths.len() - 1 { assert_eq!(events.len(), 2); } else { assert_eq!(events.len(), 1); }
2228+
2229+
let expected_payment_id = match events[0] {
22502230
Event::PaymentPathFailed { payment_hash, payment_failed_permanently, all_paths_failed, ref path, ref payment_id, .. } => {
22512231
assert_eq!(payment_hash, our_payment_hash);
22522232
assert!(payment_failed_permanently);
@@ -2257,7 +2237,16 @@ pub fn pass_failed_payment_back_no_abandon<'a, 'b, 'c>(origin_node: &Node<'a, 'b
22572237
payment_id.unwrap()
22582238
},
22592239
_ => panic!("Unexpected event"),
2260-
});
2240+
};
2241+
if i == expected_paths.len() - 1 {
2242+
match events[1] {
2243+
Event::PaymentFailed { ref payment_hash, ref payment_id } => {
2244+
assert_eq!(*payment_hash, our_payment_hash, "unexpected second payment_hash");
2245+
assert_eq!(*payment_id, expected_payment_id);
2246+
}
2247+
_ => panic!("Unexpected second event"),
2248+
}
2249+
}
22612250
}
22622251
}
22632252

@@ -2266,8 +2255,6 @@ pub fn pass_failed_payment_back_no_abandon<'a, 'b, 'c>(origin_node: &Node<'a, 'b
22662255
assert!(expected_paths[0].last().unwrap().node.get_and_clear_pending_events().is_empty());
22672256
assert!(expected_paths[0].last().unwrap().node.get_and_clear_pending_msg_events().is_empty());
22682257
check_added_monitors!(expected_paths[0].last().unwrap(), 0);
2269-
2270-
expected_payment_id
22712258
}
22722259

22732260
pub fn fail_payment<'a, 'b, 'c>(origin_node: &Node<'a, 'b, 'c>, expected_path: &[&Node<'a, 'b, 'c>], our_payment_hash: PaymentHash) {

0 commit comments

Comments
 (0)