Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions bindings/ldk_node.udl
Original file line numberDiff line numberDiff line change
Expand Up@@ -44,6 +44,7 @@ dictionary LSPS2ServiceConfig {
u32 max_client_to_self_delay;
u64 min_payment_size_msat;
u64 max_payment_size_msat;
boolean client_trusts_lsp;
};

enum LogLevel {
Expand Down
54 changes: 42 additions & 12 deletions src/event.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -491,7 +491,7 @@ where
counterparty_node_id,
channel_value_satoshis,
output_script,
..
user_channel_id,
} => {
// Construct the raw transaction with the output that is paid the amount of the
// channel.
Expand All@@ -510,16 +510,44 @@ where
locktime,
) {
Ok(final_tx) => {
// Give the funding transaction back to LDK for opening the channel.
match self.channel_manager.funding_transaction_generated(
temporary_channel_id,
counterparty_node_id,
final_tx,
) {
let needs_manual_broadcast =
Comment thread
tnull marked this conversation as resolved.
self.liquidity_source.as_ref().map_or(false, |ls| {
Comment thread
joostjager marked this conversation as resolved.
ls.as_ref().lsps2_channel_needs_manual_broadcast(
counterparty_node_id,
user_channel_id,
)
});

let result = if needs_manual_broadcast {
self.liquidity_source.as_ref().map(|ls| {
ls.lsps2_store_funding_transaction(
user_channel_id,
counterparty_node_id,
final_tx.clone(),
);
});
self.channel_manager.funding_transaction_generated_manual_broadcast(
temporary_channel_id,
counterparty_node_id,
final_tx,
)
} else {
self.channel_manager.funding_transaction_generated(
temporary_channel_id,
counterparty_node_id,
final_tx,
)
};

match result {
Ok(()) => {},
Err(APIError::APIMisuseError { err }) => {
log_error!(self.logger, "Panicking due to APIMisuseError: {}", err);
panic!("APIMisuseError: {}", err);
log_error!(
self.logger,
"Encountered APIMisuseError, this should never happen: {}",
err
);
debug_assert!(false, "APIMisuseError: {}", err);
},
Err(APIError::ChannelUnavailable { err }) => {
log_error!(
Expand DownExpand Up@@ -547,15 +575,17 @@ where
)
.unwrap_or_else(|e| {
log_error!(self.logger, "Failed to force close channel after funding generation failed: {:?}", e);
panic!(
debug_assert!(false,
"Failed to force close channel after funding generation failed"
);
});
},
}
},
LdkEvent::FundingTxBroadcastSafe { .. } => {
debug_assert!(false, "We currently only support safe funding, so this event should never be emitted.");
LdkEvent::FundingTxBroadcastSafe { user_channel_id, counterparty_node_id, .. } => {
self.liquidity_source.as_ref().map(|ls| {
ls.lsps2_funding_tx_broadcast_safe(user_channel_id, counterparty_node_id);
});
},
LdkEvent::PaymentClaimable {
payment_hash,
Expand Down
73 changes: 71 additions & 2 deletions src/liquidity.rs
Original file line numberDiff line numberDiff line change
Expand Up@@ -14,6 +14,7 @@ use std::time::Duration;

use bitcoin::hashes::{sha256, Hash};
use bitcoin::secp256k1::{PublicKey, Secp256k1};
use bitcoin::Transaction;
use chrono::Utc;
use lightning::events::HTLCHandlingFailureType;
use lightning::ln::channelmanager::{InterceptId, MIN_FINAL_CLTV_EXPIRY_DELTA};
Expand DownExpand Up@@ -51,7 +52,6 @@ use crate::{total_anchor_channels_reserve_sats, Config, Error};
const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;

const LSPS2_GETINFO_REQUEST_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
const LSPS2_CLIENT_TRUSTS_LSP_MODE: bool = true;
const LSPS2_CHANNEL_CLTV_EXPIRY_DELTA: u32 = 72;

struct LSPS1Client {
Expand DownExpand Up@@ -130,6 +130,8 @@ pub struct LSPS2ServiceConfig {
pub min_payment_size_msat: u64,
/// The maximum payment size that we will accept when opening a channel.
pub max_payment_size_msat: u64,
/// Use the client trusts lsp model
pub client_trusts_lsp: bool,
}

pub(crate) struct LiquiditySourceBuilder<L: Deref>
Expand DownExpand Up@@ -305,6 +307,73 @@ where
self.lsps2_client.as_ref().map(|s| (s.lsp_node_id, s.lsp_address.clone()))
}

pub(crate) fn lsps2_channel_needs_manual_broadcast(
&self, counterparty_node_id: PublicKey, user_channel_id: u128,
) -> bool {
self.lsps2_service.as_ref().map_or(false, |lsps2_service| {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same q about error logging.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See above, I think continuing and just logging on the manual-broadcast step is preferable.

lsps2_service.service_config.client_trusts_lsp
&& self
.liquidity_manager()
.lsps2_service_handler()
.and_then(|handler| {
handler
.channel_needs_manual_broadcast(user_channel_id, &counterparty_node_id)
.ok()
})
.unwrap_or(false)
})
}

pub(crate) fn lsps2_store_funding_transaction(
Comment thread
tnull marked this conversation as resolved.
&self, user_channel_id: u128, counterparty_node_id: PublicKey, funding_tx: Transaction,
) {
if self.lsps2_service.as_ref().map_or(false, |svc| !svc.service_config.client_trusts_lsp) {
// Only necessary for client-trusts-LSP flow
return;
}

let lsps2_service_handler = self.liquidity_manager.lsps2_service_handler();
if let Some(handler) = lsps2_service_handler {
handler
.store_funding_transaction(user_channel_id, &counterparty_node_id, funding_tx)
.unwrap_or_else(|e| {
debug_assert!(false, "Failed to store funding transaction: {:?}", e);
log_error!(self.logger, "Failed to store funding transaction: {:?}", e);
});
} else {
log_error!(self.logger, "LSPS2 service handler is not available.");
}
}

pub(crate) fn lsps2_funding_tx_broadcast_safe(
&self, user_channel_id: u128, counterparty_node_id: PublicKey,
) {
if self.lsps2_service.as_ref().map_or(false, |svc| !svc.service_config.client_trusts_lsp) {
// Only necessary for client-trusts-LSP flow
return;
}

let lsps2_service_handler = self.liquidity_manager.lsps2_service_handler();
if let Some(handler) = lsps2_service_handler {
handler
.set_funding_tx_broadcast_safe(user_channel_id, &counterparty_node_id)
.unwrap_or_else(|e| {
debug_assert!(
false,
"Failed to mark funding transaction safe to broadcast: {:?}",
e
);
log_error!(
self.logger,
"Failed to mark funding transaction safe to broadcast: {:?}",
e
);
});
} else {
log_error!(self.logger, "LSPS2 service handler is not available.");
}
}

pub(crate) async fn handle_next_event(&self) {
match self.liquidity_manager.next_event_async().await {
LiquidityEvent::LSPS1Client(LSPS1ClientEvent::SupportedOptionsReady {
Expand DownExpand Up@@ -594,7 +663,7 @@ where
request_id,
intercept_scid,
LSPS2_CHANNEL_CLTV_EXPIRY_DELTA,
LSPS2_CLIENT_TRUSTS_LSP_MODE,
service_config.client_trusts_lsp,
user_channel_id,
)
.await
Expand Down
Loading
Loading