Skip to content

Commit 988ba66

Browse files
committed
Refactor liquidity source to support multiple LSP nodes
Replace per-protocol single-LSP configuration `LSPS1Client` and `LSPS2Client` with a unified `Vec<LspNode>` model where users configure LSP nodes via `add_liquidity_source()` at build time or runtime and per-LSP protocol support is discovered via the LSPS0 `list_protocols`. - Introduce a per-LSP `trust_peer_0conf` flag to `LspConfig`/`LspNode` structs that controls whether 0-conf channels from that LSP are accepted - Add LSPS0 protocol discovery `discover_lsp_protocols` with event handling for `ListProtocolsResponse` - Update events to also use each LSP's `trust_peer_0conf` flag when deciding whether to allow 0-conf channels - Replace `set_liquidity_source_lsps1` and `set_liquidity_source_lsps2` builder methods with a single `add_liquidity_source()` that takes a `trust_peer_0conf` flag - Rename `set_liquidity_provider_lsps2` to `enable_liquidity_provider` - LSPS2 JIT channels now query all LSPS2-capable LSPs and automatically select the cheapest fee offer across all of them - Spawn background discovery task on `Node::start()` and expose a watch channel so dependent flows can wait for discovery to complete - Add a new `Liquidity` handler `Node::liquidity()` exposing `add_liquidity_source()` API for adding LSPs at runtime, and `lsps1()` for the existing LSPS1 surface
1 parent 96ba539 commit 988ba66

12 files changed

Lines changed: 1838 additions & 1293 deletions

File tree

