Skip to content

Commit 74c8fbb

Browse files
Generate PendingHTLCsForwardable upon retryable payment
1 parent e58e972 commit 74c8fbb

File tree

2 files changed

+21
-4
lines changed

2 files changed

+21
-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: 20 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, 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};
@@ -29,6 +29,7 @@ use crate::util::time::tests::SinceEpoch;
2929
use core::cmp;
3030
use core::fmt::{self, Display, Formatter};
3131
use core::ops::Deref;
32+
use core::time::Duration;
3233

3334
use crate::prelude::*;
3435
use crate::sync::Mutex;
@@ -87,6 +88,11 @@ impl PendingOutboundPayment {
8788
}
8889
false
8990
}
91+
pub fn insert_previously_failed_scid(&mut self, scid: u64) {
92+
if let PendingOutboundPayment::Retryable { route_params: Some(params), .. } = self {
93+
params.payment_params.previously_failed_channels.push(scid);
94+
}
95+
}
9096
pub(super) fn is_fulfilled(&self) -> bool {
9197
match self {
9298
PendingOutboundPayment::Fulfilled { .. } => true,
@@ -788,7 +794,8 @@ impl OutboundPayments {
788794
let mut outbounds = self.pending_outbound_payments.lock().unwrap();
789795
let mut all_paths_failed = false;
790796
let mut full_failure_ev = None;
791-
if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(*payment_id) {
797+
let mut pending_retry_ev = None;
798+
let attempts_remaining = if let hash_map::Entry::Occupied(mut payment) = outbounds.entry(*payment_id) {
792799
if !payment.get_mut().remove(&session_priv_bytes, Some(&path)) {
793800
log_trace!(logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
794801
return
@@ -797,6 +804,7 @@ impl OutboundPayments {
797804
log_trace!(logger, "Received failure of HTLC with payment_hash {} after payment completion", log_bytes!(payment_hash.0));
798805
return
799806
}
807+
let is_retryable = payment.get().is_retryable();
800808
if payment.get().remaining_parts() == 0 {
801809
all_paths_failed = true;
802810
if payment.get().abandoned() {
@@ -807,10 +815,11 @@ impl OutboundPayments {
807815
payment.remove();
808816
}
809817
}
818+
is_retryable
810819
} else {
811820
log_trace!(logger, "Received duplicative fail for HTLC with payment_hash {}", log_bytes!(payment_hash.0));
812821
return
813-
}
822+
};
814823
let mut retry = if let Some(payment_params_data) = payment_params {
815824
let path_last_hop = path.last().expect("Outbound payments must have had a valid path");
816825
Some(RouteParameters {
@@ -847,8 +856,15 @@ impl OutboundPayments {
847856
// process_onion_failure we should close that channel as it implies our
848857
// next-hop is needlessly blaming us!
849858
if let Some(scid) = short_channel_id {
859+
outbounds.get_mut(&payment_id).map(|pmt| pmt.insert_previously_failed_scid(scid));
850860
retry.as_mut().map(|r| r.payment_params.previously_failed_channels.push(scid));
851861
}
862+
if payment_retryable && attempts_remaining && retry.is_some() {
863+
debug_assert!(full_failure_ev.is_none());
864+
pending_retry_ev = Some(events::Event::PendingHTLCsForwardable {
865+
time_forwardable: Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS),
866+
});
867+
}
852868
events::Event::PaymentPathFailed {
853869
payment_id: Some(*payment_id),
854870
payment_hash: payment_hash.clone(),
@@ -868,6 +884,7 @@ impl OutboundPayments {
868884
let mut pending_events = pending_events.lock().unwrap();
869885
pending_events.push(path_failure);
870886
if let Some(ev) = full_failure_ev { pending_events.push(ev); }
887+
if let Some(ev) = pending_retry_ev { pending_events.push(ev); }
871888
}
872889

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

0 commit comments

Comments
 (0)