Skip to content

Commit 0f1bc13

Browse files
committed
Configure BOLT 12 invoice payment retry strategy
Replace a constant three retry attempts for BOLT 12 invoice payments with a retry strategy specified when creating a pending outbound payment. This is configured by users in a later commit when constructing an InvoiceRequest or a Refund.
1 parent a52d7fb commit 0f1bc13

File tree

1 file changed

+40
-17
lines changed

1 file changed

+40
-17
lines changed

lightning/src/ln/outbound_payment.rs

+40-17
Original file line numberDiff line numberDiff line change
@@ -53,9 +53,11 @@ pub(crate) enum PendingOutboundPayment {
5353
},
5454
AwaitingInvoice {
5555
timer_ticks_without_response: u8,
56+
retry_strategy: Retry,
5657
},
5758
InvoiceReceived {
5859
payment_hash: PaymentHash,
60+
retry_strategy: Retry,
5961
},
6062
Retryable {
6163
retry_strategy: Option<Retry>,
@@ -156,7 +158,7 @@ impl PendingOutboundPayment {
156158
match self {
157159
PendingOutboundPayment::Legacy { .. } => None,
158160
PendingOutboundPayment::AwaitingInvoice { .. } => None,
159-
PendingOutboundPayment::InvoiceReceived { payment_hash } => Some(*payment_hash),
161+
PendingOutboundPayment::InvoiceReceived { payment_hash, .. } => Some(*payment_hash),
160162
PendingOutboundPayment::Retryable { payment_hash, .. } => Some(*payment_hash),
161163
PendingOutboundPayment::Fulfilled { payment_hash, .. } => *payment_hash,
162164
PendingOutboundPayment::Abandoned { payment_hash, .. } => Some(*payment_hash),
@@ -186,7 +188,7 @@ impl PendingOutboundPayment {
186188
payment_hash: *payment_hash,
187189
reason: Some(reason)
188190
};
189-
} else if let PendingOutboundPayment::InvoiceReceived { payment_hash } = self {
191+
} else if let PendingOutboundPayment::InvoiceReceived { payment_hash, .. } = self {
190192
*self = PendingOutboundPayment::Abandoned {
191193
session_privs: HashSet::new(),
192194
payment_hash: *payment_hash,
@@ -272,6 +274,19 @@ pub enum Retry {
272274
Timeout(core::time::Duration),
273275
}
274276

277+
#[cfg(feature = "no-std")]
278+
impl_writeable_tlv_based_enum!(Retry,
279+
;
280+
(0, Attempts)
281+
);
282+
283+
#[cfg(not(feature = "no-std"))]
284+
impl_writeable_tlv_based_enum!(Retry,
285+
;
286+
(0, Attempts),
287+
(2, Timeout)
288+
);
289+
275290
impl Retry {
276291
pub(crate) fn is_retryable_now(&self, attempts: &PaymentAttempts) -> bool {
277292
match (self, attempts) {
@@ -587,8 +602,6 @@ pub(super) struct SendAlongPathArgs<'a> {
587602
pub session_priv_bytes: [u8; 32],
588603
}
589604

590-
const BOLT_12_INVOICE_RETRY_STRATEGY: Retry = Retry::Attempts(3);
591-
592605
pub(super) struct OutboundPayments {
593606
pub(super) pending_outbound_payments: Mutex<HashMap<PaymentId, PendingOutboundPayment>>,
594607
pub(super) retry_lock: Mutex<()>,
@@ -707,10 +720,15 @@ impl OutboundPayments {
707720
{
708721
let payment_hash = invoice.payment_hash();
709722
match self.pending_outbound_payments.lock().unwrap().entry(payment_id) {
710-
hash_map::Entry::Occupied(entry) if entry.get().is_awaiting_invoice() => {
711-
*entry.into_mut() = PendingOutboundPayment::InvoiceReceived { payment_hash };
723+
hash_map::Entry::Occupied(entry) => match entry.get() {
724+
PendingOutboundPayment::AwaitingInvoice { retry_strategy, .. } => {
725+
*entry.into_mut() = PendingOutboundPayment::InvoiceReceived {
726+
payment_hash,
727+
retry_strategy: *retry_strategy,
728+
};
729+
},
730+
_ => return Err(Bolt12PaymentError::DuplicateInvoice),
712731
},
713-
hash_map::Entry::Occupied(_) => return Err(Bolt12PaymentError::DuplicateInvoice),
714732
hash_map::Entry::Vacant(_) => return Err(Bolt12PaymentError::UnexpectedInvoice),
715733
};
716734

@@ -957,14 +975,14 @@ impl OutboundPayments {
957975
log_error!(logger, "Payment not yet sent");
958976
return
959977
},
960-
PendingOutboundPayment::InvoiceReceived { payment_hash } => {
978+
PendingOutboundPayment::InvoiceReceived { payment_hash, retry_strategy } => {
961979
let total_amount = route_params.final_value_msat;
962980
let recipient_onion = RecipientOnionFields {
963981
payment_secret: None,
964982
payment_metadata: None,
965983
custom_tlvs: vec![],
966984
};
967-
let retry_strategy = Some(BOLT_12_INVOICE_RETRY_STRATEGY);
985+
let retry_strategy = Some(*retry_strategy);
968986
let payment_params = Some(route_params.payment_params.clone());
969987
let (retryable_payment, onion_session_privs) = self.create_pending_payment(
970988
*payment_hash, recipient_onion.clone(), None, &route,
@@ -1186,13 +1204,16 @@ impl OutboundPayments {
11861204
}
11871205

11881206
#[allow(unused)]
1189-
pub(super) fn add_new_awaiting_invoice(&self, payment_id: PaymentId) -> Result<(), ()> {
1207+
pub(super) fn add_new_awaiting_invoice(
1208+
&self, payment_id: PaymentId, retry_strategy: Retry
1209+
) -> Result<(), ()> {
11901210
let mut pending_outbounds = self.pending_outbound_payments.lock().unwrap();
11911211
match pending_outbounds.entry(payment_id) {
11921212
hash_map::Entry::Occupied(_) => Err(()),
11931213
hash_map::Entry::Vacant(entry) => {
11941214
entry.insert(PendingOutboundPayment::AwaitingInvoice {
11951215
timer_ticks_without_response: 0,
1216+
retry_strategy,
11961217
});
11971218

11981219
Ok(())
@@ -1662,9 +1683,11 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
16621683
},
16631684
(5, AwaitingInvoice) => {
16641685
(0, timer_ticks_without_response, required),
1686+
(2, retry_strategy, required),
16651687
},
16661688
(7, InvoiceReceived) => {
16671689
(0, payment_hash, required),
1690+
(2, retry_strategy, required),
16681691
},
16691692
);
16701693

@@ -1895,7 +1918,7 @@ mod tests {
18951918
let payment_id = PaymentId([0; 32]);
18961919

18971920
assert!(!outbound_payments.has_pending_payments());
1898-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
1921+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
18991922
assert!(outbound_payments.has_pending_payments());
19001923

19011924
for _ in 0..INVOICE_REQUEST_TIMEOUT_TICKS {
@@ -1915,10 +1938,10 @@ mod tests {
19151938
);
19161939
assert!(pending_events.lock().unwrap().is_empty());
19171940

1918-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
1941+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
19191942
assert!(outbound_payments.has_pending_payments());
19201943

1921-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_err());
1944+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_err());
19221945
}
19231946

19241947
#[cfg(feature = "std")]
@@ -1934,7 +1957,7 @@ mod tests {
19341957
let outbound_payments = OutboundPayments::new();
19351958
let payment_id = PaymentId([0; 32]);
19361959

1937-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
1960+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
19381961
assert!(outbound_payments.has_pending_payments());
19391962

19401963
let created_at = now() - DEFAULT_RELATIVE_EXPIRY;
@@ -1980,7 +2003,7 @@ mod tests {
19802003
let outbound_payments = OutboundPayments::new();
19812004
let payment_id = PaymentId([0; 32]);
19822005

1983-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
2006+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
19842007
assert!(outbound_payments.has_pending_payments());
19852008

19862009
let invoice = OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -2033,7 +2056,7 @@ mod tests {
20332056
let outbound_payments = OutboundPayments::new();
20342057
let payment_id = PaymentId([0; 32]);
20352058

2036-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
2059+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
20372060
assert!(outbound_payments.has_pending_payments());
20382061

20392062
let invoice = OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -2135,7 +2158,7 @@ mod tests {
21352158
assert!(!outbound_payments.has_pending_payments());
21362159
assert!(pending_events.lock().unwrap().is_empty());
21372160

2138-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
2161+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
21392162
assert!(outbound_payments.has_pending_payments());
21402163

21412164
assert_eq!(

0 commit comments

Comments
 (0)