|
62 | 62 | } |
63 | 63 |
|
64 | 64 | 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 | +} |
65 | 70 |
|
66 | 71 | #[derive(Debug, PartialEq, Eq)] |
67 | 72 | enum JitInvoiceRequest { |
@@ -418,6 +423,34 @@ where |
418 | 423 | async fn negotiate_fixed_lease( |
419 | 424 | self: &Arc<Self>, amount_msat: u64, max_total_lsp_fee_limit_msat: Option<u64>, |
420 | 425 | 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>>, |
421 | 454 | ) -> Result<(PaymentLease, u64, LspConfig), Error> { |
422 | 455 | let all_offers = self.gather_lsps2_offers(connection_manager).await?; |
423 | 456 | let (cheapest_lsp, min_total_fee_msat, min_opening_params) = all_offers |
@@ -520,6 +553,33 @@ where |
520 | 553 | async fn negotiate_variable_lease( |
521 | 554 | self: &Arc<Self>, max_proportional_lsp_fee_limit_ppm_msat: Option<u64>, |
522 | 555 | 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>>, |
523 | 583 | ) -> Result<(PaymentLease, u64, LspConfig), Error> { |
524 | 584 | let all_offers = self.gather_lsps2_offers(connection_manager).await?; |
525 | 585 | let (cheapest_lsp, min_prop_fee_ppm_msat, min_opening_params) = all_offers |
@@ -1179,6 +1239,15 @@ mod tests { |
1179 | 1239 | assert_eq!(result, Err(())); |
1180 | 1240 | assert!(!*consumed.lock().unwrap()); |
1181 | 1241 | } |
| 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 | + } |
1182 | 1251 | } |
1183 | 1252 |
|
1184 | 1253 | pub(crate) mod state; |
0 commit comments