Skip to content

Commit 044793a

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 37c40b2 commit 044793a

File tree

2 files changed

+18
-5
lines changed

2 files changed

+18
-5
lines changed

lightning/src/ln/channelmanager.rs

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

391391
/// For events which result in both a RevokeAndACK and a CommitmentUpdate, by default they should
392392
/// 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 & 4 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::{KeysInterface, 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;
@@ -783,7 +784,8 @@ impl OutboundPayments {
783784
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
784785
let mut all_paths_failed = false;
785786
let mut full_failure_ev = None;
786-
if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(*payment_id) {
787+
let mut pending_retry_ev = None;
788+
let attempts_remaining = if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(*payment_id) {
787789
if !payment.get_mut().remove(&session_priv_bytes, Some(&path)) {
788790
log_trace!(logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
789791
return (None, None);
@@ -792,6 +794,7 @@ impl OutboundPayments {
792794
log_trace!(logger, "Received failure of HTLC with payment_hash {} after payment completion", log_bytes!(payment_hash.0));
793795
return (None, None);
794796
}
797+
let is_retryable = payment.get().is_retryable();
795798
if payment.get().remaining_parts() == 0 {
796799
all_paths_failed = true;
797800
if payment.get().abandoned() {
@@ -802,10 +805,11 @@ impl OutboundPayments {
802805
payment.remove();
803806
}
804807
}
808+
is_retryable
805809
} else {
806810
log_trace!(logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
807811
return (None, None);
808-
}
812+
};
809813
let mut retry = if let Some(payment_params_data) = payment_params {
810814
let path_last_hop = path.last().expect("Outbound payments must have had a valid path");
811815
Some(RouteParameters {
@@ -844,6 +848,15 @@ impl OutboundPayments {
844848
if let Some(scid) = short_channel_id {
845849
retry.as_mut().map(|r| r.payment_params.previously_failed_channels.push(scid));
846850
}
851+
if payment_retryable && attempts_remaining {
852+
if let Some(retry_params) = &retry {
853+
debug_assert!(full_failure_ev.is_none());
854+
pending_retry_ev = Some(events::Event::PendingHTLCsForwardable {
855+
time_forwardable: Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS),
856+
});
857+
self.retryable_htlcs.lock().unwrap().push((*payment_id, retry_params.clone()));
858+
}
859+
}
847860
events::Event::PaymentPathFailed {
848861
payment_id: Some(*payment_id),
849862
payment_hash: payment_hash.clone(),
@@ -860,7 +873,7 @@ impl OutboundPayments {
860873
}
861874
}
862875
};
863-
(Some(path_failure), full_failure_ev)
876+
(Some(path_failure), full_failure_ev.or(pending_retry_ev))
864877
}
865878

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

0 commit comments

Comments
 (0)