From 296a13ce2b3df7ab99427cbaed9b5d28fdaf0cc3 Mon Sep 17 00:00:00 2001 From: Elias Rohrer Date: Mon, 8 Jan 2024 08:30:04 +0100 Subject: [PATCH] Implement LSPS2 API methods --- src/lib.rs | 69 ++++++++++++++++++++++++++++++++++++++++++++++++ src/liquidity.rs | 7 +++++ 2 files changed, 76 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 5d2f90215..245a41585 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1574,6 +1574,75 @@ impl Node { Ok(invoice) } + /// Returns a payable invoice that can be used to request a payment of the amount given and + /// receive it via a newly created just-in-time (JIT) channel. + /// + /// When the returned invoice is paid, the configured [LSPS2]-compliant LSP will open a channel + /// to us, supplying just-in-time inbound liquidity. + /// + /// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md + pub fn receive_payment_via_jit_channel( + &self, amount_msat: u64, description: &str, expiry_secs: u32, + ) -> Result { + self.receive_payment_via_jit_channel_inner(Some(amount_msat), description, expiry_secs) + } + + /// Returns a payable invoice that can be used to request a variable amount payment (also known + /// as "zero-amount" invoice) and receive it via a newly created just-in-time (JIT) channel. + /// + /// When the returned invoice is paid, the configured [LSPS2]-compliant LSP will open a channel + /// to us, supplying just-in-time inbound liquidity. + /// + /// [LSPS2]: https://github.com/BitcoinAndLightningLayerSpecs/lsp/blob/main/LSPS2/README.md + pub fn receive_variable_amount_payment_via_jit_channel( + &self, description: &str, expiry_secs: u32, + ) -> Result { + self.receive_payment_via_jit_channel_inner(None, description, expiry_secs) + } + + fn receive_payment_via_jit_channel_inner( + &self, amount_msat: Option, description: &str, expiry_secs: u32, + ) -> Result { + let (node_id, address) = self + .liquidity_source + .get_liquidity_source_details() + .ok_or(Error::LiquiditySourceUnavailable)?; + + let rt_lock = self.runtime.read().unwrap(); + let runtime = rt_lock.as_ref().unwrap(); + + let peer_info = PeerInfo { node_id, address }; + + let con_node_id = peer_info.node_id; + let con_addr = peer_info.address.clone(); + let con_logger = Arc::clone(&self.logger); + let con_pm = Arc::clone(&self.peer_manager); + + // We need to use our main runtime here as a local runtime might not be around to poll + // connection futures going forward. + tokio::task::block_in_place(move || { + runtime.block_on(async move { + connect_peer_if_necessary(con_node_id, con_addr, con_pm, con_logger).await + }) + })?; + + log_info!(self.logger, "Connected to LSP {}@{}. ", peer_info.node_id, peer_info.address); + + let liquidity_source = Arc::clone(&self.liquidity_source); + let invoice = tokio::task::block_in_place(move || { + runtime.block_on(async move { + liquidity_source + .lsps2_receive_to_jit_channel(amount_msat, description, expiry_secs) + .await + }) + })?; + + // Persist LSP peer to make sure we reconnect on restart. + self.peer_store.add_peer(peer_info)?; + + Ok(invoice) + } + /// Retrieve the details of a specific payment with the given hash. /// /// Returns `Some` if the payment was known and `None` otherwise. diff --git a/src/liquidity.rs b/src/liquidity.rs index 73479768a..76796967a 100644 --- a/src/liquidity.rs +++ b/src/liquidity.rs @@ -86,6 +86,13 @@ where } } + pub(crate) fn get_liquidity_source_details(&self) -> Option<(PublicKey, SocketAddress)> { + match self { + Self::None => None, + Self::LSPS2 { node_id, address, .. } => Some((*node_id, address.clone())), + } + } + pub(crate) async fn handle_next_event(&self) { match self { Self::None => {}