Skip to content

Commit 73114ac

Browse files
martinsaposnictnull
authored andcommitted
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 1dd9827 commit 73114ac

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
@@ -491,7 +491,7 @@ where
491491
counterparty_node_id,
492492
channel_value_satoshis,
493493
output_script,
494-
..
494+
user_channel_id,
495495
} => {
496496
// Construct the raw transaction with the output that is paid the amount of the
497497
// channel.
@@ -510,12 +510,43 @@ where
510510
locktime,
511511
) {
512512
Ok(final_tx) => {
513-
// Give the funding transaction back to LDK for opening the channel.
514-
match self.channel_manager.funding_transaction_generated(
515-
temporary_channel_id,
516-
counterparty_node_id,
517-
final_tx,
518-
) {
513+
let needs_manual_broadcast =
514+
match self.liquidity_source.as_ref().map(|ls| {
515+
ls.as_ref().lsps2_channel_needs_manual_broadcast(
516+
counterparty_node_id,
517+
user_channel_id,
518+
)
519+
}) {
520+
Some(Ok(v)) => v,
521+
Some(Err(e)) => {
522+
log_error!(self.logger, "Failed to determine if channel needs manual broadcast: {:?}", e);
523+
false
524+
},
525+
None => false,
526+
};
527+
528+
let result = if needs_manual_broadcast {
529+
self.liquidity_source.as_ref().map(|ls| {
530+
ls.lsps2_store_funding_transaction(
531+
user_channel_id,
532+
counterparty_node_id,
533+
final_tx.clone(),
534+
);
535+
});
536+
self.channel_manager.funding_transaction_generated_manual_broadcast(
537+
temporary_channel_id,
538+
counterparty_node_id,
539+
final_tx,
540+
)
541+
} else {
542+
self.channel_manager.funding_transaction_generated(
543+
temporary_channel_id,
544+
counterparty_node_id,
545+
final_tx,
546+
)
547+
};
548+
549+
match result {
519550
Ok(()) => {},
520551
Err(APIError::APIMisuseError { err }) => {
521552
log_error!(self.logger, "Panicking due to APIMisuseError: {}", err);
@@ -554,8 +585,10 @@ where
554585
},
555586
}
556587
},
557-
LdkEvent::FundingTxBroadcastSafe { .. } => {
558-
debug_assert!(false, "We currently only support safe funding, so this event should never be emitted.");
588+
LdkEvent::FundingTxBroadcastSafe { user_channel_id, counterparty_node_id, .. } => {
589+
self.liquidity_source.as_ref().map(|ls| {
590+
ls.lsps2_funding_tx_broadcast_safe(user_channel_id, counterparty_node_id);
591+
});
559592
},
560593
LdkEvent::PaymentClaimable {
561594
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)