Skip to content

Commit cd4ba0d

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 aa133fe commit cd4ba0d

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

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

6671
#[derive(Debug, PartialEq, Eq)]
6772
enum JitInvoiceRequest {
@@ -418,6 +423,34 @@ where
418423
async fn negotiate_fixed_lease(
419424
self: &Arc<Self>, amount_msat: u64, max_total_lsp_fee_limit_msat: Option<u64>,
420425
connection_manager: &Arc<ConnectionManager<L>>,
426+
) -> Result<(PaymentLease, u64, LspConfig), Error> {
427+
let mut attempt = 1;
428+
loop {
429+
let result = self
430+
.negotiate_fixed_lease_once(
431+
amount_msat,
432+
max_total_lsp_fee_limit_msat,
433+
connection_manager,
434+
)
435+
.await;
436+
match result {
437+
Err(error) if should_retry_lease_negotiation(error, attempt) => {
438+
log_warn!(
439+
self.logger,
440+
"LSPS2 lease negotiation attempt {} failed, retrying: {}",
441+
attempt,
442+
error
443+
);
444+
attempt += 1;
445+
},
446+
result => return result,
447+
}
448+
}
449+
}
450+
451+
async fn negotiate_fixed_lease_once(
452+
self: &Arc<Self>, amount_msat: u64, max_total_lsp_fee_limit_msat: Option<u64>,
453+
connection_manager: &Arc<ConnectionManager<L>>,
421454
) -> Result<(PaymentLease, u64, LspConfig), Error> {
422455
let all_offers = self.gather_lsps2_offers(connection_manager).await?;
423456
let (cheapest_lsp, min_total_fee_msat, min_opening_params) = all_offers
@@ -520,6 +553,33 @@ where
520553
async fn negotiate_variable_lease(
521554
self: &Arc<Self>, max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
522555
connection_manager: &Arc<ConnectionManager<L>>,
556+
) -> Result<(PaymentLease, u64, LspConfig), Error> {
557+
let mut attempt = 1;
558+
loop {
559+
let result = self
560+
.negotiate_variable_lease_once(
561+
max_proportional_lsp_fee_limit_ppm_msat,
562+
connection_manager,
563+
)
564+
.await;
565+
match result {
566+
Err(error) if should_retry_lease_negotiation(error, attempt) => {
567+
log_warn!(
568+
self.logger,
569+
"LSPS2 lease negotiation attempt {} failed, retrying: {}",
570+
attempt,
571+
error
572+
);
573+
attempt += 1;
574+
},
575+
result => return result,
576+
}
577+
}
578+
}
579+
580+
async fn negotiate_variable_lease_once(
581+
self: &Arc<Self>, max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
582+
connection_manager: &Arc<ConnectionManager<L>>,
523583
) -> Result<(PaymentLease, u64, LspConfig), Error> {
524584
let all_offers = self.gather_lsps2_offers(connection_manager).await?;
525585
let (cheapest_lsp, min_prop_fee_ppm_msat, min_opening_params) = all_offers
@@ -1179,6 +1239,15 @@ mod tests {
11791239
assert_eq!(result, Err(()));
11801240
assert!(!*consumed.lock().unwrap());
11811241
}
1242+
1243+
#[test]
1244+
fn lease_negotiation_retries_only_transient_failures() {
1245+
assert!(should_retry_lease_negotiation(Error::LiquidityRequestFailed, 1));
1246+
assert!(should_retry_lease_negotiation(Error::LiquidityRequestFailed, 2));
1247+
assert!(!should_retry_lease_negotiation(Error::LiquidityRequestFailed, 3));
1248+
assert!(!should_retry_lease_negotiation(Error::LiquidityFeeTooHigh, 1));
1249+
assert!(!should_retry_lease_negotiation(Error::LiquiditySourceUnavailable, 1));
1250+
}
11821251
}
11831252

11841253
pub(crate) mod state;

0 commit comments

Comments
 (0)