Skip to content

Commit 97d9e53

Browse files
Support client_trusts_lsp=true on ldk-node
implement changes introduced on lightningdevkit/rust-lightning#3838 as discussed, client_trusts_lsp is a flag set at startup. a new function receive_via_jit_channel_manual_claim is introduced to bolt11 so we allow the client to manually claim a payment (used on tests).
1 parent cef82e4 commit 97d9e53

File tree

5 files changed

+383
-12
lines changed

5 files changed

+383
-12
lines changed

bindings/ldk_node.udl

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ dictionary LSPS2ServiceConfig {
4444
u32 max_client_to_self_delay;
4545
u64 min_payment_size_msat;
4646
u64 max_payment_size_msat;
47+
boolean client_trusts_lsp;
4748
};
4849

4950
enum LogLevel {

src/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1613,6 +1613,7 @@ fn build_with_store_internal(
16131613
Arc::clone(&kv_store),
16141614
Arc::clone(&config),
16151615
Arc::clone(&logger),
1616+
Arc::clone(&tx_broadcaster),
16161617
);
16171618

16181619
lsc.lsps1_client.as_ref().map(|config| {

src/event.rs

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -487,7 +487,7 @@ where
487487
counterparty_node_id,
488488
channel_value_satoshis,
489489
output_script,
490-
..
490+
user_channel_id,
491491
} => {
492492
// Construct the raw transaction with the output that is paid the amount of the
493493
// channel.
@@ -506,12 +506,43 @@ where
506506
locktime,
507507
) {
508508
Ok(final_tx) => {
509-
// Give the funding transaction back to LDK for opening the channel.
510-
match self.channel_manager.funding_transaction_generated(
511-
temporary_channel_id,
512-
counterparty_node_id,
513-
final_tx,
514-
) {
509+
let needs_manual_broadcast =
510+
match self.liquidity_source.as_ref().map(|ls| {
511+
ls.as_ref().lsps2_channel_needs_manual_broadcast(
512+
counterparty_node_id,
513+
user_channel_id,
514+
)
515+
}) {
516+
Some(Ok(v)) => v,
517+
Some(Err(e)) => {
518+
log_error!(self.logger, "Failed to determine if channel needs manual broadcast: {:?}", e);
519+
false
520+
},
521+
None => false,
522+
};
523+
524+
let result = if needs_manual_broadcast {
525+
self.liquidity_source.as_ref().map(|ls| {
526+
ls.lsps2_store_funding_transaction(
527+
user_channel_id,
528+
counterparty_node_id,
529+
final_tx.clone(),
530+
);
531+
});
532+
self.channel_manager.funding_transaction_generated_manual_broadcast(
533+
temporary_channel_id,
534+
counterparty_node_id,
535+
final_tx,
536+
)
537+
} else {
538+
self.channel_manager.funding_transaction_generated(
539+
temporary_channel_id,
540+
counterparty_node_id,
541+
final_tx,
542+
)
543+
};
544+
545+
match result {
515546
Ok(()) => {},
516547
Err(APIError::APIMisuseError { err }) => {
517548
log_error!(self.logger, "Panicking due to APIMisuseError: {}", err);
@@ -550,8 +581,10 @@ where
550581
},
551582
}
552583
},
553-
LdkEvent::FundingTxBroadcastSafe { .. } => {
554-
debug_assert!(false, "We currently only support safe funding, so this event should never be emitted.");
584+
LdkEvent::FundingTxBroadcastSafe { user_channel_id, counterparty_node_id, .. } => {
585+
self.liquidity_source.as_ref().map(|ls| {
586+
ls.lsps2_funding_tx_broadcast_safe(user_channel_id, counterparty_node_id);
587+
});
555588
},
556589
LdkEvent::PaymentClaimable {
557590
payment_hash,

src/liquidity.rs

Lines changed: 81 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ use std::time::Duration;
1414

1515
use bitcoin::hashes::{sha256, Hash};
1616
use bitcoin::secp256k1::{PublicKey, Secp256k1};
17+
use bitcoin::Transaction;
1718
use chrono::Utc;
1819
use lightning::events::HTLCHandlingFailureType;
1920
use lightning::ln::channelmanager::{InterceptId, MIN_FINAL_CLTV_EXPIRY_DELTA};
2021
use lightning::ln::msgs::SocketAddress;
2122
use lightning::ln::types::ChannelId;
2223
use lightning::routing::router::{RouteHint, RouteHintHop};
24+
use lightning::util::errors::APIError;
2325
use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, InvoiceBuilder, RoutingFees};
2426
use lightning_liquidity::events::LiquidityEvent;
2527
use lightning_liquidity::lsps0::ser::{LSPSDateTime, LSPSRequestId};
@@ -51,7 +53,6 @@ use crate::{total_anchor_channels_reserve_sats, Config, Error};
5153
const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;
5254

5355
const LSPS2_GETINFO_REQUEST_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
54-
const LSPS2_CLIENT_TRUSTS_LSP_MODE: bool = true;
5556
const LSPS2_CHANNEL_CLTV_EXPIRY_DELTA: u32 = 72;
5657

5758
struct LSPS1Client {
@@ -130,6 +131,8 @@ pub struct LSPS2ServiceConfig {
130131
pub min_payment_size_msat: u64,
131132
/// The maximum payment size that we will accept when opening a channel.
132133
pub max_payment_size_msat: u64,
134+
/// Use the client trusts lsp model
135+
pub client_trusts_lsp: bool,
133136
}
134137

135138
pub(crate) struct LiquiditySourceBuilder<L: Deref>
@@ -147,6 +150,7 @@ where
147150
kv_store: Arc<DynStore>,
148151
config: Arc<Config>,
149152
logger: L,
153+
broadcaster: Arc<Broadcaster>,
150154
}
151155

152156
impl<L: Deref> LiquiditySourceBuilder<L>
@@ -156,7 +160,7 @@ where
156160
pub(crate) fn new(
157161
wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>, keys_manager: Arc<KeysManager>,
158162
chain_source: Arc<ChainSource>, tx_broadcaster: Arc<Broadcaster>, kv_store: Arc<DynStore>,
159-
config: Arc<Config>, logger: L,
163+
config: Arc<Config>, logger: L, broadcaster: Arc<Broadcaster>,
160164
) -> Self {
161165
let lsps1_client = None;
162166
let lsps2_client = None;
@@ -173,6 +177,7 @@ where
173177
kv_store,
174178
config,
175179
logger,
180+
broadcaster,
176181
}
177182
}
178183

@@ -305,6 +310,79 @@ where
305310
self.lsps2_client.as_ref().map(|s| (s.lsp_node_id, s.lsp_address.clone()))
306311
}
307312

313+
pub(crate) fn lsps2_channel_needs_manual_broadcast(
314+
&self, counterparty_node_id: PublicKey, user_channel_id: u128,
315+
) -> Result<bool, APIError> {
316+
// if we are not in a client_trusts_lsp model, we don't check and just return false
317+
if !self.is_client_trusts_lsp() {
318+
log_debug!(self.logger, "Skipping funding transaction broadcast as client trusts LSP.");
319+
return Ok(false);
320+
}
321+
322+
// if we are in a client_trusts_lsp model, then we check if the LSP has an LSPS2 operation in progress
323+
self.lsps2_service.as_ref().map_or(Ok(false), |_| {
324+
let lsps2_service_handler = self.liquidity_manager.lsps2_service_handler();
325+
if let Some(handler) = lsps2_service_handler {
326+
handler.channel_needs_manual_broadcast(user_channel_id, &counterparty_node_id)
327+
} else {
328+
log_error!(self.logger, "LSPS2 service handler is not available.");
329+
Ok(false)
330+
}
331+
})
332+
}
333+
334+
pub(crate) fn lsps2_store_funding_transaction(
335+
&self, user_channel_id: u128, counterparty_node_id: PublicKey, funding_tx: Transaction,
336+
) {
337+
if !self.is_client_trusts_lsp() {
338+
log_debug!(self.logger, "Skipping funding transaction broadcast as client trusts LSP.");
339+
return;
340+
}
341+
self.lsps2_service.as_ref().map(|_| {
342+
let lsps2_service_handler = self.liquidity_manager.lsps2_service_handler();
343+
if let Some(handler) = lsps2_service_handler {
344+
handler
345+
.store_funding_transaction(user_channel_id, &counterparty_node_id, funding_tx)
346+
.unwrap_or_else(|e| {
347+
debug_assert!(false, "Failed to store funding transaction: {:?}", e);
348+
log_error!(self.logger, "Failed to store funding transaction: {:?}", e);
349+
});
350+
} else {
351+
log_error!(self.logger, "LSPS2 service handler is not available.");
352+
}
353+
});
354+
}
355+
356+
pub(crate) fn lsps2_funding_tx_broadcast_safe(
357+
&self, user_channel_id: u128, counterparty_node_id: PublicKey,
358+
) {
359+
if !self.is_client_trusts_lsp() {
360+
log_debug!(self.logger, "Skipping funding transaction broadcast as client trusts LSP.");
361+
return;
362+
}
363+
self.lsps2_service.as_ref().map(|_| {
364+
let lsps2_service_handler = self.liquidity_manager.lsps2_service_handler();
365+
if let Some(handler) = lsps2_service_handler {
366+
handler
367+
.set_funding_tx_broadcast_safe(user_channel_id, &counterparty_node_id)
368+
.unwrap_or_else(|e| {
369+
debug_assert!(false, "Failed to store funding transaction: {:?}", e);
370+
log_error!(self.logger, "Failed to store funding transaction: {:?}", e);
371+
});
372+
} else {
373+
log_error!(self.logger, "LSPS2 service handler is not available.");
374+
}
375+
});
376+
}
377+
378+
fn is_client_trusts_lsp(&self) -> bool {
379+
if let Some(lsps2_service) = self.lsps2_service.as_ref() {
380+
lsps2_service.service_config.client_trusts_lsp
381+
} else {
382+
false
383+
}
384+
}
385+
308386
pub(crate) async fn handle_next_event(&self) {
309387
match self.liquidity_manager.next_event_async().await {
310388
LiquidityEvent::LSPS1Client(LSPS1ClientEvent::SupportedOptionsReady {
@@ -594,7 +672,7 @@ where
594672
request_id,
595673
intercept_scid,
596674
LSPS2_CHANNEL_CLTV_EXPIRY_DELTA,
597-
LSPS2_CLIENT_TRUSTS_LSP_MODE,
675+
service_config.client_trusts_lsp,
598676
user_channel_id,
599677
)
600678
.await

0 commit comments

Comments
 (0)