Skip to content

Commit a69c91f

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 1a134b4 commit a69c91f

File tree

7 files changed

+443
-21
lines changed

7 files changed

+443
-21
lines changed

bindings/ldk_node.udl

Lines changed: 8 additions & 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 {
@@ -197,6 +198,13 @@ interface Bolt11Payment {
197198
Bolt11Invoice receive_variable_amount_via_jit_channel([ByRef]Bolt11InvoiceDescription description, u32 expiry_secs, u64? max_proportional_lsp_fee_limit_ppm_msat);
198199
[Throws=NodeError]
199200
Bolt11Invoice receive_variable_amount_via_jit_channel_for_hash([ByRef]Bolt11InvoiceDescription description, u32 expiry_secs, u64? max_proportional_lsp_fee_limit_ppm_msat, PaymentHash payment_hash);
201+
[Throws=NodeError]
202+
JitChannelManualClaim receive_via_jit_channel_manual_claim(u64 amount_msat, [ByRef]Bolt11InvoiceDescription description, u32 expiry_secs, u64? max_total_lsp_fee_limit_msat);
203+
};
204+
205+
dictionary JitChannelManualClaim {
206+
Bolt11Invoice invoice;
207+
PaymentPreimage preimage;
200208
};
201209

202210
interface Bolt12Payment {

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: 43 additions & 10 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,
@@ -676,7 +709,7 @@ where
676709
match info.kind {
677710
PaymentKind::Bolt11 { preimage, .. }
678711
| PaymentKind::Bolt11Jit { preimage, .. } => {
679-
if purpose.preimage().is_none() {
712+
if preimage.is_none() || purpose.preimage().is_none() {
680713
debug_assert!(
681714
preimage.is_none(),
682715
"We would have registered the preimage if we knew"

src/ffi/types.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1164,6 +1164,15 @@ impl UniffiCustomTypeConverter for LSPSDateTime {
11641164
}
11651165
}
11661166

1167+
/// A payable invoice and its corresponding preimage for manual claiming via a JIT channel.
1168+
#[derive(Debug, Clone)]
1169+
pub struct JitChannelManualClaim {
1170+
/// The payable invoice.
1171+
pub invoice: Arc<Bolt11Invoice>,
1172+
/// The payment preimage.
1173+
pub preimage: PaymentPreimage,
1174+
}
1175+
11671176
#[cfg(test)]
11681177
mod tests {
11691178
use std::num::NonZeroU64;

src/liquidity.rs

Lines changed: 84 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ use crate::{total_anchor_channels_reserve_sats, Config, Error};
5151
const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;
5252

5353
const LSPS2_GETINFO_REQUEST_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
54-
const LSPS2_CLIENT_TRUSTS_LSP_MODE: bool = true;
5554
const LSPS2_CHANNEL_CLTV_EXPIRY_DELTA: u32 = 72;
5655

5756
struct LSPS1Client {
@@ -130,6 +129,8 @@ pub struct LSPS2ServiceConfig {
130129
pub min_payment_size_msat: u64,
131130
/// The maximum payment size that we will accept when opening a channel.
132131
pub max_payment_size_msat: u64,
132+
/// Use the client trusts lsp model
133+
pub client_trusts_lsp: bool,
133134
}
134135

135136
pub(crate) struct LiquiditySourceBuilder<L: Deref>
@@ -147,6 +148,7 @@ where
147148
kv_store: Arc<DynStore>,
148149
config: Arc<Config>,
149150
logger: L,
151+
broadcaster: Arc<Broadcaster>,
150152
}
151153

152154
impl<L: Deref> LiquiditySourceBuilder<L>
@@ -155,8 +157,12 @@ where
155157
{
156158
pub(crate) fn new(
157159
wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>, keys_manager: Arc<KeysManager>,
158-
chain_source: Arc<ChainSource>, tx_broadcaster: Arc<Broadcaster>, kv_store: Arc<DynStore>,
159-
config: Arc<Config>, logger: L,
160+
chain_source: Arc<ChainSource>,
161+
tx_broadcaster: Arc<Broadcaster>,
162+
kv_store: Arc<DynStore>,
163+
config: Arc<Config>,
164+
logger: L,
165+
broadcaster: Arc<Broadcaster>,
160166
) -> Self {
161167
let lsps1_client = None;
162168
let lsps2_client = None;
@@ -173,6 +179,7 @@ where
173179
kv_store,
174180
config,
175181
logger,
182+
broadcaster,
176183
}
177184
}
178185

@@ -305,6 +312,79 @@ where
305312
self.lsps2_client.as_ref().map(|s| (s.lsp_node_id, s.lsp_address.clone()))
306313
}
307314

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

0 commit comments

Comments
 (0)