Skip to content

Commit 2a77b14

Browse files
committed
Allow configuring LSPS2 service via builders
We add the capability to configure LSPS2 service mode in `Builder` and `LiquiditySourceBuilder`.
1 parent 09343ce commit 2a77b14

2 files changed

Lines changed: 117 additions & 31 deletions

File tree

src/builder.rs

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

7878
const VSS_HARDENED_CHILD_INDEX: u32 = 877;
7979
const VSS_LNURL_AUTH_HARDENED_CHILD_INDEX: u32 = 138;
80+
const LSPS_HARDENED_CHILD_INDEX: u32 = 577;
8081

8182
#[derive(Debug, Clone)]
8283
enum ChainDataSourceConfig {
@@ -103,6 +104,14 @@ struct LiquiditySourceConfig {
103104
lsps1_client: Option<LSPS1ClientConfig>,
104105
// Act as an LSPS2 client connecting to the given service.
105106
lsps2_client: Option<LSPS2ClientConfig>,
107+
// Act as an LSPS2 service.
108+
lsps2_service: Option<LSPS2ServiceConfig>,
109+
}
110+
111+
#[derive(Debug, Clone)]
112+
struct LSPS2ServiceConfig {
113+
token: Option<String>,
114+
advertise_service: bool,
106115
}
107116

108117
#[derive(Clone)]
@@ -340,6 +349,26 @@ impl NodeBuilder {
340349
self
341350
}
342351

352+
/// Configures the [`Node`] instance to provide an [LSPS2] service, issuing just-in-time
353+
/// channels to clients.
354+
///
355+
/// If a `token` is provided, only requests matching this token will be accepted.
356+
///
357+
/// If `advertise_service` is set, the LSPS service will be announced via the gossip network.
358+
///
359+
/// **Caution**: LSP service support is in **alpha** and is considered an experimental feature.
360+
///
361+
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
362+
pub fn set_liquidity_provider_lsps2(
363+
&mut self, token: Option<String>, advertise_service: bool,
364+
) -> &mut Self {
365+
let liquidity_source_config =
366+
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
367+
let lsps2_service_config = LSPS2ServiceConfig { token, advertise_service };
368+
liquidity_source_config.lsps2_service = Some(lsps2_service_config);
369+
self
370+
}
371+
343372
/// Sets the used storage directory path.
344373
pub fn set_storage_dir_path(&mut self, storage_dir_path: String) -> &mut Self {
345374
self.config.storage_dir_path = storage_dir_path;
@@ -692,6 +721,20 @@ impl ArcedNodeBuilder {
692721
self.inner.write().unwrap().set_liquidity_source_lsps2(node_id, address, token);
693722
}
694723

724+
/// Configures the [`Node`] instance to provide an [LSPS2] service, issuing just-in-time
725+
/// channels to clients.
726+
///
727+
/// If a `token` is provided, only requests matching this token will be accepted.
728+
///
729+
/// If `advertise_service` is set, the LSPS service will be announced via the gossip network.
730+
///
731+
/// **Caution**: LSP service support is in **alpha** and is considered an experimental feature.
732+
///
733+
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
734+
pub fn set_liquidity_provider_lsps2(&self, token: Option<String>, advertise_service: bool) {
735+
self.inner.write().unwrap().set_liquidity_provider_lsps2(token, advertise_service);
736+
}
737+
695738
/// Sets the used storage directory path.
696739
pub fn set_storage_dir_path(&self, storage_dir_path: String) {
697740
self.inner.write().unwrap().set_storage_dir_path(storage_dir_path);
@@ -1167,39 +1210,56 @@ fn build_with_store_internal(
11671210
},
11681211
};
11691212

1170-
let liquidity_source = liquidity_source_config.as_ref().map(|lsc| {
1171-
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
1172-
Arc::clone(&channel_manager),
1173-
Arc::clone(&keys_manager),
1174-
Arc::clone(&chain_source),
1175-
Arc::clone(&config),
1176-
Arc::clone(&logger),
1177-
);
1213+
let (liquidity_source, custom_message_handler) =
1214+
if let Some(lsc) = liquidity_source_config.as_ref() {
1215+
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
1216+
Arc::clone(&channel_manager),
1217+
Arc::clone(&keys_manager),
1218+
Arc::clone(&chain_source),
1219+
Arc::clone(&config),
1220+
Arc::clone(&logger),
1221+
);
11781222

1179-
lsc.lsps1_client.as_ref().map(|config| {
1180-
liquidity_source_builder.lsps1_client(
1181-
config.node_id,
1182-
config.address.clone(),
1183-
config.token.clone(),
1184-
)
1185-
});
1223+
lsc.lsps1_client.as_ref().map(|config| {
1224+
liquidity_source_builder.lsps1_client(
1225+
config.node_id,
1226+
config.address.clone(),
1227+
config.token.clone(),
1228+
)
1229+
});
11861230

1187-
lsc.lsps2_client.as_ref().map(|config| {
1188-
liquidity_source_builder.lsps2_client(
1189-
config.node_id,
1190-
config.address.clone(),
1191-
config.token.clone(),
1192-
)
1193-
});
1231+
lsc.lsps2_client.as_ref().map(|config| {
1232+
liquidity_source_builder.lsps2_client(
1233+
config.node_id,
1234+
config.address.clone(),
1235+
config.token.clone(),
1236+
)
1237+
});
11941238

1195-
Arc::new(liquidity_source_builder.build())
1196-
});
1239+
let promise_secret = {
1240+
let lsps_xpriv = derive_xprv(
1241+
Arc::clone(&config),
1242+
&seed_bytes,
1243+
LSPS_HARDENED_CHILD_INDEX,
1244+
Arc::clone(&logger),
1245+
)?;
1246+
lsps_xpriv.private_key.secret_bytes()
1247+
};
1248+
lsc.lsps2_service.as_ref().map(|config| {
1249+
liquidity_source_builder.lsps2_service(
1250+
promise_secret,
1251+
config.token.clone(),
1252+
config.advertise_service,
1253+
)
1254+
});
11971255

1198-
let custom_message_handler = if let Some(liquidity_source) = liquidity_source.as_ref() {
1199-
Arc::new(NodeCustomMessageHandler::new_liquidity(Arc::clone(&liquidity_source)))
1200-
} else {
1201-
Arc::new(NodeCustomMessageHandler::new_ignoring())
1202-
};
1256+
let liquidity_source = Arc::new(liquidity_source_builder.build());
1257+
let custom_message_handler =
1258+
Arc::new(NodeCustomMessageHandler::new_liquidity(Arc::clone(&liquidity_source)));
1259+
(Some(liquidity_source), custom_message_handler)
1260+
} else {
1261+
(None, Arc::new(NodeCustomMessageHandler::new_ignoring()))
1262+
};
12031263

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

