Skip to content

Commit e6aad1b

Browse files
committed
Move LSPS2 service event handling into liquidity/service/lsps2.rs
1 parent 0d03204 commit e6aad1b

2 files changed

Lines changed: 283 additions & 279 deletions

File tree

src/liquidity/mod.rs

Lines changed: 15 additions & 279 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,10 @@ use std::ops::Deref;
1515
use std::sync::{Arc, Mutex, RwLock, Weak};
1616

1717
use bitcoin::secp256k1::PublicKey;
18-
use chrono::Utc;
1918
use lightning::ln::msgs::SocketAddress;
20-
use lightning::sign::EntropySource;
2119
use lightning_liquidity::events::LiquidityEvent;
22-
use lightning_liquidity::lsps0::ser::LSPSDateTime;
2320
use lightning_liquidity::lsps1::client::LSPS1ClientConfig as LdkLSPS1ClientConfig;
2421
use lightning_liquidity::lsps2::client::LSPS2ClientConfig as LdkLSPS2ClientConfig;
25-
use lightning_liquidity::lsps2::event::LSPS2ServiceEvent;
26-
use lightning_liquidity::lsps2::msgs::LSPS2RawOpeningFeeParams;
2722
use lightning_liquidity::lsps2::service::LSPS2ServiceConfig as LdkLSPS2ServiceConfig;
2823
use lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig};
2924

@@ -32,15 +27,13 @@ use crate::logger::{log_error, LdkLogger};
3227
use crate::types::{
3328
Broadcaster, ChannelManager, DynStore, KeysManager, LiquidityManager, PeerManager, Wallet,
3429
};
35-
use crate::{total_anchor_channels_reserve_sats, Config};
30+
use crate::Config;
3631

3732
pub(crate) use client::lsps1::{LSPS1Client, LSPS1ClientConfig};
3833
pub use client::lsps1::{LSPS1Liquidity, LSPS1OrderStatus};
3934
pub(crate) use client::lsps2::{LSPS2Client, LSPS2ClientConfig};
35+
pub(crate) use service::lsps2::LSPS2Service;
4036
pub use service::lsps2::LSPS2ServiceConfig;
41-
pub(crate) use service::lsps2::{
42-
LSPS2Service, LSPS2_CHANNEL_CLTV_EXPIRY_DELTA, LSPS2_GETINFO_REQUEST_EXPIRY,
43-
};
4437

4538
pub(crate) const LIQUIDITY_REQUEST_TIMEOUT_SECS: u64 = 5;
4639

