Skip to content

Commit dbbe8fe

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 efa348e commit dbbe8fe

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
@@ -388,7 +388,7 @@ impl MsgHandleErrInternal {
388388
/// Event::PendingHTLCsForwardable for the API guidelines indicating how long should be waited).
389389
/// This provides some limited amount of privacy. Ideally this would range from somewhere like one
390390
/// second to 30 seconds, but people expect lightning to be, you know, kinda fast, sadly.
391-
const MIN_HTLC_RELAY_HOLDING_CELL_MILLIS: u64 = 100;
391+
pub(super) const MIN_HTLC_RELAY_HOLDING_CELL_MILLIS: u64 = 100;
392392

393393
/// For events which result in both a RevokeAndACK and a CommitmentUpdate, by default they should
394394
/// 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;
@@ -785,7 +786,8 @@ impl OutboundPayments {
785786
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
786787
let mut all_paths_failed = false;
787788
let mut full_failure_ev = None;
788-
if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(*payment_id) {
789+
let mut pending_retry_ev = None;
790+
let attempts_remaining = if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(*payment_id) {
789791
if !payment.get_mut().remove(&session_priv_bytes, Some(&path)) {
790792
log_trace!(logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
791793
return
@@ -794,6 +796,7 @@ impl OutboundPayments {
794796
log_trace!(logger, "Received failure of HTLC with payment_hash {} after payment completion", log_bytes!(payment_hash.0));
795797
return
796798
}
799+
let is_retryable = payment.get().is_retryable();
797800
if payment.get().remaining_parts() == 0 {
798801
all_paths_failed = true;
799802
if payment.get().abandoned() {
@@ -804,10 +807,11 @@ impl OutboundPayments {
804807
payment.remove();
805808
}
806809
}
810+
is_retryable
807811
} else {
808812
log_trace!(logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
809813
return
810-
}
814+
};
811815
let mut retry = if let Some(payment_params_data) = payment_params {
812816
let path_last_hop = path.last().expect("Outbound payments must have had a valid path");
813817
Some(RouteParameters {
@@ -846,6 +850,15 @@ impl OutboundPayments {
846850
if let Some(scid) = short_channel_id {
847851
retry.as_mut().map(|r| r.payment_params.previously_failed_channels.push(scid));
848852
}
853+
if payment_retryable && attempts_remaining {
854+
if let Some(retry_params) = &retry {
855+
debug_assert!(full_failure_ev.is_none());
856+
pending_retry_ev = Some(events::Event::PendingHTLCsForwardable {
857+
time_forwardable: Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS),
858+
});
859+
self.retryable_htlcs.lock().unwrap().push((*payment_id, retry_params.clone()));
860+
}
861+
}
849862
events::Event::PaymentPathFailed {
850863
payment_id: Some(*payment_id),
851864
payment_hash: payment_hash.clone(),
@@ -865,6 +878,7 @@ impl OutboundPayments {
865878
let mut pending_events = pending_events.lock().unwrap();
866879
pending_events.push(path_failure);
867880
if let Some(ev) = full_failure_ev { pending_events.push(ev); }
881+
if let Some(ev) = pending_retry_ev { pending_events.push(ev); }
868882
}
869883

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

0 commit comments

Comments
 (0)