src/liquidity.rs

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,9 @@ use lightning_liquidity::lsps1::msgs::{ChannelInfo, LSPS1Options, OrderId, Order
2525
use lightning_liquidity::lsps2::client::LSPS2ClientConfig as LdkLSPS2ClientConfig;
2626
use lightning_liquidity::lsps2::event::LSPS2ClientEvent;
2727
use lightning_liquidity::lsps2::msgs::OpeningFeeParams;
28+
use lightning_liquidity::lsps2::service::LSPS2ServiceConfig;
2829
use lightning_liquidity::lsps2::utils::compute_opening_fee;
29-
use lightning_liquidity::LiquidityClientConfig;
30+
use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig};
3031

3132
use bitcoin::hashes::{sha256, Hash};
3233
use bitcoin::secp256k1::{PublicKey, Secp256k1};
@@ -75,12 +76,19 @@ pub(crate) struct LSPS2ClientConfig {
7576
pub token: Option<String>,
7677
}
7778

79+
struct LSPS2Service {
80+
token: Option<String>,
81+
service_config: LSPS2ServiceConfig,
82+
advertise_service: bool,
83+
}
84+
7885
pub(crate) struct LiquiditySourceBuilder<L: Deref>
7986
where
8087
L::Target: LdkLogger,
8188
{
8289
lsps1_client: Option<LSPS1Client>,
8390
lsps2_client: Option<LSPS2Client>,
91+
lsps2_service: Option<LSPS2Service>,
8492
channel_manager: Arc<ChannelManager>,
8593
keys_manager: Arc<KeysManager>,
8694
chain_source: Arc<ChainSource>,
@@ -98,9 +106,11 @@ where
98106
) -> Self {
99107
let lsps1_client = None;
100108
let lsps2_client = None;
109+
let lsps2_service = None;
101110
Self {
102111
lsps1_client,
103112
lsps2_client,
113+
lsps2_service,
104114
channel_manager,
105115
keys_manager,
106116
chain_source,
@@ -146,7 +156,21 @@ where
146156
self
147157
}
148158

159+
pub(crate) fn lsps2_service(
160+
&mut self, promise_secret: [u8; 32], token: Option<String>, advertise_service: bool,
161+
) -> &mut Self {
162+
let service_config = LSPS2ServiceConfig { promise_secret };
163+
self.lsps2_service = Some(LSPS2Service { token, service_config, advertise_service });
164+
self
165+
}
166+
149167
pub(crate) fn build(self) -> LiquiditySource<L> {
168+
let liquidity_service_config = self.lsps2_service.as_ref().map(|s| {
169+
let lsps2_service_config = Some(s.service_config.clone());
170+
let advertise_service = s.advertise_service;
171+
LiquidityServiceConfig { lsps2_service_config, advertise_service }
172+
});
173+
150174
let lsps1_client_config = self.lsps1_client.as_ref().map(|s| s.ldk_client_config.clone());
151175
let lsps2_client_config = self.lsps2_client.as_ref().map(|s| s.ldk_client_config.clone());
152176
let liquidity_client_config =
@@ -157,13 +181,14 @@ where
157181
Arc::clone(&self.channel_manager),
158182
Some(Arc::clone(&self.chain_source)),
159183
None,
160-
None,
184+
liquidity_service_config,
161185
liquidity_client_config,
162186
));
163187

164188
LiquiditySource {
165189
lsps1_client: self.lsps1_client,
166190
lsps2_client: self.lsps2_client,
191+
lsps2_service: self.lsps2_service,
167192
channel_manager: self.channel_manager,
168193
keys_manager: self.keys_manager,
169194
liquidity_manager,
@@ -179,6 +204,7 @@ where
179204
{
180205
lsps1_client: Option<LSPS1Client>,
181206
lsps2_client: Option<LSPS2Client>,
207+
lsps2_service: Option<LSPS2Service>,
182208
channel_manager: Arc<ChannelManager>,
183209
keys_manager: Arc<KeysManager>,
184210
liquidity_manager: Arc<LiquidityManager>,

0 commit comments

Comments
 (0)