Skip to content

Commit

Permalink
Allow to set LSPS1 liquidity source
Browse files Browse the repository at this point in the history
We add support for LSPS1 liquidity sources. To this end we slightly
refactor our logic to first create a `LiquiditySourceBuilder` that then
can be used to `build()` the `LiquiditySource` with the configured
services.
  • Loading branch information
tnull committed Aug 13, 2024
1 parent 9c79ade commit 99bc97a
Show file tree
Hide file tree
Showing 3 changed files with 152 additions and 40 deletions.
84 changes: 55 additions & 29 deletions src/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use crate::fee_estimator::OnchainFeeEstimator;
use crate::gossip::GossipSource;
use crate::io;
use crate::io::sqlite_store::SqliteStore;
use crate::liquidity::LiquiditySource;
use crate::liquidity::LiquiditySourceBuilder;
use crate::logger::{log_error, log_info, FilesystemLogger, Logger};
use crate::message_handler::NodeCustomMessageHandler;
use crate::payment::store::PaymentStore;
Expand Down Expand Up @@ -42,9 +42,6 @@ use lightning_persister::fs_store::FilesystemStore;

use lightning_transaction_sync::EsploraSyncClient;

use lightning_liquidity::lsps2::client::LSPS2ClientConfig;
use lightning_liquidity::{LiquidityClientConfig, LiquidityManager};

#[cfg(any(vss, vss_test))]
use crate::io::vss_store::VssStore;
use bdk::bitcoin::secp256k1::Secp256k1;
Expand Down Expand Up @@ -89,13 +86,15 @@ enum GossipSourceConfig {

#[derive(Debug, Clone)]
struct LiquiditySourceConfig {
// LSPS1 service's (node_id, address, token)
lsps1_service: Option<(PublicKey, SocketAddress, Option<String>)>,
// LSPS2 service's (node_id, address, token)
lsps2_service: Option<(PublicKey, SocketAddress, Option<String>)>,
}

impl Default for LiquiditySourceConfig {
fn default() -> Self {
Self { lsps2_service: None }
Self { lsps1_service: None, lsps2_service: None }
}
}

Expand Down Expand Up @@ -247,7 +246,26 @@ impl NodeBuilder {
self
}

/// Configures the [`Node`] instance to source its inbound liquidity from the given
/// Configures the [`Node`] instance to source inbound liquidity from the given
/// [LSPS1](https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS1/README.md)
/// service.
///
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
///
/// The given `token` will be used by the LSP to authenticate the user.
pub fn set_liquidity_source_lsps1(
&mut self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
) -> &mut Self {
// Mark the LSP as trusted for 0conf
self.config.trusted_peers_0conf.push(node_id.clone());

let liquidity_source_config =
self.liquidity_source_config.get_or_insert(LiquiditySourceConfig::default());
liquidity_source_config.lsps1_service = Some((node_id, address, token));
self
}

/// Configures the [`Node`] instance to source just-in-time inbound liquidity from the given
/// [LSPS2](https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md)
/// service.
///
Expand Down Expand Up @@ -459,7 +477,20 @@ impl ArcedNodeBuilder {
self.inner.write().unwrap().set_gossip_source_rgs(rgs_server_url);
}

/// Configures the [`Node`] instance to source its inbound liquidity from the given
/// Configures the [`Node`] instance to source inbound liquidity from the given
/// [LSPS1](https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS1/README.md)
/// service.
///
/// Will mark the LSP as trusted for 0-confirmation channels, see [`Config::trusted_peers_0conf`].
///
/// The given `token` will be used by the LSP to authenticate the user.
pub fn set_liquidity_source_lsps1(
&self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
) {
self.inner.write().unwrap().set_liquidity_source_lsps1(node_id, address, token);
}

/// Configures the [`Node`] instance to source just-in-time inbound liquidity from the given
/// [LSPS2](https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md)
/// service.
///
Expand Down Expand Up @@ -817,29 +848,24 @@ fn build_with_store_internal(
},
};

