Skip to content

Commit 3b0718a

Browse files
Store HTLC pending retry data upon path failure
And generate a PendingHTLCsForwardable event, since we'll be retrying these payments in process_pending_htlcs_forwardable in the next commit(s). No retries will be stored or events generated yet since we currently always pass RetryAttempts::(0).
1 parent 077fa0a commit 3b0718a

File tree

2 files changed

+18
-4
lines changed

2 files changed

+18
-4
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -390,7 +390,7 @@ impl MsgHandleErrInternal {
390390
/// Event::PendingHTLCsForwardable for the API guidelines indicating how long should be waited).
391391
/// This provides some limited amount of privacy. Ideally this would range from somewhere like one
392392
/// second to 30 seconds, but people expect lightning to be, you know, kinda fast, sadly.
393-
const MIN_HTLC_RELAY_HOLDING_CELL_MILLIS: u64 = 100;
393+
pub(super) const MIN_HTLC_RELAY_HOLDING_CELL_MILLIS: u64 = 100;
394394

395395
/// For events which result in both a RevokeAndACK and a CommitmentUpdate, by default they should
396396
/// be sent in the order they appear in the return value, however sometimes the order needs to be

lightning/src/ln/outbound_payment.rs

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ use bitcoin::secp256k1::{self, Secp256k1, SecretKey};
1515

1616
use crate::chain::keysinterface::{EntropySource, KeysInterface, NodeSigner, Recipient};
1717
use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
18-
use crate::ln::channelmanager::{HTLCSource, IDEMPOTENCY_TIMEOUT_TICKS, PaymentId};
18+
use crate::ln::channelmanager::{HTLCSource, IDEMPOTENCY_TIMEOUT_TICKS, MIN_HTLC_RELAY_HOLDING_CELL_MILLIS, PaymentId};
1919
use crate::ln::msgs::DecodeError;
2020
use crate::ln::onion_utils::HTLCFailReason;
2121
use crate::routing::router::{PaymentParameters, Route, RouteHop, RouteParameters, RoutePath};
@@ -30,6 +30,7 @@ use core::cmp;
3030
use core::fmt::{self, Display, Formatter};
3131
use core::ops::Deref;
3232
use core::sync::atomic::{AtomicUsize, Ordering};
33+
use core::time::Duration;
3334

3435
use crate::prelude::*;
3536
use crate::sync::Mutex;
@@ -795,7 +796,8 @@ impl OutboundPayments {
795796
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
796797
let mut all_paths_failed = false;
797798
let mut full_failure_ev = None;
798-
if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(*payment_id) {
799+
let mut pending_retry_ev = None;
800+
let attempts_remaining = if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(*payment_id) {
799801
if !payment.get_mut().remove(&session_priv_bytes, Some(&path)) {
800802
log_trace!(logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
801803
return
@@ -804,6 +806,7 @@ impl OutboundPayments {
804806
log_trace!(logger, "Received failure of HTLC with payment_hash {} after payment completion", log_bytes!(payment_hash.0));
805807
return
806808
}
809+
let is_retryable = payment.get().is_retryable();
807810
if payment.get().remaining_parts() == 0 {
808811
all_paths_failed = true;
809812
if payment.get().abandoned() {
@@ -814,10 +817,11 @@ impl OutboundPayments {
814817
payment.remove();
815818
}
816819
}
820+
is_retryable
817821
} else {
818822
log_trace!(logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
819823
return
820-
}
824+
};
821825
let mut retry = if let Some(payment_params_data) = payment_params {
822826
let path_last_hop = path.last().expect("Outbound payments must have had a valid path");
823827
Some(RouteParameters {
@@ -856,6 +860,15 @@ impl OutboundPayments {
856860
if let Some(scid) = short_channel_id {
857861
retry.as_mut().map(|r| r.payment_params.previously_failed_channels.push(scid));
858862
}
863+
if payment_retryable && attempts_remaining {
864+
if let Some(retry_params) = &retry {
865+
debug_assert!(full_failure_ev.is_none());
866+
pending_retry_ev = Some(events::Event::PendingHTLCsForwardable {
867+
time_forwardable: Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS),
868+
});
869+
self.retryable_htlcs.lock().unwrap().push((*payment_id, retry_params.clone()));
870+
}
871+
}
859872
events::Event::PaymentPathFailed {
860873
payment_id: Some(*payment_id),
861874
payment_hash: payment_hash.clone(),
@@ -875,6 +888,7 @@ impl OutboundPayments {
875888
let mut pending_events = pending_events.lock().unwrap();
876889
pending_events.push(path_failure);
877890
if let Some(ev) = full_failure_ev { pending_events.push(ev); }
891+
if let Some(ev) = pending_retry_ev { pending_events.push(ev); }
878892
}
879893

880894
pub(super) fn abandon_payment(&self, payment_id: PaymentId) -> Option<events::Event> {

0 commit comments

Comments
 (0)