Require `supported_options` in `LSPS1ServiceConfig`
What changed, and why it matters
This commit removes several risky 'unwrap' calls in the LSPS1 liquidity service by making the 'supported_options' configuration field mandatory. Previously, if a service operator forgot to set this field, the code would panic (crash) when handling certain requests. Now the compiler enforces that the field is always provided, preventing that crash path at build time.
Treat as a hardening improvement. No immediate incident response is indicated, but downstream users building LSPS1 services should update to ensure their configurations provide supported_options, as the API now requires it.
Security signals we found
Removal of unwrap() calls on configuration Option fields
Conversion of runtime panic path into compile-time enforced required field
Defensive API hardening in LSP service configuration
Evidence from the diff
The patch changes LSPS1ServiceConfig.supported_options from Option
Changed components
lightning-liquidity/src/lsps1/service.rslightning-liquidity/tests/lsps0_integration_tests.rslightning-liquidity/tests/lsps1_integration_tests.rsInspect captured patch +22 / −18
diff --git a/lightning-liquidity/src/lsps1/service.rs b/lightning-liquidity/src/lsps1/service.rs
index 0b0adc0..9ce5e67 100644
--- a/lightning-liquidity/src/lsps1/service.rs
+++ b/lightning-liquidity/src/lsps1/service.rs
@@ -47,7 +47,7 @@ pub struct LSPS1ServiceConfig {
/// A token to be send with each channel request.
pub token: Option<String>,
/// The options supported by the LSP.
- pub supported_options: Option<LSPS1Options>,
+ pub supported_options: LSPS1Options,
}
/// The main object allowing to send and receive bLIP-51 / LSPS1 messages.
@@ -117,15 +117,7 @@ where
let mut message_queue_notifier = self.pending_messages.notifier();
let response = LSPS1Response::GetInfo(LSPS1GetInfoResponse {
- options: self
- .config
- .supported_options
- .clone()
- .ok_or(LightningError {
- err: format!("Configuration for LSP server not set."),
- action: ErrorAction::IgnoreAndLog(Level::Info),
- })
- .unwrap(),
+ options: self.config.supported_options.clone(),
});
let msg = LSPS1Message::Response(request_id, response).into();
@@ -140,14 +132,11 @@ where
let mut message_queue_notifier = self.pending_messages.notifier();
let event_queue_notifier = self.pending_events.notifier();
- if !is_valid(¶ms.order, &self.config.supported_options.as_ref().unwrap()) {
+ if !is_valid(¶ms.order, &self.config.supported_options) {
let response = LSPS1Response::CreateOrderError(LSPSResponseError {
code: LSPS1_CREATE_ORDER_REQUEST_ORDER_MISMATCH_ERROR_CODE,
message: format!("Order does not match options supported by LSP server"),
- data: Some(format!(
- "Supported options are {:?}",
- &self.config.supported_options.as_ref().unwrap()
- )),
+ data: Some(format!("Supported options are {:?}", &self.config.supported_options)),
});
let msg = LSPS1Message::Response(request_id, response).into();
message_queue_notifier.enqueue(counterparty_node_id, msg);
diff --git a/lightning-liquidity/tests/lsps0_integration_tests.rs b/lightning-liquidity/tests/lsps0_integration_tests.rs
index 423d497..7f0e01b 100644
--- a/lightning-liquidity/tests/lsps0_integration_tests.rs
+++ b/lightning-liquidity/tests/lsps0_integration_tests.rs
@@ -9,6 +9,8 @@ use lightning_liquidity::lsps0::event::LSPS0ClientEvent;
#[cfg(lsps1_service)]
use lightning_liquidity::lsps1::client::LSPS1ClientConfig;
#[cfg(lsps1_service)]
+use lightning_liquidity::lsps1::msgs::LSPS1Options;
+#[cfg(lsps1_service)]
use lightning_liquidity::lsps1::service::LSPS1ServiceConfig;
use lightning_liquidity::lsps2::client::LSPS2ClientConfig;
use lightning_liquidity::lsps2::service::LSPS2ServiceConfig;
@@ -34,7 +36,21 @@ fn list_protocols_integration_test() {
let promise_secret = [42; 32];
let lsps2_service_config = LSPS2ServiceConfig { promise_secret };
#[cfg(lsps1_service)]
- let lsps1_service_config = LSPS1ServiceConfig { supported_options: None, token: None };
+ let lsps1_service_config = {
+ let supported_options = LSPS1Options {
+ min_required_channel_confirmations: 0,
+ min_funding_confirms_within_blocks: 6,
+ supports_zero_channel_reserve: true,
+ max_channel_expiry_blocks: 144,
+ min_initial_client_balance_sat: 10_000_000,
+ max_initial_client_balance_sat: 100_000_000,
+ min_initial_lsp_balance_sat: 100_000,
+ max_initial_lsp_balance_sat: 100_000_000,
+ min_channel_balance_sat: 100_000,
+ max_channel_balance_sat: 100_000_000,
+ };
+ LSPS1ServiceConfig { supported_options, token: None }
+ };
let lsps5_service_config = LSPS5ServiceConfig::default();
let service_config = LiquidityServiceConfig {
#[cfg(lsps1_service)]
diff --git a/lightning-liquidity/tests/lsps1_integration_tests.rs b/lightning-liquidity/tests/lsps1_integration_tests.rs
index 0db96f5..e799cce 100644
--- a/lightning-liquidity/tests/lsps1_integration_tests.rs
+++ b/lightning-liquidity/tests/lsps1_integration_tests.rs
@@ -30,8 +30,7 @@ use lightning::ln::functional_test_utils::{create_network, Node};
fn build_lsps1_configs(
supported_options: LSPS1Options,
) -> (LiquidityServiceConfig, LiquidityClientConfig) {
- let lsps1_service_config =
- LSPS1ServiceConfig { token: None, supported_options: Some(supported_options) };
+ let lsps1_service_config = LSPS1ServiceConfig { token: None, supported_options };
let service_config = LiquidityServiceConfig {
lsps1_service_config: Some(lsps1_service_config),
lsps2_service_config: None,
Why this scored 42/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.