Skip to content

Commit f62b001

Browse files
committed
lsps2: Retry failed lease negotiation
Retry transient LSPS2 request failures for foreground acquisition and background cache refills. Preserve immediate errors for fee limits and unavailable liquidity sources. Co-Authored-By: HAL 9000
1 parent 32c48bd commit f62b001

1 file changed

Lines changed: 69 additions & 0 deletions

File tree

  • src/liquidity/client/lsps2

src/liquidity/client/lsps2/mod.rs

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,11 @@ where
5757
}
5858

5959
const DEFAULT_BOLT12_INVOICE_EXPIRY_SECS: u32 = 2 * 60 * 60;
60+
const LEASE_NEGOTIATION_MAX_ATTEMPTS: usize = 3;
61+
62+
fn should_retry_lease_negotiation(error: Error, attempt: usize) -> bool {
63+
error == Error::LiquidityRequestFailed && attempt < LEASE_NEGOTIATION_MAX_ATTEMPTS
64+
}
6065

6166
pub(crate) struct JitInvoiceResponse {
6267
pub(crate) payment_metadata: BTreeMap<u64, Vec<u8>>,
@@ -312,6 +317,34 @@ where
312317

313318
async fn negotiate_fixed_lease(
314319
self: &Arc<Self>, amount_msat: u64, connection_manager: &Arc<ConnectionManager<L>>,
320+
) -> Result<(PaymentLease, u64, LspConfig), Error> {
321+
let mut attempt = 1;
322+
loop {
323+
let result = self
324+
.negotiate_fixed_lease_once(
325+
amount_msat,
326+
max_total_lsp_fee_limit_msat,
327+
connection_manager,
328+
)
329+
.await;
330+
match result {
331+
Err(error) if should_retry_lease_negotiation(error, attempt) => {
332+
log_warn!(
333+
self.logger,
334+
"LSPS2 lease negotiation attempt {} failed, retrying: {}",
335+
attempt,
336+
error
337+
);
338+
attempt += 1;
339+
},
340+
result => return result,
341+
}
342+
}
343+
}
344+
345+
async fn negotiate_fixed_lease_once(
346+
self: &Arc<Self>, amount_msat: u64, max_total_lsp_fee_limit_msat: Option<u64>,
347+
connection_manager: &Arc<ConnectionManager<L>>,
315348
) -> Result<(PaymentLease, u64, LspConfig), Error> {
316349
let all_offers = self.gather_lsps2_offers(connection_manager).await?;
317350
let (cheapest_lsp, min_total_fee_msat, min_opening_params) = all_offers
@@ -398,6 +431,33 @@ where
398431

399432
async fn negotiate_variable_lease(
400433
self: &Arc<Self>, connection_manager: &Arc<ConnectionManager<L>>,
434+
) -> Result<(PaymentLease, u64, LspConfig), Error> {
435+
let mut attempt = 1;
436+
loop {
437+
let result = self
438+
.negotiate_variable_lease_once(
439+
max_proportional_lsp_fee_limit_ppm_msat,
440+
connection_manager,
441+
)
442+
.await;
443+
match result {
444+
Err(error) if should_retry_lease_negotiation(error, attempt) => {
445+
log_warn!(
446+
self.logger,
447+
"LSPS2 lease negotiation attempt {} failed, retrying: {}",
448+
attempt,
449+
error
450+
);
451+
attempt += 1;
452+
},
453+
result => return result,
454+
}
455+
}
456+
}
457+
458+
async fn negotiate_variable_lease_once(
459+
self: &Arc<Self>, max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
460+
connection_manager: &Arc<ConnectionManager<L>>,
401461
) -> Result<(PaymentLease, u64, LspConfig), Error> {
402462
let all_offers = self.gather_lsps2_offers(connection_manager).await?;
403463
let mut rejected_for_fee = false;
@@ -970,6 +1030,15 @@ mod tests {
9701030
assert_eq!(result, Err(()));
9711031
assert!(!*consumed.lock().unwrap());
9721032
}
1033+
1034+
#[test]
1035+
fn lease_negotiation_retries_only_transient_failures() {
1036+
assert!(should_retry_lease_negotiation(Error::LiquidityRequestFailed, 1));
1037+
assert!(should_retry_lease_negotiation(Error::LiquidityRequestFailed, 2));
1038+
assert!(!should_retry_lease_negotiation(Error::LiquidityRequestFailed, 3));
1039+
assert!(!should_retry_lease_negotiation(Error::LiquidityFeeTooHigh, 1));
1040+
assert!(!should_retry_lease_negotiation(Error::LiquiditySourceUnavailable, 1));
1041+
}
9731042
}
9741043

9751044
pub(crate) mod router;

0 commit comments

Comments
 (0)