Skip to content

Commit d04fdef

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

File tree

2 files changed

+117
-31
lines changed

2 files changed

+117
-31
lines changed

src/builder.rs

+89-29
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,8 @@ 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>,
106109
}
107110

108111
#[derive(Debug, Clone)]
@@ -119,6 +122,12 @@ struct LSPS2ClientConfig {
119122
token: Option<String>,
120123
}
121124

125+
#[derive(Debug, Clone)]
126+
struct LSPS2ServiceConfig {
127+
token: Option<String>,
128+
advertise_service: bool,
129+
}
130+
122131
#[derive(Clone)]
123132
enum LogWriterConfig {
124133
File { log_file_path: Option<String>, max_log_level: Option<LogLevel> },
@@ -356,6 +365,26 @@ impl NodeBuilder {
356365
self
357366
}
358367

368+
/// Configures the [`Node`] instance to provide an [LSPS2] service, issuing just-in-time
369+
/// channels to clients.
370+
///
371+
/// If a `token` is provided, only requests matching this token will be accepted.
372+
///
373+
/// If `advertise_service` is set, the LSPS service will be announced via the gossip network.
374+
///
375+
/// **Caution**: LSP service support is in **alpha** and is considered an experimental feature.
376+
///
377+
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
378+
pub fn set_liquidity_provider_lsps2(
379+
&mut self, token: Option<String>, advertise_service: bool,
380+
) -> &mut Self {
381+
let liquidity_source_config =
382+
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
383+
let lsps2_service_config = LSPS2ServiceConfig { token, advertise_service };
384+
liquidity_source_config.lsps2_service = Some(lsps2_service_config);
385+
self
386+
}
387+
359388
/// Sets the used storage directory path.
360389
pub fn set_storage_dir_path(&mut self, storage_dir_path: String) -> &mut Self {
361390
self.config.storage_dir_path = storage_dir_path;
@@ -713,6 +742,20 @@ impl ArcedNodeBuilder {
713742
self.inner.write().unwrap().set_liquidity_source_lsps2(node_id, address, token);
714743
}
715744

745+
/// Configures the [`Node`] instance to provide an [LSPS2] service, issuing just-in-time
746+
/// channels to clients.
747+
///
748+
/// If a `token` is provided, only requests matching this token will be accepted.
749+
///
750+
/// If `advertise_service` is set, the LSPS service will be announced via the gossip network.
751+
///
752+
/// **Caution**: LSP service support is in **alpha** and is considered an experimental feature.
753+
///
754+
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
755+
pub fn set_liquidity_provider_lsps2(&self, token: Option<String>, advertise_service: bool) {
756+
self.inner.write().unwrap().set_liquidity_provider_lsps2(token, advertise_service);
757+
}
758+
716759
/// Sets the used storage directory path.
717760
pub fn set_storage_dir_path(&self, storage_dir_path: String) {
718761
self.inner.write().unwrap().set_storage_dir_path(storage_dir_path);
@@ -1193,39 +1236,56 @@ fn build_with_store_internal(
11931236
},
11941237
};
11951238

1196-
let liquidity_source = liquidity_source_config.as_ref().map(|lsc| {
1197-
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
1198-
Arc::clone(&channel_manager),
1199-
Arc::clone(&keys_manager),
1200-
Arc::clone(&chain_source),
1201-
Arc::clone(&config),
1202-
Arc::clone(&logger),
1203-
);
1239+
let (liquidity_source, custom_message_handler) =
1240+
if let Some(lsc) = liquidity_source_config.as_ref() {
1241+
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
1242+
Arc::clone(&channel_manager),
1243+
Arc::clone(&keys_manager),
1244+
Arc::clone(&chain_source),
1245+
Arc::clone(&config),
1246+
Arc::clone(&logger),
1247+
);
12041248

1205-
lsc.lsps1_client.as_ref().map(|config| {
1206-
liquidity_source_builder.lsps1_client(
1207-
config.node_id,
1208-
config.address.clone(),
1209-
config.token.clone(),
1210-
)
1211-
});
1249+
lsc.lsps1_client.as_ref().map(|config| {
1250+
liquidity_source_builder.lsps1_client(
1251+
config.node_id,
1252+
config.address.clone(),
1253+
config.token.clone(),
1254+
)
1255+
});
12121256

1213-
lsc.lsps2_client.as_ref().map(|config| {
1214-
liquidity_source_builder.lsps2_client(
1215-
config.node_id,
1216-
config.address.clone(),
1217-
config.token.clone(),
1218-
)
1219-
});
1257+
lsc.lsps2_client.as_ref().map(|config| {
1258+
liquidity_source_builder.lsps2_client(
1259+
config.node_id,
1260+
config.address.clone(),
1261+
config.token.clone(),
1262+
)
1263+
});
12201264

1221-
Arc::new(liquidity_source_builder.build())
1222-
});
1265+
let promise_secret = {
1266+
let lsps_xpriv = derive_xprv(
1267+
Arc::clone(&config),
1268+
&seed_bytes,
1269+
LSPS_HARDENED_CHILD_INDEX,
1270+
Arc::clone(&logger),
1271+
)?;
1272+
lsps_xpriv.private_key.secret_bytes()
1273+
};
1274+
lsc.lsps2_service.as_ref().map(|config| {
1275+
liquidity_source_builder.lsps2_service(
1276+
promise_secret,
1277+
config.token.clone(),
1278+
config.advertise_service,
1279+
)
1280+
});
12231281

1224-
let custom_message_handler = if let Some(liquidity_source) = liquidity_source.as_ref() {
1225-
Arc::new(NodeCustomMessageHandler::new_liquidity(Arc::clone(&liquidity_source)))
1226-
} else {
1227-
Arc::new(NodeCustomMessageHandler::new_ignoring())
1228-
};
1282+
let liquidity_source = Arc::new(liquidity_source_builder.build());
1283+
let custom_message_handler =
1284+
Arc::new(NodeCustomMessageHandler::new_liquidity(Arc::clone(&liquidity_source)));
1285+
(Some(liquidity_source), custom_message_handler)
1286+
} else {
1287+
(None, Arc::new(NodeCustomMessageHandler::new_ignoring()))
1288+
};
12291289

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