let liquidity_source = liquidity_source_config.as_ref().and_then(|lsc| {
let liquidity_source = liquidity_source_config.as_ref().map(|lsc| {
let mut liquidity_source_builder = LiquiditySourceBuilder::new(
Arc::clone(&channel_manager),
Arc::clone(&keys_manager),
Arc::clone(&tx_sync),
Arc::clone(&config),
Arc::clone(&logger),
);

lsc.lsps1_service.as_ref().map(|(node_id, address, token)| {
liquidity_source_builder.lsps1_service(*node_id, address.clone(), token.clone())
});

lsc.lsps2_service.as_ref().map(|(node_id, address, token)| {
let lsps2_client_config = Some(LSPS2ClientConfig {});
let liquidity_client_config = Some(LiquidityClientConfig { lsps2_client_config });
let liquidity_manager = Arc::new(LiquidityManager::new(
Arc::clone(&keys_manager),
Arc::clone(&channel_manager),
Some(Arc::clone(&tx_sync)),
None,
None,
liquidity_client_config,
));
Arc::new(LiquiditySource::new_lsps2(
*node_id,
address.clone(),
token.clone(),
Arc::clone(&channel_manager),
Arc::clone(&keys_manager),
liquidity_manager,
Arc::clone(&config),
Arc::clone(&logger),
))
})
liquidity_source_builder.lsps2_service(*node_id, address.clone(), token.clone())
});

Arc::new(liquidity_source_builder.build())
});

