Skip to content

Commit 4ced077

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 282ee1a commit 4ced077

File tree

1 file changed

+41
-18
lines changed

1 file changed

+41
-18
lines changed

lightning/src/ln/outbound_payment.rs

+41-18
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(())
@@ -1667,9 +1688,11 @@ impl_writeable_tlv_based_enum_upgradable!(PendingOutboundPayment,
16671688
},
16681689
(5, AwaitingInvoice) => {
16691690
(0, timer_ticks_without_response, required),
1691+
(2, retry_strategy, required),
16701692
},
16711693
(7, InvoiceReceived) => {
16721694
(0, payment_hash, required),
1695+
(2, retry_strategy, required),
16731696
},
16741697
);
16751698

@@ -1891,7 +1914,7 @@ mod tests {
18911914
let payment_id = PaymentId([0; 32]);
18921915

18931916
assert!(!outbound_payments.has_pending_payments());
1894-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
1917+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
18951918
assert!(outbound_payments.has_pending_payments());
18961919

18971920
for _ in 0..INVOICE_REQUEST_TIMEOUT_TICKS {
@@ -1909,10 +1932,10 @@ mod tests {
19091932
);
19101933
assert!(pending_events.lock().unwrap().is_empty());
19111934

1912-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
1935+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
19131936
assert!(outbound_payments.has_pending_payments());
19141937

1915-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_err());
1938+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_err());
19161939
}
19171940

19181941
#[test]
@@ -1922,7 +1945,7 @@ mod tests {
19221945
let payment_id = PaymentId([0; 32]);
19231946

19241947
assert!(!outbound_payments.has_pending_payments());
1925-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
1948+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
19261949
assert!(outbound_payments.has_pending_payments());
19271950

19281951
outbound_payments.abandon_payment(
@@ -1950,7 +1973,7 @@ mod tests {
19501973
let outbound_payments = OutboundPayments::new();
19511974
let payment_id = PaymentId([0; 32]);
19521975

1953-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
1976+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
19541977
assert!(outbound_payments.has_pending_payments());
19551978

19561979
let created_at = now() - DEFAULT_RELATIVE_EXPIRY;
@@ -1996,7 +2019,7 @@ mod tests {
19962019
let outbound_payments = OutboundPayments::new();
19972020
let payment_id = PaymentId([0; 32]);
19982021

1999-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
2022+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
20002023
assert!(outbound_payments.has_pending_payments());
20012024

20022025
let invoice = OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -2049,7 +2072,7 @@ mod tests {
20492072
let outbound_payments = OutboundPayments::new();
20502073
let payment_id = PaymentId([0; 32]);
20512074

2052-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
2075+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
20532076
assert!(outbound_payments.has_pending_payments());
20542077

20552078
let invoice = OfferBuilder::new("foo".into(), recipient_pubkey())
@@ -2149,7 +2172,7 @@ mod tests {
21492172
assert!(!outbound_payments.has_pending_payments());
21502173
assert!(pending_events.lock().unwrap().is_empty());
21512174

2152-
assert!(outbound_payments.add_new_awaiting_invoice(payment_id).is_ok());
2175+
assert!(outbound_payments.add_new_awaiting_invoice(payment_id, Retry::Attempts(0)).is_ok());
21532176
assert!(outbound_payments.has_pending_payments());
21542177

21552178
assert_eq!(

0 commit comments

Comments
 (0)