Skip to content

Commit 267b4be

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 a6844a6 commit 267b4be

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
@@ -61,6 +61,11 @@ where
6161
}
6262

6363
const DEFAULT_BOLT12_INVOICE_EXPIRY_SECS: u32 = 2 * 60 * 60;
64+
const LEASE_NEGOTIATION_MAX_ATTEMPTS: usize = 3;
65+
66+
fn should_retry_lease_negotiation(error: Error, attempt: usize) -> bool {
67+
error == Error::LiquidityRequestFailed && attempt < LEASE_NEGOTIATION_MAX_ATTEMPTS
68+
}
6469

6570
pub(crate) struct JitInvoiceResponse {
6671
pub(crate) payment_metadata: BTreeMap<u64, Vec<u8>>,
@@ -316,6 +321,34 @@ where
316321

317322
async fn negotiate_fixed_lease(
318323
self: &Arc<Self>, amount_msat: u64, connection_manager: &Arc<ConnectionManager<L>>,
324+
) -> Result<(PaymentLease, u64, LspConfig), Error> {
325+
let mut attempt = 1;
326+
loop {
327+
let result = self
328+
.negotiate_fixed_lease_once(
329+
amount_msat,
330+
max_total_lsp_fee_limit_msat,
331+
connection_manager,
332+
)
333+
.await;
334+
match result {
335+
Err(error) if should_retry_lease_negotiation(error, attempt) => {
336+
log_warn!(
337+
self.logger,
338+
"LSPS2 lease negotiation attempt {} failed, retrying: {}",
339+
attempt,
340+
error
341+
);
342+
attempt += 1;
343+
},
344+
result => return result,
345+
}
346+
}
347+
}
348+
349+
async fn negotiate_fixed_lease_once(
350+
self: &Arc<Self>, amount_msat: u64, max_total_lsp_fee_limit_msat: Option<u64>,
351+
connection_manager: &Arc<ConnectionManager<L>>,
319352
) -> Result<(PaymentLease, u64, LspConfig), Error> {
320353
let all_offers = self.gather_lsps2_offers(connection_manager).await?;
321354
let (cheapest_lsp, min_total_fee_msat, min_opening_params) = all_offers
@@ -402,6 +435,33 @@ where
402435

403436
async fn negotiate_variable_lease(
404437
self: &Arc<Self>, connection_manager: &Arc<ConnectionManager<L>>,
438+
) -> Result<(PaymentLease, u64, LspConfig), Error> {
439+
let mut attempt = 1;
440+
loop {
441+
let result = self
442+
.negotiate_variable_lease_once(
443+
max_proportional_lsp_fee_limit_ppm_msat,
444+
connection_manager,
445+
)
446+
.await;
447+
match result {
448+
Err(error) if should_retry_lease_negotiation(error, attempt) => {
449+
log_warn!(
450+
self.logger,
451+
"LSPS2 lease negotiation attempt {} failed, retrying: {}",
452+
attempt,
453+
error
454+
);
455+
attempt += 1;
456+
},
457+
result => return result,
458+
}
459+
}
460+
}
461+
462+
async fn negotiate_variable_lease_once(
463+
self: &Arc<Self>, max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
464+
connection_manager: &Arc<ConnectionManager<L>>,
405465
) -> Result<(PaymentLease, u64, LspConfig), Error> {
406466
let all_offers = self.gather_lsps2_offers(connection_manager).await?;
407467
let mut rejected_for_fee = false;
@@ -977,6 +1037,15 @@ mod tests {
9771037
assert_eq!(result, Err(()));
9781038
assert_eq!(*restored.lock().unwrap(), Some(42));
9791039
}
1040+
1041+
#[test]
1042+
fn lease_negotiation_retries_only_transient_failures() {
1043+
assert!(should_retry_lease_negotiation(Error::LiquidityRequestFailed, 1));
1044+
assert!(should_retry_lease_negotiation(Error::LiquidityRequestFailed, 2));
1045+
assert!(!should_retry_lease_negotiation(Error::LiquidityRequestFailed, 3));
1046+
assert!(!should_retry_lease_negotiation(Error::LiquidityFeeTooHigh, 1));
1047+
assert!(!should_retry_lease_negotiation(Error::LiquiditySourceUnavailable, 1));
1048+
}
9801049
}
9811050

9821051
pub(crate) mod router;

0 commit comments

Comments
 (0)