bindings/ldk_node.udl

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -43,8 +43,7 @@ interface Builder {
4343
void set_gossip_source_p2p();
4444
void set_gossip_source_rgs(string rgs_server_url);
4545
void set_pathfinding_scores_source(string url);
46-
void set_liquidity_source_lsps1(PublicKey node_id, SocketAddress address, string? token);
47-
void set_liquidity_source_lsps2(PublicKey node_id, SocketAddress address, string? token);
46+
void add_liquidity_source(PublicKey node_id, SocketAddress address, string? token, boolean trust_peer_0conf);
4847
void set_storage_dir_path(string storage_dir_path);
4948
void set_filesystem_logger(string? log_file_path, LogLevel? max_log_level);
5049
void set_log_facade_logger();
@@ -99,7 +98,7 @@ interface Node {
9998
SpontaneousPayment spontaneous_payment();
10099
OnchainPayment onchain_payment();
101100
UnifiedPayment unified_payment();
102-
LSPS1Liquidity lsps1_liquidity();
101+
Liquidity liquidity();
103102
[Throws=NodeError]
104103
void lnurl_auth(string lnurl);
105104
[Throws=NodeError]
@@ -167,7 +166,7 @@ interface FeeRate {
167166

168167
typedef interface UnifiedPayment;
169168

170-
typedef interface LSPS1Liquidity;
169+
typedef interface Liquidity;
171170

172171
[Error]
173172
enum NodeError {
@@ -275,6 +274,7 @@ dictionary LSPS1OrderStatus {
275274
LSPS1OrderParams order_params;
276275
LSPS1PaymentInfo payment_options;
277276
LSPS1ChannelInfo? channel_state;
277+
PublicKey counterparty_node_id;
278278
};
279279

280280
[Remote]

src/builder.rs

Lines changed: 65 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,7 @@ use crate::io::{
6868
PENDING_PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE,
6969
PENDING_PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE,
7070
};
71-
use crate::liquidity::{
72-
LSPS1ClientConfig, LSPS2ClientConfig, LSPS2ServiceConfig, LiquiditySourceBuilder,
73-
};
71+
use crate::liquidity::{LSPS2ServiceConfig, LiquiditySourceBuilder, LspConfig};
7472
use crate::lnurl_auth::LnurlAuth;
7573
use crate::logger::{log_error, LdkLogger, LogLevel, LogWriter, Logger};
7674
use crate::message_handler::NodeCustomMessageHandler;
@@ -123,10 +121,8 @@ struct PathfindingScoresSyncConfig {
123121

124122
#[derive(Debug, Clone, Default)]
125123
struct LiquiditySourceConfig {
126-
// Act as an LSPS1 client connecting to the given service.
127-
lsps1_client: Option<LSPS1ClientConfig>,
128-
// Act as an LSPS2 client connecting to the given service.
129-
lsps2_client: Option<LSPS2ClientConfig>,
124+
// Acts for both LSPS1 and LSPS2 clients connecting to the given service.
125+
lsp_nodes: Vec<LspConfig>,
130126
// Act as an LSPS2 service.
131127
lsps2_service: Option<LSPS2ServiceConfig>,
132128
}
@@ -443,45 +439,36 @@ impl NodeBuilder {
443439
self
444440
}
445441

446-
/// Configures the [`Node`] instance to source inbound liquidity from the given
447-
/// [bLIP-51 / LSPS1] service.
442+
/// Configures the [`Node`] instance to source inbound liquidity from the given LSP.
448443
///
449-
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
444+
/// The node will discover the LSP's supported protocols (LSPS1/LSPS2) on startup via [bLIP-50 / LSPS0]
445+
/// and select the appropriate protocol per request automatically.
450446
///
451447
/// The given `token` will be used by the LSP to authenticate the user.
448+
/// `trust_peer_0conf` controls whether the node will additionally accept
449+
/// 0-confirmation channels opened by this LSP. If `false`, 0-confirmation
450+
/// acceptance for this peer falls back to [`Config::trusted_peers_0conf`].
451+
///
452+
/// May be called multiple times to register several LSPs. Duplicate `node_id`s are ignored.
452453
///
453-
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
454-
pub fn set_liquidity_source_lsps1(
454+
/// [bLIP-50 / LSPS0]: https://github.com/lightning/blips/blob/master/blip-0050.md
455+
pub fn add_liquidity_source(
455456
&mut self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
457+
trust_peer_0conf: bool,
456458
) -> &mut Self {
457-
// Mark the LSP as trusted for 0conf
458-
self.config.trusted_peers_0conf.push(node_id.clone());
459-
460459
let liquidity_source_config =
461460
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
462-
let lsps1_client_config = LSPS1ClientConfig { node_id, address, token };
463-
liquidity_source_config.lsps1_client = Some(lsps1_client_config);
464-
self
465-
}
466461

467-
/// Configures the [`Node`] instance to source just-in-time inbound liquidity from the given
468-
/// [bLIP-52 / LSPS2] service.
469-
///
470-
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
471-
///
472-
/// The given `token` will be used by the LSP to authenticate the user.
473-
///
474-
/// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
475-
pub fn set_liquidity_source_lsps2(
476-
&mut self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
477-
) -> &mut Self {
478-
// Mark the LSP as trusted for 0conf
479-
self.config.trusted_peers_0conf.push(node_id.clone());
462+
if liquidity_source_config.lsp_nodes.iter().any(|n| n.node_id == node_id) {
463+
return self;
464+
}
480465

481-
let liquidity_source_config =
482-
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
483-
let lsps2_client_config = LSPS2ClientConfig { node_id, address, token };
484-
liquidity_source_config.lsps2_client = Some(lsps2_client_config);
466+
liquidity_source_config.lsp_nodes.push(LspConfig {
467+
node_id,
468+
address,
469+
token,
470+
trust_peer_0conf,
471+
});
485472
self
486473
}
487474

@@ -491,12 +478,12 @@ impl NodeBuilder {
491478
/// **Caution**: LSP service support is in **alpha** and is considered an experimental feature.
492479
///
493480
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
494-
pub fn set_liquidity_provider_lsps2(
495-
&mut self, service_config: LSPS2ServiceConfig,
481+
pub fn enable_liquidity_provider(
482+
&mut self, lsps2_service_config: LSPS2ServiceConfig,
496483
) -> &mut Self {
497484
let liquidity_source_config =
498485
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
499-
liquidity_source_config.lsps2_service = Some(service_config);
486+
liquidity_source_config.lsps2_service = Some(lsps2_service_config);
500487
self
501488
}
502489

@@ -1032,32 +1019,29 @@ impl ArcedNodeBuilder {
10321019
self.inner.write().expect("lock").set_pathfinding_scores_source(url);
10331020
}
10341021

1035-
/// Configures the [`Node`] instance to source inbound liquidity from the given
1036-
/// [bLIP-51 / LSPS1] service.
1022+
/// Configures the [`Node`] instance to source inbound liquidity from the given LSP.
10371023
///
1038-
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
1024+
/// The node will discover the LSP's supported protocols (LSPS1/LSPS2) on startup via [bLIP-50 / LSPS0]
1025+
/// and select the appropriate protocol per request automatically.
10391026
///
10401027
/// The given `token` will be used by the LSP to authenticate the user.
1028+
/// `trust_peer_0conf` controls whether the node will additionally accept
1029+
/// 0-confirmation channels opened by this LSP. If `false`, 0-confirmation
1030+
/// acceptance for this peer falls back to [`Config::trusted_peers_0conf`].
10411031
///
1042-
/// [bLIP-51 / LSPS1]: https://github.com/lightning/blips/blob/master/blip-0051.md
1043-
pub fn set_liquidity_source_lsps1(
1044-
&self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
1045-
) {
1046-
self.inner.write().expect("lock").set_liquidity_source_lsps1(node_id, address, token);
1047-
}
1048-
1049-
/// Configures the [`Node`] instance to source just-in-time inbound liquidity from the given
1050-
/// [bLIP-52 / LSPS2] service.
1051-
///
1052-
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
1053-
///
1054-
/// The given `token` will be used by the LSP to authenticate the user.
1032+
/// May be called multiple times to register several LSPs. Duplicate `node_id`s are ignored.
10551033
///
1056-
/// [bLIP-52 / LSPS2]: https://github.com/lightning/blips/blob/master/blip-0052.md
1057-
pub fn set_liquidity_source_lsps2(
1034+
/// [bLIP-50 / LSPS0]: https://github.com/lightning/blips/blob/master/blip-0050.md
1035+
pub fn add_liquidity_source(
10581036
&self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
1037+
trust_peer_0conf: bool,
10591038
) {
1060-
self.inner.write().expect("lock").set_liquidity_source_lsps2(node_id, address, token);
1039+
self.inner.write().expect("lock").add_liquidity_source(
1040+
node_id,
1041+
address,
1042+
token,
1043+
trust_peer_0conf,
1044+
);
10611045
}
10621046

10631047
/// Configures the [`Node`] instance to provide an [LSPS2] service, issuing just-in-time
@@ -1066,8 +1050,8 @@ impl ArcedNodeBuilder {
10661050
/// **Caution**: LSP service support is in **alpha** and is considered an experimental feature.
10671051
///
10681052
/// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md
1069-
pub fn set_liquidity_provider_lsps2(&self, service_config: LSPS2ServiceConfig) {
1070-
self.inner.write().expect("lock").set_liquidity_provider_lsps2(service_config);
1053+
pub fn enable_liquidity_provider(&self, lsps2_service_config: LSPS2ServiceConfig) {
1054+
self.inner.write().expect("lock").enable_liquidity_provider(lsps2_service_config);
10711055
}
10721056

10731057
/// Sets the used storage directory path.
@@ -1975,33 +1959,19 @@ fn build_with_store_internal(
19751959
},
19761960
};
19771961

1978-
let (liquidity_source, custom_message_handler) =
1979-
if let Some(lsc) = liquidity_source_config.as_ref() {
1980-
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
1981-
Arc::clone(&wallet),
1982-
Arc::clone(&channel_manager),
1983-
Arc::clone(&keys_manager),
1984-
Arc::clone(&tx_broadcaster),
1985-
Arc::clone(&kv_store),
1986-
Arc::clone(&config),
1987-
Arc::clone(&logger),
1988-
);
1989-
1990-
lsc.lsps1_client.as_ref().map(|config| {
1991-
liquidity_source_builder.lsps1_client(
1992-
config.node_id,
1993-
config.address.clone(),
1994-
config.token.clone(),
1995-
)
1996-
});
1962+
let (liquidity_source, custom_message_handler) = {
1963+
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
1964+
Arc::clone(&wallet),
1965+
Arc::clone(&channel_manager),
1966+
Arc::clone(&keys_manager),
1967+
Arc::clone(&tx_broadcaster),
1968+
Arc::clone(&kv_store),
1969+
Arc::clone(&config),
1970+
Arc::clone(&logger),
1971+
);
19971972

1998-
lsc.lsps2_client.as_ref().map(|config| {
1999-
liquidity_source_builder.lsps2_client(
2000-
config.node_id,
2001-
config.address.clone(),
2002-
config.token.clone(),
2003-
)
2004-
});
1973+
if let Some(lsc) = liquidity_source_config.as_ref() {
1974+
liquidity_source_builder.set_lsp_nodes(lsc.lsp_nodes.clone());
20051975

20061976
let promise_secret = {
20071977
let lsps_xpriv = derive_xprv(
@@ -2015,15 +1985,15 @@ fn build_with_store_internal(
20151985
lsc.lsps2_service.as_ref().map(|config| {
20161986
liquidity_source_builder.lsps2_service(promise_secret, config.clone())
20171987
});
1988+
}
20181989

2019-
let liquidity_source = runtime
2020-
.block_on(async move { liquidity_source_builder.build().await.map(Arc::new) })?;
2021-
let custom_message_handler =
2022-
Arc::new(NodeCustomMessageHandler::new_liquidity(Arc::clone(&liquidity_source)));
2023-
(Some(liquidity_source), custom_message_handler)
2024-
} else {
2025-
(None, Arc::new(NodeCustomMessageHandler::new_ignoring()))
2026-
};
1990+
let liquidity_source = runtime
1991+
.block_on(async move { liquidity_source_builder.build().await.map(Arc::new) })?;
1992+
let custom_message_handler =
1993+
Arc::new(NodeCustomMessageHandler::new_liquidity(Arc::clone(&liquidity_source)));
1994+
1995+
(liquidity_source, custom_message_handler)
1996+
};
20271997

20281998
let msg_handler = match gossip_source.as_gossip_sync() {
20291999
GossipSync::P2P(p2p_gossip_sync) => MessageHandler {
@@ -2072,7 +2042,7 @@ fn build_with_store_internal(
20722042
}));
20732043
}
20742044

2075-
liquidity_source.as_ref().map(|l| l.set_peer_manager(Arc::downgrade(&peer_manager)));
2045+
liquidity_source.lsps2_service().set_peer_manager(Arc::downgrade(&peer_manager));
20762046

20772047
let connection_manager = Arc::new(ConnectionManager::new(
20782048
Arc::clone(&peer_manager),

0 commit comments

Comments
 (0)