let custom_message_handler = if let Some(liquidity_source) = liquidity_source.as_ref() {
Expand Down
106 changes: 96 additions & 10 deletions src/liquidity.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::logger::{log_debug, log_error, log_info, Logger};
use crate::types::{ChannelManager, KeysManager, LiquidityManager, PeerManager};
use crate::types::{ChainSource, ChannelManager, KeysManager, LiquidityManager, PeerManager};
use crate::{Config, Error};

use lightning::ln::channelmanager::MIN_FINAL_CLTV_EXPIRY_DELTA;
Expand All @@ -8,9 +8,12 @@ use lightning::routing::router::{RouteHint, RouteHintHop};
use lightning_invoice::{Bolt11Invoice, InvoiceBuilder, RoutingFees};
use lightning_liquidity::events::Event;
use lightning_liquidity::lsps0::ser::RequestId;
use lightning_liquidity::lsps1::client::LSPS1ClientConfig;
use lightning_liquidity::lsps2::client::LSPS2ClientConfig;
use lightning_liquidity::lsps2::event::LSPS2ClientEvent;
use lightning_liquidity::lsps2::msgs::OpeningFeeParams;
use lightning_liquidity::lsps2::utils::compute_opening_fee;
use lightning_liquidity::LiquidityClientConfig;

use bitcoin::hashes::{sha256, Hash};
use bitcoin::secp256k1::{PublicKey, Secp256k1};
Expand All @@ -24,47 +27,126 @@ use std::time::Duration;

const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;

struct LSPS1Service {
node_id: PublicKey,
address: SocketAddress,
token: Option<String>,
client_config: LSPS1ClientConfig,
}

struct LSPS2Service {
node_id: PublicKey,
address: SocketAddress,
token: Option<String>,
client_config: LSPS2ClientConfig,
pending_fee_requests: Mutex<HashMap<RequestId, oneshot::Sender<LSPS2FeeResponse>>>,
pending_buy_requests: Mutex<HashMap<RequestId, oneshot::Sender<LSPS2BuyResponse>>>,
}

pub(crate) struct LiquiditySource<L: Deref>
pub(crate) struct LiquiditySourceBuilder<L: Deref>
where
L::Target: Logger,
{
lsps1_service: Option<LSPS1Service>,
lsps2_service: Option<LSPS2Service>,
channel_manager: Arc<ChannelManager>,
keys_manager: Arc<KeysManager>,
liquidity_manager: Arc<LiquidityManager>,
tx_sync: Arc<ChainSource>,
config: Arc<Config>,
logger: L,
}

impl<L: Deref> LiquiditySource<L>
impl<L: Deref> LiquiditySourceBuilder<L>
where
L::Target: Logger,
{
pub(crate) fn new_lsps2(
node_id: PublicKey, address: SocketAddress, token: Option<String>,
pub(crate) fn new(
channel_manager: Arc<ChannelManager>, keys_manager: Arc<KeysManager>,
liquidity_manager: Arc<LiquidityManager>, config: Arc<Config>, logger: L,
tx_sync: Arc<ChainSource>, config: Arc<Config>, logger: L,
) -> Self {
let lsps1_service = None;
let lsps2_service = None;
Self {
lsps1_service,
lsps2_service,
channel_manager,
keys_manager,
tx_sync,
config,
logger,
}
}

pub(crate) fn lsps1_service(
&mut self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
) -> &mut Self {
// TODO: allow to set max_channel_fees_msat
let client_config = LSPS1ClientConfig { max_channel_fees_msat: None };
self.lsps1_service = Some(LSPS1Service { node_id, address, token, client_config });
self
}

pub(crate) fn lsps2_service(
&mut self, node_id: PublicKey, address: SocketAddress, token: Option<String>,
) -> &mut Self {
let client_config = LSPS2ClientConfig {};
let pending_fee_requests = Mutex::new(HashMap::new());
let pending_buy_requests = Mutex::new(HashMap::new());
let lsps2_service = Some(LSPS2Service {
self.lsps2_service = Some(LSPS2Service {
node_id,
address,
token,
client_config,
pending_fee_requests,
pending_buy_requests,
});
Self { lsps2_service, channel_manager, keys_manager, liquidity_manager, config, logger }
self
}

pub(crate) fn build(self) -> LiquiditySource<L> {
let lsps1_client_config = self.lsps1_service.as_ref().map(|s| s.client_config.clone());
let lsps2_client_config = self.lsps2_service.as_ref().map(|s| s.client_config.clone());
let liquidity_client_config =
Some(LiquidityClientConfig { lsps1_client_config, lsps2_client_config });

let liquidity_manager = Arc::new(LiquidityManager::new(
Arc::clone(&self.keys_manager),
Arc::clone(&self.channel_manager),
Some(Arc::clone(&self.tx_sync)),
None,
None,
liquidity_client_config,
));

LiquiditySource {
lsps1_service: self.lsps1_service,
lsps2_service: self.lsps2_service,
channel_manager: self.channel_manager,
keys_manager: self.keys_manager,
liquidity_manager,
config: self.config,
logger: self.logger,
}
}
}

pub(crate) struct LiquiditySource<L: Deref>
where
L::Target: Logger,
{
lsps1_service: Option<LSPS1Service>,
lsps2_service: Option<LSPS2Service>,
channel_manager: Arc<ChannelManager>,
keys_manager: Arc<KeysManager>,
liquidity_manager: Arc<LiquidityManager>,
config: Arc<Config>,
logger: L,
}

impl<L: Deref> LiquiditySource<L>
where
L::Target: Logger,
{
pub(crate) fn set_peer_manager(&self, peer_manager: Arc<PeerManager>) {
let process_msgs_callback = move || peer_manager.process_events();
self.liquidity_manager.set_process_msgs_callback(process_msgs_callback);
Expand All @@ -74,7 +156,11 @@ where
self.liquidity_manager.as_ref()
}

pub(crate) fn get_liquidity_source_details(&self) -> Option<(PublicKey, SocketAddress)> {
pub(crate) fn get_lsps1_service_details(&self) -> Option<(PublicKey, SocketAddress)> {
self.lsps1_service.as_ref().map(|s| (s.node_id, s.address.clone()))
}

pub(crate) fn get_lsps2_service_details(&self) -> Option<(PublicKey, SocketAddress)> {
self.lsps2_service.as_ref().map(|s| (s.node_id, s.address.clone()))
}

Expand Down
2 changes: 1 addition & 1 deletion src/payment/bolt11.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,7 +550,7 @@ impl Bolt11Payment {
self.liquidity_source.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;

let (node_id, address) = liquidity_source
.get_liquidity_source_details()
.get_lsps2_service_details()
.ok_or(Error::LiquiditySourceUnavailable)?;

let rt_lock = self.runtime.read().unwrap();
Expand Down

0 comments on commit 99bc97a

Please sign in to comment.