Skip to content

Commit 3e0f6ee

Browse files
committed
Allow configuring LSPS2 service via builders
We add the capability to configure LSPS2 service mode in `Builder` and `LiquiditySourceBuilder`.
1 parent 82f28a7 commit 3e0f6ee

File tree

4 files changed

+152
-34
lines changed

4 files changed

+152
-34
lines changed

bindings/ldk_node.udl

+12
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,18 @@ dictionary EsploraSyncConfig {
2525
u64 fee_rate_cache_update_interval_secs;
2626
};
2727

28+
dictionary LSPS2ServiceConfig {
29+
string? require_token;
30+
boolean advertise_service;
31+
u32 channel_opening_fee_ppm;
32+
u32 channel_over_provisioning_ppm;
33+
u64 min_channel_opening_fee_msat;
34+
u32 min_channel_lifetime;
35+
u32 max_client_to_self_delay;
36+
u64 min_payment_size_msat;
37+
u64 max_payment_size_msat;
38+
};
39+
2840
enum LogLevel {
2941
"Gossip",
3042
"Trace",

src/builder.rs

+74-31
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ use crate::gossip::GossipSource;
1818
use crate::io::sqlite_store::SqliteStore;
1919
use crate::io::utils::{read_node_metrics, write_node_metrics};
2020
use crate::io::vss_store::VssStore;
21-
use crate::liquidity::{LSPS1ClientConfig, LSPS2ClientConfig, LiquiditySourceBuilder};
21+
use crate::liquidity::{
22+
LSPS1ClientConfig, LSPS2ClientConfig, LSPS2ServiceConfig, LiquiditySourceBuilder,
23+
};
2224
use crate::logger::{log_error, log_info, LdkLogger, LogLevel, LogWriter, Logger};
2325
use crate::message_handler::NodeCustomMessageHandler;
2426
use crate::payment::store::PaymentStore;
@@ -77,6 +79,7 @@ use vss_client::headers::{FixedHeaders, LnurlAuthToJwtProvider, VssHeaderProvide
7779

7880
const VSS_HARDENED_CHILD_INDEX: u32 = 877;
7981
const VSS_LNURL_AUTH_HARDENED_CHILD_INDEX: u32 = 138;
82+
const LSPS_HARDENED_CHILD_INDEX: u32 = 577;
8083

8184
#[derive(Debug, Clone)]
8285
enum ChainDataSourceConfig {
@@ -103,6 +106,8 @@ struct LiquiditySourceConfig {
103106
lsps1_client: Option<LSPS1ClientConfig>,
104107
// Act as an LSPS2 client connecting to the given service.
105108
lsps2_client: Option<LSPS2ClientConfig>,
109+
// Act as an LSPS2 service.
110+
lsps2_service: Option<LSPS2ServiceConfig>,
106111
}
107112

108113
#[derive(Clone)]
@@ -342,6 +347,21 @@ impl NodeBuilder {
342347
self
343348
}
344349

350+
/// Configures the [`Node`] instance to provide an [LSPS2] service, issuing just-in-time
351+
/// channels to clients.
352+
///
353+
/// **Caution**: LSP service support is in **alpha** and is considered an experimental feature.
354+
///
355+
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
356+
pub fn set_liquidity_provider_lsps2(
357+
&mut self, service_config: LSPS2ServiceConfig,
358+
) -> &mut Self {
359+
let liquidity_source_config =
360+
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
361+
liquidity_source_config.lsps2_service = Some(service_config);
362+
self
363+
}
364+
345365
/// Sets the used storage directory path.
346366
pub fn set_storage_dir_path(&mut self, storage_dir_path: String) -> &mut Self {
347367
self.config.storage_dir_path = storage_dir_path;
@@ -699,6 +719,16 @@ impl ArcedNodeBuilder {
699719
self.inner.write().unwrap().set_liquidity_source_lsps2(node_id, address, token);
700720
}
701721

722+
/// Configures the [`Node`] instance to provide an [LSPS2] service, issuing just-in-time
723+
/// channels to clients.
724+
///
725+
/// **Caution**: LSP service support is in **alpha** and is considered an experimental feature.
726+
///
727+
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
728+
pub fn set_liquidity_provider_lsps2(&self, service_config: LSPS2ServiceConfig) {
729+
self.inner.write().unwrap().set_liquidity_provider_lsps2(service_config);
730+
}
731+
702732
/// Sets the used storage directory path.
703733
pub fn set_storage_dir_path(&self, storage_dir_path: String) {
704734
self.inner.write().unwrap().set_storage_dir_path(storage_dir_path);
@@ -1179,39 +1209,52 @@ fn build_with_store_internal(
11791209
},
11801210
};
11811211

1182-
let liquidity_source = liquidity_source_config.as_ref().map(|lsc| {
1183-
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
1184-
Arc::clone(&channel_manager),
1185-
Arc::clone(&keys_manager),
1186-
Arc::clone(&chain_source),
1187-
Arc::clone(&config),
1188-
Arc::clone(&logger),
1189-
);
1190-
1191-
lsc.lsps1_client.as_ref().map(|config| {
1192-
liquidity_source_builder.lsps1_client(
1193-
config.node_id,
1194-
config.address.clone(),
1195-
config.token.clone(),
1196-
)
1197-
});
1212+
let (liquidity_source, custom_message_handler) =
1213+
if let Some(lsc) = liquidity_source_config.as_ref() {
1214+
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
1215+
Arc::clone(&channel_manager),
1216+
Arc::clone(&keys_manager),
1217+
Arc::clone(&chain_source),
1218+
Arc::clone(&config),
1219+
Arc::clone(&logger),
1220+
);
11981221

1199-
lsc.lsps2_client.as_ref().map(|config| {
1200-
liquidity_source_builder.lsps2_client(
1201-
config.node_id,
1202-
config.address.clone(),
1203-
config.token.clone(),
1204-
)
1205-
});
1222+
lsc.lsps1_client.as_ref().map(|config| {
1223+
liquidity_source_builder.lsps1_client(
1224+
config.node_id,
1225+
config.address.clone(),
1226+
config.token.clone(),
1227+
)
1228+
});
12061229

1207-
Arc::new(liquidity_source_builder.build())
1208-
});
1230+
lsc.lsps2_client.as_ref().map(|config| {
1231+
liquidity_source_builder.lsps2_client(
1232+
config.node_id,
1233+
config.address.clone(),
1234+
config.token.clone(),
1235+
)
1236+
});
12091237

1210-
let custom_message_handler = if let Some(liquidity_source) = liquidity_source.as_ref() {
1211-
Arc::new(NodeCustomMessageHandler::new_liquidity(Arc::clone(&liquidity_source)))
1212-
} else {
1213-
Arc::new(NodeCustomMessageHandler::new_ignoring())
1214-
};
1238+
let promise_secret = {
1239+
let lsps_xpriv = derive_xprv(
1240+
Arc::clone(&config),
1241+
&seed_bytes,
1242+
LSPS_HARDENED_CHILD_INDEX,
1243+
Arc::clone(&logger),
1244+
)?;
1245+
lsps_xpriv.private_key.secret_bytes()
1246+
};
1247+
lsc.lsps2_service.as_ref().map(|config| {
1248+
liquidity_source_builder.lsps2_service(promise_secret, config.clone())
1249+
});
1250+
1251+
let liquidity_source = Arc::new(liquidity_source_builder.build());
1252+
let custom_message_handler =
1253+
Arc::new(NodeCustomMessageHandler::new_liquidity(Arc::clone(&liquidity_source)));
1254+
(Some(liquidity_source), custom_message_handler)
1255+
} else {
1256+
(None, Arc::new(NodeCustomMessageHandler::new_ignoring()))
1257+
};
12151258

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

src/liquidity.rs

+65-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 as LdkLSPS2ClientConfig;
2626
use lightning_liquidity::lsps2::event::LSPS2ClientEvent;
2727
use lightning_liquidity::lsps2::msgs::OpeningFeeParams;
28+
use lightning_liquidity::lsps2::service::LSPS2ServiceConfig as LdkLSPS2ServiceConfig;
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,56 @@ pub(crate) struct LSPS2ClientConfig {
7576
pub token: Option<String>,
7677
}
7778

79+
struct LSPS2Service {
80+
service_config: LSPS2ServiceConfig,
81+
ldk_service_config: LdkLSPS2ServiceConfig,
82+
}
83+
84+
/// Represents the configuration of the LSPS2 service.
85+
///
86+
/// See [bLIP-52 / LSPS2] for more information.
87+
///
88+
/// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
89+
#[derive(Debug, Clone)]
90+
pub struct LSPS2ServiceConfig {
91+
/// A token we may require to be sent by the clients.
92+
///
93+
/// If set, only requests matching this token will be accepted.
94+
pub require_token: Option<String>,
95+
/// Indicates whether the LSPS service will be announced via the gossip network.
96+
pub advertise_service: bool,
97+
/// The fee we withhold for the channel open from the initial payment.
98+
///
99+
/// This fee is proportional to the client-requested amount, in parts-per-million.
100+
pub channel_opening_fee_ppm: u32,
101+
/// The proportional overprovisioning for the channel.
102+
///
103+
/// This determines, in parts-per-million, how much value we'll provision on top of the amount
104+
/// we need to forward the payment to the client.
105+
///
106+
/// For example, setting this to `100_000` will result in a channel being opened that is 10%
107+
/// larger than then the to-be-forwarded amount (i.e., client-requested amount minus the
108+
/// channel opening fee fee).
109+
pub channel_over_provisioning_ppm: u32,
110+
/// The minimum fee required for opening a channel.
111+
pub min_channel_opening_fee_msat: u64,
112+
/// The minimum number of blocks after confirmation we promise to keep the channel open.
113+
pub min_channel_lifetime: u32,
114+
/// The maximum number of blocks that the client is allowed to set its `to_self_delay` parameter.
115+
pub max_client_to_self_delay: u32,
116+
/// The minimum payment size that we will accept when opening a channel.
117+
pub min_payment_size_msat: u64,
118+
/// The maximum payment size that we will accept when opening a channel.
119+
pub max_payment_size_msat: u64,
120+
}
121+
78122
pub(crate) struct LiquiditySourceBuilder<L: Deref>
79123
where
80124
L::Target: LdkLogger,
81125
{
82126
lsps1_client: Option<LSPS1Client>,
83127
lsps2_client: Option<LSPS2Client>,
128+
lsps2_service: Option<LSPS2Service>,
84129
channel_manager: Arc<ChannelManager>,
85130
keys_manager: Arc<KeysManager>,
86131
chain_source: Arc<ChainSource>,
@@ -98,9 +143,11 @@ where
98143
) -> Self {
99144
let lsps1_client = None;
100145
let lsps2_client = None;
146+
let lsps2_service = None;
101147
Self {
102148
lsps1_client,
103149
lsps2_client,
150+
lsps2_service,
104151
channel_manager,
105152
keys_manager,
106153
chain_source,
@@ -146,7 +193,21 @@ where
146193
self
147194
}
148195

196+
pub(crate) fn lsps2_service(
197+
&mut self, promise_secret: [u8; 32], service_config: LSPS2ServiceConfig,
198+
) -> &mut Self {
199+
let ldk_service_config = LdkLSPS2ServiceConfig { promise_secret };
200+
self.lsps2_service = Some(LSPS2Service { service_config, ldk_service_config });
201+
self
202+
}
203+
149204
pub(crate) fn build(self) -> LiquiditySource<L> {
205+
let liquidity_service_config = self.lsps2_service.as_ref().map(|s| {
206+
let lsps2_service_config = Some(s.ldk_service_config.clone());
207+
let advertise_service = s.service_config.advertise_service;
208+
LiquidityServiceConfig { lsps2_service_config, advertise_service }
209+
});
210+
150211
let lsps1_client_config = self.lsps1_client.as_ref().map(|s| s.ldk_client_config.clone());
151212
let lsps2_client_config = self.lsps2_client.as_ref().map(|s| s.ldk_client_config.clone());
152213
let liquidity_client_config =
@@ -157,13 +218,14 @@ where
157218
Arc::clone(&self.channel_manager),
158219
Some(Arc::clone(&self.chain_source)),
159220
None,
160-
None,
221+
liquidity_service_config,
161222
liquidity_client_config,
162223
));
163224

164225
LiquiditySource {
165226
lsps1_client: self.lsps1_client,
166227
lsps2_client: self.lsps2_client,
228+
lsps2_service: self.lsps2_service,
167229
channel_manager: self.channel_manager,
168230
keys_manager: self.keys_manager,
169231
liquidity_manager,
@@ -179,6 +241,7 @@ where
179241
{
180242
lsps1_client: Option<LSPS1Client>,
181243
lsps2_client: Option<LSPS2Client>,
244+
lsps2_service: Option<LSPS2Service>,
182245
channel_manager: Arc<ChannelManager>,
183246
keys_manager: Arc<KeysManager>,
184247
liquidity_manager: Arc<LiquidityManager>,

src/uniffi_types.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ pub use crate::config::{
1414
default_config, AnchorChannelsConfig, EsploraSyncConfig, MaxDustHTLCExposure,
1515
};
1616
pub use crate::graph::{ChannelInfo, ChannelUpdateInfo, NodeAnnouncementInfo, NodeInfo};
17-
pub use crate::liquidity::{LSPS1OrderStatus, OnchainPaymentInfo, PaymentInfo};
17+
pub use crate::liquidity::{LSPS1OrderStatus, LSPS2ServiceConfig, OnchainPaymentInfo, PaymentInfo};
1818
pub use crate::logger::{LogLevel, LogRecord, LogWriter};
1919
pub use crate::payment::store::{
2020
ConfirmationStatus, LSPFeeLimits, PaymentDirection, PaymentKind, PaymentStatus,

0 commit comments

Comments
 (0)