src/liquidity.rs

+28-2
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;
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};
@@ -61,12 +62,19 @@ struct LSPS2Client {
6162
pending_buy_requests: Mutex<HashMap<RequestId, oneshot::Sender<LSPS2BuyResponse>>>,
6263
}
6364

65+
struct LSPS2Service {
66+
token: Option<String>,
67+
service_config: LSPS2ServiceConfig,
68+
advertise_service: bool,
69+
}
70+
6471
pub(crate) struct LiquiditySourceBuilder<L: Deref>
6572
where
6673
L::Target: LdkLogger,
6774
{
6875
lsps1_client: Option<LSPS1Client>,
6976
lsps2_client: Option<LSPS2Client>,
77+
lsps2_service: Option<LSPS2Service>,
7078
channel_manager: Arc<ChannelManager>,
7179
keys_manager: Arc<KeysManager>,
7280
chain_source: Arc<ChainSource>,
@@ -84,9 +92,11 @@ where
8492
) -> Self {
8593
let lsps1_client = None;
8694
let lsps2_client = None;
95+
let lsps2_service = None;
8796
Self {
8897
lsps1_client,
8998
lsps2_client,
99+
lsps2_service,
90100
channel_manager,
91101
keys_manager,
92102
chain_source,
@@ -132,7 +142,21 @@ where
132142
self
133143
}
134144

145+
pub(crate) fn lsps2_service(
146+
&mut self, promise_secret: [u8; 32], token: Option<String>, advertise_service: bool,
147+
) -> &mut Self {
148+
let service_config = LSPS2ServiceConfig { promise_secret };
149+
self.lsps2_service = Some(LSPS2Service { token, service_config, advertise_service });
150+
self
151+
}
152+
135153
pub(crate) fn build(self) -> LiquiditySource<L> {
154+
let liquidity_service_config = self.lsps2_service.as_ref().map(|s| {
155+
let lsps2_service_config = Some(s.service_config.clone());
156+
let advertise_service = s.advertise_service;
157+
LiquidityServiceConfig { lsps2_service_config, advertise_service }
158+
});
159+
136160
let lsps1_client_config = self.lsps1_client.as_ref().map(|s| s.client_config.clone());
137161
let lsps2_client_config = self.lsps2_client.as_ref().map(|s| s.client_config.clone());
138162
let liquidity_client_config =
@@ -143,13 +167,14 @@ where
143167
Arc::clone(&self.channel_manager),
144168
Some(Arc::clone(&self.chain_source)),
145169
None,
146-
None,
170+
liquidity_service_config,
147171
liquidity_client_config,
148172
));
149173

150174
LiquiditySource {
151175
lsps1_client: self.lsps1_client,
152176
lsps2_client: self.lsps2_client,
177+
lsps2_service: self.lsps2_service,
153178
channel_manager: self.channel_manager,
154179
keys_manager: self.keys_manager,
155180
liquidity_manager,
@@ -165,6 +190,7 @@ where
165190
{
166191
lsps1_client: Option<LSPS1Client>,
167192
lsps2_client: Option<LSPS2Client>,
193+
lsps2_service: Option<LSPS2Service>,
168194
channel_manager: Arc<ChannelManager>,
169195
keys_manager: Arc<KeysManager>,
170196
liquidity_manager: Arc<LiquidityManager>,

0 commit comments

Comments
 (0)