Skip to content

Commit 53a8174

Browse files
Support client_trusts_lsp
1 parent c9c1b38 commit 53a8174

File tree

4 files changed

+387
-22
lines changed

4 files changed

+387
-22
lines changed

src/event.rs

Lines changed: 47 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66
// accordance with one or both of these licenses.
77

8+
use crate::payment::PaymentDetails;
89
use crate::types::{CustomTlvRecord, DynStore, PaymentStore, Sweeper, Wallet};
910

1011
use crate::{
@@ -19,9 +20,7 @@ use crate::fee_estimator::ConfirmationTarget;
1920
use crate::liquidity::LiquiditySource;
2021
use crate::logger::Logger;
2122

22-
use crate::payment::store::{
23-
PaymentDetails, PaymentDetailsUpdate, PaymentDirection, PaymentKind, PaymentStatus,
24-
};
23+
use crate::payment::store::{PaymentDetailsUpdate, PaymentDirection, PaymentKind, PaymentStatus};
2524

2625
use crate::io::{
2726
EVENT_QUEUE_PERSISTENCE_KEY, EVENT_QUEUE_PERSISTENCE_PRIMARY_NAMESPACE,
@@ -36,6 +35,9 @@ use lightning::impl_writeable_tlv_based_enum;
3635
use lightning::ln::channelmanager::PaymentId;
3736
use lightning::ln::types::ChannelId;
3837
use lightning::routing::gossip::NodeId;
38+
use lightning::util::config::{
39+
ChannelConfigOverrides, ChannelConfigUpdate, ChannelHandshakeConfigUpdate,
40+
};
3941
use lightning::util::errors::APIError;
4042
use lightning::util::ser::{Readable, ReadableArgs, Writeable, Writer};
4143

@@ -493,7 +495,7 @@ where
493495
counterparty_node_id,
494496
channel_value_satoshis,
495497
output_script,
496-
..
498+
user_channel_id,
497499
} => {
498500
// Construct the raw transaction with the output that is paid the amount of the
499501
// channel.
@@ -512,12 +514,39 @@ where
512514
locktime,
513515
) {
514516
Ok(final_tx) => {
515-
// Give the funding transaction back to LDK for opening the channel.
516-
match self.channel_manager.funding_transaction_generated(
517-
temporary_channel_id,
518-
counterparty_node_id,
519-
final_tx,
520-
) {
517+
let needs_manual_broadcast = self
518+
.liquidity_source
519+
.as_ref()
520+
.map(|ls| {
521+
ls.as_ref().lsps2_channel_needs_manual_broadcast(
522+
counterparty_node_id,
523+
user_channel_id,
524+
)
525+
})
526+
.unwrap_or(false);
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 {
521550
Ok(()) => {},
522551
Err(APIError::APIMisuseError { err }) => {
523552
log_error!(self.logger, "Panicking due to APIMisuseError: {}", err);
@@ -556,16 +585,17 @@ where
556585
},
557586
}
558587
},
559-
LdkEvent::FundingTxBroadcastSafe { .. } => {
560-
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+
});
561592
},
562593
LdkEvent::PaymentClaimable {
563594
payment_hash,
564595
purpose,
565596
amount_msat,
566597
receiver_node_id: _,
567-
via_channel_id: _,
568-
via_user_channel_id: _,
598+
via_channel_ids: _,
569599
claim_deadline,
570600
onion_fields,
571601
counterparty_skimmed_fee_msat,
@@ -683,8 +713,9 @@ where
683713
// the payment has been registered via `_for_hash` variants and needs to be manually claimed via
684714
// user interaction.
685715
match info.kind {
686-
PaymentKind::Bolt11 { preimage, .. } => {
687-
if purpose.preimage().is_none() {
716+
PaymentKind::Bolt11 { preimage, .. }
717+
| PaymentKind::Bolt11Jit { preimage, .. } => {
718+
if preimage.is_none() || purpose.preimage().is_none() {
688719
debug_assert!(
689720
preimage.is_none(),
690721
"We would have registered the preimage if we knew"

src/liquidity.rs

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,6 @@ use std::time::Duration;
5555
const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;
5656

5757
const LSPS2_GETINFO_REQUEST_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
58-
const LSPS2_CLIENT_TRUSTS_LSP_MODE: bool = true;
5958
const LSPS2_CHANNEL_CLTV_EXPIRY_DELTA: u32 = 72;
6059

6160
struct LSPS1Client {
@@ -134,6 +133,8 @@ pub struct LSPS2ServiceConfig {
134133
pub min_payment_size_msat: u64,
135134
/// The maximum payment size that we will accept when opening a channel.
136135
pub max_payment_size_msat: u64,
136+
/// Use the client trusts lsp model
137+
pub client_trusts_lsp: bool,
137138
}
138139

139140
pub(crate) struct LiquiditySourceBuilder<L: Deref>
@@ -292,6 +293,81 @@ where
292293
self.lsps2_client.as_ref().map(|s| (s.lsp_node_id, s.lsp_address.clone()))
293294
}
294295

296+
pub(crate) fn lsps2_channel_needs_manual_broadcast(
297+
&self, counterparty_node_id: PublicKey, user_channel_id: u128,
298+
) -> bool {
299+
// if we are not in a client_trusts_lsp model, we don't check and just return false
300+
if !self.is_client_trusts_lsp() {
301+
log_debug!(self.logger, "Skipping funding transaction broadcast as client trusts LSP.");
302+
return false;
303+
}
304+
305+
// if we are in a client_trusts_lsp model, then we check if the LSP has an LSPS2 operation in progress
306+
self.lsps2_service.as_ref().map_or(false, |_| {
307+
let lsps2_service_handler = self.liquidity_manager.lsps2_service_handler();
308+
if let Some(handler) = lsps2_service_handler {
309+
handler
310+
.channel_needs_manual_broadcast(user_channel_id, &counterparty_node_id)
311+
.unwrap_or(false)
312+
} else {
313+
log_error!(self.logger, "LSPS2 service handler is not available.");
314+
false
315+
}
316+
})
317+
}
318+
319+
pub(crate) fn lsps2_store_funding_transaction(
320+
&self, user_channel_id: u128, counterparty_node_id: PublicKey, funding_tx: Transaction,
321+
) {
322+
if !self.is_client_trusts_lsp() {
323+
log_debug!(self.logger, "Skipping funding transaction broadcast as client trusts LSP.");
324+
return;
325+
}
326+
self.lsps2_service.as_ref().map(|_| {
327+
let lsps2_service_handler = self.liquidity_manager.lsps2_service_handler();
328+
if let Some(handler) = lsps2_service_handler {
329+
handler
330+
.store_funding_transaction(user_channel_id, &counterparty_node_id, funding_tx)
331+
.unwrap_or_else(|e| {
332+
debug_assert!(false, "Failed to store funding transaction: {:?}", e);
333+
log_error!(self.logger, "Failed to store funding transaction: {:?}", e);
334+
});
335+
} else {
336+
log_error!(self.logger, "LSPS2 service handler is not available.");
337+
}
338+
});
339+
}
340+
341+
pub(crate) fn lsps2_funding_tx_broadcast_safe(
342+
&self, user_channel_id: u128, counterparty_node_id: PublicKey,
343+
) {
344+
if !self.is_client_trusts_lsp() {
345+
log_debug!(self.logger, "Skipping funding transaction broadcast as client trusts LSP.");
346+
return;
347+
}
348+
self.lsps2_service.as_ref().map(|_| {
349+
let lsps2_service_handler = self.liquidity_manager.lsps2_service_handler();
350+
if let Some(handler) = lsps2_service_handler {
351+
handler
352+
.funding_tx_broadcast_safe(user_channel_id, &counterparty_node_id)
353+
.unwrap_or_else(|e| {
354+
debug_assert!(false, "Failed to store funding transaction: {:?}", e);
355+
log_error!(self.logger, "Failed to store funding transaction: {:?}", e);
356+
});
357+
} else {
358+
log_error!(self.logger, "LSPS2 service handler is not available.");
359+
}
360+
});
361+
}
362+
363+
fn is_client_trusts_lsp(&self) -> bool {
364+
if let Some(lsps2_service) = self.lsps2_service.as_ref() {
365+
lsps2_service.service_config.client_trusts_lsp
366+
} else {
367+
false
368+
}
369+
}
370+
295371
pub(crate) async fn handle_next_event(&self) {
296372
match self.liquidity_manager.next_event_async().await {
297373
LiquidityEvent::LSPS1Client(LSPS1ClientEvent::SupportedOptionsReady {
@@ -580,7 +656,7 @@ where
580656
request_id,
581657
intercept_scid,
582658
LSPS2_CHANNEL_CLTV_EXPIRY_DELTA,
583-
LSPS2_CLIENT_TRUSTS_LSP_MODE,
659+
service_config.client_trusts_lsp,
584660
user_channel_id,
585661
) {
586662
Ok(()) => {},

src/payment/bolt11.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -574,6 +574,7 @@ impl Bolt11Payment {
574574
expiry_secs,
575575
max_total_lsp_fee_limit_msat,
576576
None,
577+
true,
577578
)?;
578579
Ok(maybe_wrap(invoice))
579580
}
@@ -592,6 +593,7 @@ impl Bolt11Payment {
592593
expiry_secs,
593594
max_total_lsp_fee_limit_msat,
594595
None,
596+
false,
595597
)?;
596598
let preimage = preimage.ok_or(Error::InvoiceCreationFailed)?;
597599
Ok((maybe_wrap(invoice), preimage))
@@ -619,15 +621,16 @@ impl Bolt11Payment {
619621
expiry_secs,
620622
None,
621623
max_proportional_lsp_fee_limit_ppm_msat,
624+
true,
622625
)?;
623626
Ok(maybe_wrap(invoice))
624627
}
625628

626629
fn receive_via_jit_channel_inner(
627630
&self, amount_msat: Option<u64>, description: &LdkBolt11InvoiceDescription,
628631
expiry_secs: u32, max_total_lsp_fee_limit_msat: Option<u64>,
629-
max_proportional_lsp_fee_limit_ppm_msat: Option<u64>,
630-
) -> Result<LdkBolt11Invoice, Error> {
632+
max_proportional_lsp_fee_limit_ppm_msat: Option<u64>, auto_claim: bool,
633+
) -> Result<(LdkBolt11Invoice, Option<PaymentPreimage>), Error> {
631634
let liquidity_source =
632635
self.liquidity_source.as_ref().ok_or(Error::LiquiditySourceUnavailable)?;
633636

@@ -690,9 +693,12 @@ impl Bolt11Payment {
690693
let id = PaymentId(payment_hash.0);
691694
let preimage =
692695
self.channel_manager.get_payment_preimage(payment_hash, payment_secret.clone()).ok();
696+
697+
let stored_preimage = if auto_claim { preimage } else { None };
698+
693699
let kind = PaymentKind::Bolt11Jit {
694700
hash: payment_hash,
695-
preimage,
701+
preimage: stored_preimage,
696702
secret: Some(payment_secret.clone()),
697703
counterparty_skimmed_fee_msat: None,
698704
lsp_fee_limits,
@@ -710,7 +716,7 @@ impl Bolt11Payment {
710716
// Persist LSP peer to make sure we reconnect on restart.
711717
self.peer_store.add_peer(peer_info)?;
712718

713-
Ok(invoice)
719+
Ok((invoice, preimage))
714720
}
715721

716722
/// Sends payment probes over all paths of a route that would be used to pay the given invoice.

0 commit comments

Comments
 (0)