Skip to content

Commit c9b8b89

Browse files
committed
Allow configuring LSPS2 service via builders
We add the capability to configure LSPS2 service mode in `Builder` and `LiquiditySourceBuilder`.
1 parent 55e124a commit c9b8b89

File tree

2 files changed

+117
-31
lines changed

2 files changed

+117
-31
lines changed

src/builder.rs

Lines changed: 89 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ use vss_client::headers::{FixedHeaders, LnurlAuthToJwtProvider, VssHeaderProvide
7474

7575
const VSS_HARDENED_CHILD_INDEX: u32 = 877;
7676
const VSS_LNURL_AUTH_HARDENED_CHILD_INDEX: u32 = 138;
77+
const LSPS_HARDENED_CHILD_INDEX: u32 = 577;
7778

7879
#[derive(Debug, Clone)]
7980
enum ChainDataSourceConfig {
@@ -100,6 +101,8 @@ struct LiquiditySourceConfig {
100101
lsps1_client: Option<LSPS1ClientConfig>,
101102
// Act as an LSPS2 client connecting to the given service.
102103
lsps2_client: Option<LSPS2ClientConfig>,
104+
// Act as an LSPS2 service.
105+
lsps2_service: Option<LSPS2ServiceConfig>,
103106
}
104107

105108
#[derive(Debug, Clone)]
@@ -116,6 +119,12 @@ struct LSPS2ClientConfig {
116119
token: Option<String>,
117120
}
118121

122+
#[derive(Debug, Clone)]
123+
struct LSPS2ServiceConfig {
124+
token: Option<String>,
125+
advertise_service: bool,
126+
}
127+
119128
/// An error encountered during building a [`Node`].
120129
///
121130
/// [`Node`]: crate::Node
@@ -323,6 +332,26 @@ impl NodeBuilder {
323332
self
324333
}
325334

335+
/// Configures the [`Node`] instance to provide an [LSPS2] service, issuing just-in-time
336+
/// channels to clients.
337+
///
338+
/// If a `token` is provided, only requests matching this token will be accepted.
339+
///
340+
/// If `advertise_service` is set, the LSPS service will be announced via the gossip network.
341+
///
342+
/// **Caution**: LSP service support is in **alpha** and is considered an experimental feature.
343+
///
344+
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
345+
pub fn set_liquidity_provider_lsps2(
346+
&mut self, token: Option<String>, advertise_service: bool,
347+
) -> &mut Self {
348+
let liquidity_source_config =
349+
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
350+
let lsps2_service_config = LSPS2ServiceConfig { token, advertise_service };
351+
liquidity_source_config.lsps2_service = Some(lsps2_service_config);
352+
self
353+
}
354+
326355
/// Sets the used storage directory path.
327356
pub fn set_storage_dir_path(&mut self, storage_dir_path: String) -> &mut Self {
328357
self.config.storage_dir_path = storage_dir_path;
@@ -658,6 +687,20 @@ impl ArcedNodeBuilder {
658687
self.inner.write().unwrap().set_liquidity_source_lsps2(node_id, address, token);
659688
}
660689

690+
/// Configures the [`Node`] instance to provide an [LSPS2] service, issuing just-in-time
691+
/// channels to clients.
692+
///
693+
/// If a `token` is provided, only requests matching this token will be accepted.
694+
///
695+
/// If `advertise_service` is set, the LSPS service will be announced via the gossip network.
696+
///
697+
/// **Caution**: LSP service support is in **alpha** and is considered an experimental feature.
698+
///
699+
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
700+
pub fn set_liquidity_provider_lsps2(&self, token: Option<String>) {
701+
self.inner.write().unwrap().set_liquidity_service_lsps2(token);
702+
}
703+
661704
/// Sets the used storage directory path.
662705
pub fn set_storage_dir_path(&self, storage_dir_path: String) {
663706
self.inner.write().unwrap().set_storage_dir_path(storage_dir_path);
@@ -1105,39 +1148,56 @@ fn build_with_store_internal(
11051148
},
11061149
};
11071150

1108-
let liquidity_source = liquidity_source_config.as_ref().map(|lsc| {
1109-
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
1110-
Arc::clone(&channel_manager),
1111-
Arc::clone(&keys_manager),
1112-
Arc::clone(&chain_source),
1113-
Arc::clone(&config),
1114-
Arc::clone(&logger),
1115-
);
1151+
let (liquidity_source, custom_message_handler) =
1152+
if let Some(lsc) = liquidity_source_config.as_ref() {
1153+
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
1154+
Arc::clone(&channel_manager),
1155+
Arc::clone(&keys_manager),
1156+
Arc::clone(&chain_source),
1157+
Arc::clone(&config),
1158+
Arc::clone(&logger),
1159+
);
11161160

1117-
lsc.lsps1_client.as_ref().map(|config| {
1118-
liquidity_source_builder.lsps1_client(
1119-
config.node_id,
1120-
config.address.clone(),
1121-
config.token.clone(),
1122-
)
1123-
});
1161+
lsc.lsps1_client.as_ref().map(|config| {
1162+
liquidity_source_builder.lsps1_client(
1163+
config.node_id,
1164+
config.address.clone(),
1165+
config.token.clone(),
1166+
)
1167+
});
11241168

1125-
lsc.lsps2_client.as_ref().map(|config| {
1126-
liquidity_source_builder.lsps2_client(
1127-
config.node_id,
1128-
config.address.clone(),
1129-
config.token.clone(),
1130-
)
1131-
});
1169+
lsc.lsps2_client.as_ref().map(|config| {
1170+
liquidity_source_builder.lsps2_client(
1171+
config.node_id,
1172+
config.address.clone(),
1173+
config.token.clone(),
1174+
)
1175+
});
11321176

1133-
Arc::new(liquidity_source_builder.build())
1134-
});
1177+
let promise_secret = {
1178+
let lsps_xpriv = derive_xprv(
1179+
Arc::clone(&config),
1180+
&seed_bytes,
1181+
LSPS_HARDENED_CHILD_INDEX,
1182+
Arc::clone(&logger),
1183+
)?;
1184+
lsps_xpriv.private_key.secret_bytes()
1185+
};
1186+
lsc.lsps2_service.as_ref().map(|config| {
1187+
liquidity_source_builder.lsps2_service(
1188+
promise_secret,
1189+
config.token.clone(),
1190+
config.advertise_service,
1191+
)
1192+
});
11351193

1136-
let custom_message_handler = if let Some(liquidity_source) = liquidity_source.as_ref() {
1137-
Arc::new(NodeCustomMessageHandler::new_liquidity(Arc::clone(&liquidity_source)))
1138-
} else {
1139-
Arc::new(NodeCustomMessageHandler::new_ignoring())
1140-
};
1194+
let liquidity_source = Arc::new(liquidity_source_builder.build());
1195+
let custom_message_handler =
1196+
Arc::new(NodeCustomMessageHandler::new_liquidity(Arc::clone(&liquidity_source)));
1197+
(Some(liquidity_source), custom_message_handler)
1198+
} else {
1199+
(None, Arc::new(NodeCustomMessageHandler::new_ignoring()))
1200+
};
11411201

11421202
let msg_handler = match gossip_source.as_gossip_sync() {
11431203
GossipSync::P2P(p2p_gossip_sync) => MessageHandler {

src/liquidity.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,9 @@ use lightning_liquidity::lsps1::msgs::{
2727
use lightning_liquidity::lsps2::client::LSPS2ClientConfig;
2828
use lightning_liquidity::lsps2::event::LSPS2ClientEvent;
2929
use lightning_liquidity::lsps2::msgs::OpeningFeeParams;
30+
use lightning_liquidity::lsps2::service::LSPS2ServiceConfig;
3031
use lightning_liquidity::lsps2::utils::compute_opening_fee;
31-
use lightning_liquidity::LiquidityClientConfig;
32+
use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig};
3233

3334
use bitcoin::hashes::{sha256, Hash};
3435
use bitcoin::secp256k1::{PublicKey, Secp256k1};
@@ -65,12 +66,19 @@ struct LSPS2Client {
6566
pending_buy_requests: Mutex<HashMap<RequestId, oneshot::Sender<LSPS2BuyResponse>>>,
6667
}
6768

69+
struct LSPS2Service {
70+
token: Option<String>,
71+
service_config: LSPS2ServiceConfig,
72+
advertise_service: bool,
73+
}
74+
6875
pub(crate) struct LiquiditySourceBuilder<L: Deref>
6976
where
7077
L::Target: Logger,
7178
{
7279
lsps1_client: Option<LSPS1Client>,
7380
lsps2_client: Option<LSPS2Client>,
81+
lsps2_service: Option<LSPS2Service>,
7482
channel_manager: Arc<ChannelManager>,
7583
keys_manager: Arc<KeysManager>,
7684
chain_source: Arc<ChainSource>,
@@ -88,9 +96,11 @@ where
8896
) -> Self {
8997
let lsps1_client = None;
9098
let lsps2_client = None;
99+
let lsps2_service = None;
91100
Self {
92101
lsps1_client,
93102
lsps2_client,
103+
lsps2_service,
94104
channel_manager,
95105
keys_manager,
96106
chain_source,
@@ -136,7 +146,21 @@ where
136146
self
137147
}
138148

149+
pub(crate) fn lsps2_service(
150+
&mut self, promise_secret: [u8; 32], token: Option<String>, advertise_service: bool,
151+
) -> &mut Self {
152+
let service_config = LSPS2ServiceConfig { promise_secret };
153+
self.lsps2_service = Some(LSPS2Service { token, service_config, advertise_service });
154+
self
155+
}
156+
139157
pub(crate) fn build(self) -> LiquiditySource<L> {
158+
let liquidity_service_config = self.lsps2_service.as_ref().map(|s| {
159+
let lsps2_service_config = Some(s.service_config.clone());
160+
let advertise_service = s.advertise_service;
161+
LiquidityServiceConfig { lsps2_service_config, advertise_service }
162+
});
163+
140164
let lsps1_client_config = self.lsps1_client.as_ref().map(|s| s.client_config.clone());
141165
let lsps2_client_config = self.lsps2_client.as_ref().map(|s| s.client_config.clone());
142166
let liquidity_client_config =
@@ -147,13 +171,14 @@ where
147171
Arc::clone(&self.channel_manager),
148172
Some(Arc::clone(&self.chain_source)),
149173
None,
150-
None,
174+
liquidity_service_config,
151175
liquidity_client_config,
152176
));
153177

154178
LiquiditySource {
155179
lsps1_client: self.lsps1_client,
156180
lsps2_client: self.lsps2_client,
181+
lsps2_service: self.lsps2_service,
157182
channel_manager: self.channel_manager,
158183
keys_manager: self.keys_manager,
159184
liquidity_manager,
@@ -169,6 +194,7 @@ where
169194
{
170195
lsps1_client: Option<LSPS1Client>,
171196
lsps2_client: Option<LSPS2Client>,
197+
lsps2_service: Option<LSPS2Service>,
172198
channel_manager: Arc<ChannelManager>,
173199
keys_manager: Arc<KeysManager>,
174200
liquidity_manager: Arc<LiquidityManager>,

0 commit comments

Comments
 (0)