@@ -218,279 +211,22 @@ where
218211
log_error!(self.logger, "Received unexpected LSPS1Client event!");
219212
}
220213
},
221-
LiquidityEvent::LSPS2Service(LSPS2ServiceEvent::GetInfo {
222-
request_id,
223-
counterparty_node_id,
224-
token,
225-
}) => {
226-
if let Some(lsps2_service_handler) =
227-
self.liquidity_manager.lsps2_service_handler().as_ref()
228-
{
229-
let service_config = if let Some(service_config) =
230-
self.lsps2_service.as_ref().map(|s| s.service_config.clone())
231-
{
232-
service_config
233-
} else {
234-
log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
235-
return;
236-
};
237-
238-
if let Some(required) = service_config.require_token {
239-
if token != Some(required) {
240-
log_error!(
241-
self.logger,
242-
"Rejecting LSPS2 request {:?} from counterparty {} as the client provided an invalid token.",
243-
request_id,
244-
counterparty_node_id
245-
);
246-
lsps2_service_handler.invalid_token_provided(&counterparty_node_id, request_id.clone()).unwrap_or_else(|e| {
247-
debug_assert!(false, "Failed to reject LSPS2 request. This should never happen.");
248-
log_error!(
249-
self.logger,
250-
"Failed to reject LSPS2 request {:?} from counterparty {} due to: {:?}. This should never happen.",
251-
request_id,
252-
counterparty_node_id,
253-
e
254-
);
255-
});
256-
return;
257-
}
258-
}
259-
260-
let valid_until = LSPSDateTime(Utc::now() + LSPS2_GETINFO_REQUEST_EXPIRY);
261-
let opening_fee_params = LSPS2RawOpeningFeeParams {
262-
min_fee_msat: service_config.min_channel_opening_fee_msat,
263-
proportional: service_config.channel_opening_fee_ppm,
264-
valid_until,
265-
min_lifetime: service_config.min_channel_lifetime,
266-
max_client_to_self_delay: service_config.max_client_to_self_delay,
267-
min_payment_size_msat: service_config.min_payment_size_msat,
268-
max_payment_size_msat: service_config.max_payment_size_msat,
269-
};
270-
271-
let opening_fee_params_menu = vec![opening_fee_params];
272-
273-
if let Err(e) = lsps2_service_handler.opening_fee_params_generated(
274-
&counterparty_node_id,
275-
request_id,
276-
opening_fee_params_menu,
277-
) {
278-
log_error!(
279-
self.logger,
280-
"Failed to handle generated opening fee params: {:?}",
281-
e
282-
);
283-
}
284-
} else {
285-
log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
286-
return;
287-
}
288-
},
289-
LiquidityEvent::LSPS2Service(LSPS2ServiceEvent::BuyRequest {
290-
request_id,
291-
counterparty_node_id,
292-
opening_fee_params: _,
293-
payment_size_msat,
294-
}) => {
295-
if let Some(lsps2_service_handler) =
296-
self.liquidity_manager.lsps2_service_handler().as_ref()
297-
{
298-
let service_config = if let Some(service_config) =
299-
self.lsps2_service.as_ref().map(|s| s.service_config.clone())
300-
{
301-
service_config
302-
} else {
303-
log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
304-
return;
305-
};
306-
307-
let user_channel_id: u128 = u128::from_ne_bytes(
308-
self.keys_manager.get_secure_random_bytes()[..16]
309-
.try_into()
310-
.expect("a 16-byte slice should convert into a [u8; 16]"),
311-
);
312-
let intercept_scid = self.channel_manager.get_intercept_scid();
313-
314-
if let Some(payment_size_msat) = payment_size_msat {
315-
// We already check this in `lightning-liquidity`, but better safe than
316-
// sorry.
317-
//
318-
// TODO: We might want to eventually send back an error here, but we
319-
// currently can't and have to trust `lightning-liquidity` is doing the
320-
// right thing.
321-
//
322-
// TODO: Eventually we also might want to make sure that we have sufficient
323-
// liquidity for the channel opening here.
324-
if payment_size_msat > service_config.max_payment_size_msat
325-
|| payment_size_msat < service_config.min_payment_size_msat
326-
{
327-
log_error!(
328-
self.logger,
329-
"Rejecting to handle LSPS2 buy request {:?} from counterparty {} as the client requested an invalid payment size.",
330-
request_id,
331-
counterparty_node_id
332-
);
333-
return;
334-
}
335-
}
336-
337-
match lsps2_service_handler
338-
.invoice_parameters_generated(
339-
&counterparty_node_id,
340-
request_id,
341-
intercept_scid,
342-
LSPS2_CHANNEL_CLTV_EXPIRY_DELTA,
343-
service_config.client_trusts_lsp,
344-
user_channel_id,
214+
LiquidityEvent::LSPS2Service(event) => {
215+
if let Some(lsps2_service) = self.lsps2_service.as_ref() {
216+
lsps2_service
217+
.handle_next_event(
218+
event,
219+
&self.liquidity_manager,
220+
&self.channel_manager,
221+
&self.keys_manager,
222+
&self.peer_manager,
223+
&self.wallet,
224+
&self.config,
225+
&self.logger,
345226
)
346-
.await
347-
{
348-
Ok(()) => {},
349-
Err(e) => {
350-
log_error!(
351-
self.logger,
352-
"Failed to provide invoice parameters: {:?}",
353-
e
354-
);
355-
return;
356-
},
357-
}
358-
} else {
359-
log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
360-
return;
361-
}
362-
},
363-
LiquidityEvent::LSPS2Service(LSPS2ServiceEvent::OpenChannel {
364-
their_network_key,
365-
amt_to_forward_msat,
366-
opening_fee_msat: _,
367-
user_channel_id,
368-
intercept_scid: _,
369-
}) => {
370-
if self.liquidity_manager.lsps2_service_handler().is_none() {
371-
log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
372-
return;
373-
};
374-
375-
let service_config = if let Some(service_config) =
376-
self.lsps2_service.as_ref().map(|s| s.service_config.clone())
377-
{
378-
service_config
227+
.await;
379228
} else {
380229
log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as LSPS2 liquidity service was not configured.",);
381-
return;
382-
};
383-
384-
let init_features = if let Some(Some(peer_manager)) =
385-
self.peer_manager.read().expect("lock").as_ref().map(|weak| weak.upgrade())
386-
{
387-
// Fail if we're not connected to the prospective channel partner.
388-
if let Some(peer) = peer_manager.peer_by_node_id(&their_network_key) {
389-
peer.init_features
390-
} else {
391-
// TODO: We just silently fail here. Eventually we will need to remember
392-
// the pending requests and regularly retry opening the channel until we
393-
// succeed.
394-
log_error!(
395-
self.logger,
396-
"Failed to open LSPS2 channel to {} due to peer not being not connected.",
397-
their_network_key,
398-
);
399-
return;
400-
}
401-
} else {
402-
debug_assert!(false, "Failed to handle LSPS2ServiceEvent as peer manager isn't available. This should never happen.",);
403-
log_error!(self.logger, "Failed to handle LSPS2ServiceEvent as peer manager isn't available. This should never happen.",);
404-
return;
405-
};
406-
407-
// Fail if we have insufficient onchain funds available.
408-
let over_provisioning_msat = (amt_to_forward_msat
409-
* service_config.channel_over_provisioning_ppm as u64)
410-
/ 1_000_000;
411-
let channel_amount_sats = (amt_to_forward_msat + over_provisioning_msat) / 1000;
412-
let cur_anchor_reserve_sats =
413-
total_anchor_channels_reserve_sats(&self.channel_manager, &self.config);
414-
let spendable_amount_sats =
415-
self.wallet.get_spendable_amount_sats(cur_anchor_reserve_sats).unwrap_or(0);
416-
let required_funds_sats = channel_amount_sats
417-
+ self.config.anchor_channels_config.as_ref().map_or(0, |c| {
418-
if init_features.requires_anchors_zero_fee_htlc_tx()
419-
&& !c.trusted_peers_no_reserve.contains(&their_network_key)
420-
{
421-
c.per_channel_reserve_sats
422-
} else {
423-
0
424-
}
425-
});
426-
if spendable_amount_sats < required_funds_sats {
427-
log_error!(self.logger,
428-
"Unable to create channel due to insufficient funds. Available: {}sats, Required: {}sats",
429-
spendable_amount_sats, channel_amount_sats
430-
);
431-
// TODO: We just silently fail here. Eventually we will need to remember
432-
// the pending requests and regularly retry opening the channel until we
433-
// succeed.
434-
return;
435-
}
436-
437-
let mut config = self.channel_manager.get_current_config().clone();
438-
439-
// If we act as an LSPS2 service, the HTLC-value-in-flight must be 100% of the
440-
// channel value to ensure we can forward the initial payment. That cap only
441-
// applies to unannounced channels, so the channel must also be unannounced.
442-
debug_assert_eq!(
443-
config
444-
.channel_handshake_config
445-
.unannounced_channel_max_inbound_htlc_value_in_flight_percentage,
446-
100
447-
);
448-
debug_assert!(!config.channel_handshake_config.announce_for_forwarding);
449-
debug_assert!(config.accept_forwards_to_priv_channels);
450-
451-
// We set the forwarding fee to 0 for now as we're getting paid by the channel fee.
452-
//
453-
// TODO: revisit this decision eventually.
454-
config.channel_config.forwarding_fee_base_msat = 0;
455-
config.channel_config.forwarding_fee_proportional_millionths = 0;
456-
457-
let result = if service_config.disable_client_reserve {
458-
self.channel_manager.create_channel_to_trusted_peer_0reserve(
459-
their_network_key,
460-
channel_amount_sats,
461-
0,
462-
user_channel_id,
463-
None,
464-
Some(config),
465-
)
466-
} else {
467-
self.channel_manager.create_channel(
468-
their_network_key,
469-
channel_amount_sats,
470-
0,
471-
user_channel_id,
472-
None,
473-
Some(config),
474-
)
475-
};
476-
477-
match result {
478-
Ok(_) => {},
479-
Err(e) => {
480-
// TODO: We just silently fail here. Eventually we will need to remember
481-
// the pending requests and regularly retry opening the channel until we
482-
// succeed.
483-
let zero_reserve_string =
484-
if service_config.disable_client_reserve { "0reserve " } else { "" };
485-
log_error!(
486-
self.logger,
487-
"Failed to open LSPS2 {}channel to {}: {:?}",
488-
zero_reserve_string,
489-
their_network_key,
490-
e
491-
);
492-
return;
493-
},
494230
}
495231
},
496232
LiquidityEvent::LSPS2Client(event) => {

0 commit comments

Comments
 (0)