Skip to content

Commit c9d0c96

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 2944bd1 commit c9d0c96

File tree

6 files changed

+423
-23
lines changed

6 files changed

+423
-23
lines changed

src/builder.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1507,6 +1507,7 @@ fn build_with_store_internal(
15071507
Arc::clone(&chain_source),
15081508
Arc::clone(&config),
15091509
Arc::clone(&logger),
1510+
Arc::clone(&tx_broadcaster),
15101511
);
15111512

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

src/event.rs

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -497,7 +497,7 @@ where
497497
counterparty_node_id,
498498
channel_value_satoshis,
499499
output_script,
500-
..
500+
user_channel_id,
501501
} => {
502502
// Construct the raw transaction with the output that is paid the amount of the
503503
// channel.
@@ -516,12 +516,43 @@ where
516516
locktime,
517517
) {
518518
Ok(final_tx) => {
519-
// Give the funding transaction back to LDK for opening the channel.
520-
match self.channel_manager.funding_transaction_generated(
521-
temporary_channel_id,
522-
counterparty_node_id,
523-
final_tx,
524-
) {
519+
let needs_manual_broadcast =
520+
match self.liquidity_source.as_ref().map(|ls| {
521+
ls.as_ref().lsps2_channel_needs_manual_broadcast(
522+
counterparty_node_id,
523+
user_channel_id,
524+
)
525+
}) {
526+
Some(Ok(v)) => v,
527+
Some(Err(e)) => {
528+
log_error!(self.logger, "Failed to determine if channel needs manual broadcast: {:?}", e);
529+
false
530+
},
531+
None => false,
532+
};
533+
534+
let result = if needs_manual_broadcast {
535+
self.liquidity_source.as_ref().map(|ls| {
536+
ls.lsps2_store_funding_transaction(
537+
user_channel_id,
538+
counterparty_node_id,
539+
final_tx.clone(),
540+
);
541+
});
542+
self.channel_manager.funding_transaction_generated_manual_broadcast(
543+
temporary_channel_id,
544+
counterparty_node_id,
545+
final_tx,
546+
)
547+
} else {
548+
self.channel_manager.funding_transaction_generated(
549+
temporary_channel_id,
550+
counterparty_node_id,
551+
final_tx,
552+
)
553+
};
554+
555+
match result {
525556
Ok(()) => {},
526557
Err(APIError::APIMisuseError { err }) => {
527558
log_error!(self.logger, "Panicking due to APIMisuseError: {}", err);
@@ -560,8 +591,10 @@ where
560591
},
561592
}
562593
},
563-
LdkEvent::FundingTxBroadcastSafe { .. } => {
564-
debug_assert!(false, "We currently only support safe funding, so this event should never be emitted.");
594+
LdkEvent::FundingTxBroadcastSafe { user_channel_id, counterparty_node_id, .. } => {
595+
self.liquidity_source.as_ref().map(|ls| {
596+
ls.lsps2_funding_tx_broadcast_safe(user_channel_id, counterparty_node_id);
597+
});
565598
},
566599
LdkEvent::PaymentClaimable {
567600
payment_hash,
@@ -686,7 +719,7 @@ where
686719
match info.kind {
687720
PaymentKind::Bolt11 { preimage, .. }
688721
| PaymentKind::Bolt11Jit { preimage, .. } => {
689-
if purpose.preimage().is_none() {
722+
if preimage.is_none() || purpose.preimage().is_none() {
690723
debug_assert!(
691724
preimage.is_none(),
692725
"We would have registered the preimage if we knew"
@@ -1280,7 +1313,7 @@ where
12801313
}
12811314

12821315
if let Some(liquidity_source) = self.liquidity_source.as_ref() {
1283-
liquidity_source.handle_payment_forwarded(next_channel_id);
1316+
liquidity_source.handle_payment_forwarded(next_channel_id, skimmed_fee_msat);
12841317
}
12851318

12861319
let event = Event::PaymentForwarded {

src/liquidity.rs

Lines changed: 91 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,17 @@ use crate::chain::ChainSource;
1111
use crate::connection::ConnectionManager;
1212
use crate::logger::{log_debug, log_error, log_info, LdkLogger, Logger};
1313
use crate::runtime::Runtime;
14-
use crate::types::{ChannelManager, KeysManager, LiquidityManager, PeerManager, Wallet};
14+
use crate::types::{
15+
Broadcaster, ChannelManager, KeysManager, LiquidityManager, PeerManager, Wallet,
16+
};
1517
use crate::{total_anchor_channels_reserve_sats, Config, Error};
1618

1719
use lightning::events::HTLCHandlingFailureType;
1820
use lightning::ln::channelmanager::{InterceptId, MIN_FINAL_CLTV_EXPIRY_DELTA};
1921
use lightning::ln::msgs::SocketAddress;
2022
use lightning::ln::types::ChannelId;
2123
use lightning::routing::router::{RouteHint, RouteHintHop};
24+
use lightning::util::errors::APIError;
2225

2326
use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, InvoiceBuilder, RoutingFees};
2427

@@ -40,6 +43,7 @@ use lightning_types::payment::PaymentHash;
4043

4144
use bitcoin::hashes::{sha256, Hash};
4245
use bitcoin::secp256k1::{PublicKey, Secp256k1};
46+
use bitcoin::Transaction;
4347

4448
use tokio::sync::oneshot;
4549

@@ -55,7 +59,6 @@ use std::time::Duration;
5559
const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;
5660

5761
const LSPS2_GETINFO_REQUEST_EXPIRY: Duration = Duration::from_secs(60 * 60 * 24);
58-
const LSPS2_CLIENT_TRUSTS_LSP_MODE: bool = true;
5962
const LSPS2_CHANNEL_CLTV_EXPIRY_DELTA: u32 = 72;
6063

6164
struct LSPS1Client {
@@ -134,6 +137,8 @@ pub struct LSPS2ServiceConfig {
134137
pub min_payment_size_msat: u64,
135138
/// The maximum payment size that we will accept when opening a channel.
136139
pub max_payment_size_msat: u64,
140+
/// Use the client trusts lsp model
141+
pub client_trusts_lsp: bool,
137142
}
138143

139144
pub(crate) struct LiquiditySourceBuilder<L: Deref>
@@ -149,6 +154,7 @@ where
149154
chain_source: Arc<ChainSource>,
150155
config: Arc<Config>,
151156
logger: L,
157+
broadcaster: Arc<Broadcaster>,
152158
}
153159

154160
impl<L: Deref> LiquiditySourceBuilder<L>
@@ -158,6 +164,7 @@ where
158164
pub(crate) fn new(
159165
wallet: Arc<Wallet>, channel_manager: Arc<ChannelManager>, keys_manager: Arc<KeysManager>,
160166
chain_source: Arc<ChainSource>, config: Arc<Config>, logger: L,
167+
broadcaster: Arc<Broadcaster>,
161168
) -> Self {
162169
let lsps1_client = None;
163170
let lsps2_client = None;
@@ -172,6 +179,7 @@ where
172179
chain_source,
173180
config,
174181
logger,
182+
broadcaster,
175183
}
176184
}
177185

@@ -242,6 +250,7 @@ where
242250
Arc::clone(&self.keys_manager),
243251
Arc::clone(&self.channel_manager),
244252
Some(Arc::clone(&self.chain_source)),
253+
Arc::clone(&self.broadcaster),
245254
None,
246255
liquidity_service_config,
247256
liquidity_client_config,
@@ -298,6 +307,79 @@ where
298307
self.lsps2_client.as_ref().map(|s| (s.lsp_node_id, s.lsp_address.clone()))
299308
}
300309

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

1299-
pub(crate) fn handle_payment_forwarded(&self, next_channel_id: Option<ChannelId>) {
1381+
pub(crate) fn handle_payment_forwarded(
1382+
&self, next_channel_id: Option<ChannelId>, skimmed_fee_msat: Option<u64>,
1383+
) {
13001384
if let Some(next_channel_id) = next_channel_id {
13011385
if let Some(lsps2_service_handler) = self.liquidity_manager.lsps2_service_handler() {
1302-
if let Err(e) = lsps2_service_handler.payment_forwarded(next_channel_id) {
1386+
if let Err(e) = lsps2_service_handler
1387+
.payment_forwarded(next_channel_id, skimmed_fee_msat.unwrap_or(0))
1388+
{
13031389
log_error!(
13041390
self.logger,
13051391
"LSPS2 service failed to handle PaymentForwarded: {:?}",

0 commit comments

Comments
 (0)