Skip to content

Commit 27be2eb

Browse files
LSPS1: Service refactor - Part 1.
- Remove dead / unnecesary functions, dependencies, etc. - Add the first LSPS1 integration test. There are no breaking API changes, ldk-node should function as usual
1 parent b5bfa85 commit 27be2eb

File tree

3 files changed

+249
-41
lines changed

3 files changed

+249
-41
lines changed

lightning-liquidity/src/lsps1/service.rs

Lines changed: 4 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,13 @@ use crate::prelude::{new_hash_map, HashMap};
3030
use crate::sync::{Arc, Mutex, RwLock};
3131
use crate::utils;
3232

33-
use lightning::chain::Filter;
34-
use lightning::ln::channelmanager::AChannelManager;
3533
use lightning::ln::msgs::{ErrorAction, LightningError};
3634
use lightning::sign::EntropySource;
3735
use lightning::util::errors::APIError;
3836
use lightning::util::logger::Level;
3937

4038
use bitcoin::secp256k1::PublicKey;
4139

42-
use chrono::Utc;
43-
4440
/// Server-side configuration options for bLIP-51 / LSPS1 channel requests.
4541
#[derive(Clone, Debug)]
4642
pub struct LSPS1ServiceConfig {
@@ -62,7 +58,6 @@ impl From<ChannelStateError> for LightningError {
6258
enum OutboundRequestState {
6359
OrderCreated { order_id: LSPS1OrderId },
6460
WaitingPayment { order_id: LSPS1OrderId },
65-
Ready,
6661
}
6762

6863
impl OutboundRequestState {
@@ -101,67 +96,43 @@ impl OutboundCRChannel {
10196
self.state = self.state.awaiting_payment()?;
10297
Ok(())
10398
}
104-
105-
fn check_order_validity(&self, supported_options: &LSPS1Options) -> bool {
106-
let order = &self.config.order;
107-
108-
is_valid(order, supported_options)
109-
}
11099
}
111100

112101
#[derive(Default)]
113102
struct PeerState {
114103
outbound_channels_by_order_id: HashMap<LSPS1OrderId, OutboundCRChannel>,
115-
request_to_cid: HashMap<LSPSRequestId, u128>,
116104
pending_requests: HashMap<LSPSRequestId, LSPS1Request>,
117105
}
118106

119107
impl PeerState {
120108
fn insert_outbound_channel(&mut self, order_id: LSPS1OrderId, channel: OutboundCRChannel) {
121109
self.outbound_channels_by_order_id.insert(order_id, channel);
122110
}
123-
124-
fn insert_request(&mut self, request_id: LSPSRequestId, channel_id: u128) {
125-
self.request_to_cid.insert(request_id, channel_id);
126-
}
127-
128-
fn remove_outbound_channel(&mut self, order_id: LSPS1OrderId) {
129-
self.outbound_channels_by_order_id.remove(&order_id);
130-
}
131111
}
132112

133113
/// The main object allowing to send and receive bLIP-51 / LSPS1 messages.
134-
pub struct LSPS1ServiceHandler<ES: Deref, CM: Deref + Clone, C: Deref>
114+
pub struct LSPS1ServiceHandler<ES: Deref>
135115
where
136116
ES::Target: EntropySource,
137-
CM::Target: AChannelManager,
138-
C::Target: Filter,
139117
{
140118
entropy_source: ES,
141-
channel_manager: CM,
142-
chain_source: Option<C>,
143119
pending_messages: Arc<MessageQueue>,
144120
pending_events: Arc<EventQueue>,
145121
per_peer_state: RwLock<HashMap<PublicKey, Mutex<PeerState>>>,
146122
config: LSPS1ServiceConfig,
147123
}
148124

149-
impl<ES: Deref, CM: Deref + Clone, C: Deref> LSPS1ServiceHandler<ES, CM, C>
125+
impl<ES: Deref> LSPS1ServiceHandler<ES>
150126
where
151127
ES::Target: EntropySource,
152-
CM::Target: AChannelManager,
153-
C::Target: Filter,
154-
ES::Target: EntropySource,
155128
{
156129
/// Constructs a `LSPS1ServiceHandler`.
157130
pub(crate) fn new(
158131
entropy_source: ES, pending_messages: Arc<MessageQueue>, pending_events: Arc<EventQueue>,
159-
channel_manager: CM, chain_source: Option<C>, config: LSPS1ServiceConfig,
132+
config: LSPS1ServiceConfig,
160133
) -> Self {
161134
Self {
162135
entropy_source,
163-
channel_manager,
164-
chain_source,
165136
pending_messages,
166137
pending_events,
167138
per_peer_state: RwLock::new(new_hash_map()),
@@ -432,12 +403,9 @@ where
432403
}
433404
}
434405

435-
impl<ES: Deref, CM: Deref + Clone, C: Deref> LSPSProtocolMessageHandler
436-
for LSPS1ServiceHandler<ES, CM, C>
406+
impl<ES: Deref> LSPSProtocolMessageHandler for LSPS1ServiceHandler<ES>
437407
where
438408
ES::Target: EntropySource,
439-
CM::Target: AChannelManager,
440-
C::Target: Filter,
441409
{
442410
type ProtocolMessage = LSPS1Message;
443411
const PROTOCOL_NUMBER: Option<u16> = Some(1);

lightning-liquidity/src/manager.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ where
140140
lsps0_client_handler: LSPS0ClientHandler<ES>,
141141
lsps0_service_handler: Option<LSPS0ServiceHandler>,
142142
#[cfg(lsps1_service)]
143-
lsps1_service_handler: Option<LSPS1ServiceHandler<ES, CM, C>>,
143+
lsps1_service_handler: Option<LSPS1ServiceHandler<ES>>,
144144
lsps1_client_handler: Option<LSPS1ClientHandler<ES>>,
145145
lsps2_service_handler: Option<LSPS2ServiceHandler<CM>>,
146146
lsps2_client_handler: Option<LSPS2ClientHandler<ES>>,
@@ -212,7 +212,7 @@ where {
212212
#[cfg(lsps1_service)]
213213
let lsps1_service_handler = service_config.as_ref().and_then(|config| {
214214
if let Some(number) =
215-
<LSPS1ServiceHandler<ES, CM, C> as LSPSProtocolMessageHandler>::PROTOCOL_NUMBER
215+
<LSPS1ServiceHandler<ES> as LSPSProtocolMessageHandler>::PROTOCOL_NUMBER
216216
{
217217
supported_protocols.push(number);
218218
}
@@ -221,8 +221,6 @@ where {
221221
entropy_source.clone(),
222222
Arc::clone(&pending_messages),
223223
Arc::clone(&pending_events),
224-
channel_manager.clone(),
225-
chain_source.clone(),
226224
config.clone(),
227225
)
228226
})
@@ -279,7 +277,7 @@ where {
279277

280278
/// Returns a reference to the LSPS1 server-side handler.
281279
#[cfg(lsps1_service)]
282-
pub fn lsps1_service_handler(&self) -> Option<&LSPS1ServiceHandler<ES, CM, C>> {
280+
pub fn lsps1_service_handler(&self) -> Option<&LSPS1ServiceHandler<ES>> {
283281
self.lsps1_service_handler.as_ref()
284282
}
285283

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,242 @@
1+
#![cfg(all(test, feature = "std"))]
2+
3+
mod common;
4+
5+
#[cfg(lsps1_service)]
6+
use {
7+
bitcoin::secp256k1::SecretKey,
8+
common::create_service_and_client_nodes,
9+
common::{get_lsps_message, Node},
10+
lightning::ln::peer_handler::CustomMessageHandler,
11+
lightning_liquidity::events::LiquidityEvent,
12+
lightning_liquidity::lsps0::ser::LSPSDateTime,
13+
lightning_liquidity::lsps1::client::LSPS1ClientConfig,
14+
lightning_liquidity::lsps1::event::LSPS1ClientEvent,
15+
lightning_liquidity::lsps1::event::LSPS1ServiceEvent,
16+
lightning_liquidity::lsps1::msgs::LSPS1OrderState,
17+
lightning_liquidity::lsps1::msgs::{
18+
LSPS1OnchainPaymentInfo, LSPS1Options, LSPS1OrderParams, LSPS1PaymentInfo,
19+
},
20+
lightning_liquidity::lsps1::service::LSPS1ServiceConfig,
21+
lightning_liquidity::{LiquidityClientConfig, LiquidityServiceConfig},
22+
std::str::FromStr,
23+
};
24+
25+
#[cfg(lsps1_service)]
26+
fn setup_test_lsps1(
27+
persist_dir: &str, _supported_options: LSPS1Options,
28+
) -> (bitcoin::secp256k1::PublicKey, bitcoin::secp256k1::PublicKey, Node, Node, [u8; 32]) {
29+
let promise_secret = [42; 32];
30+
let signing_key = SecretKey::from_slice(&promise_secret).unwrap();
31+
32+
let lsps1_service_config =
33+
LSPS1ServiceConfig { token: None, supported_options: Some(_supported_options) };
34+
let service_config: LiquidityServiceConfig = LiquidityServiceConfig {
35+
lsps1_service_config: Some(lsps1_service_config),
36+
lsps2_service_config: None,
37+
advertise_service: true,
38+
};
39+
40+
let lsps1_client_config = LSPS1ClientConfig { max_channel_fees_msat: None };
41+
let client_config = LiquidityClientConfig {
42+
lsps1_client_config: Some(lsps1_client_config),
43+
lsps2_client_config: None,
44+
};
45+
46+
let (service_node, client_node) =
47+
create_service_and_client_nodes(persist_dir, service_config, client_config);
48+
49+
let secp = bitcoin::secp256k1::Secp256k1::new();
50+
let service_node_id = bitcoin::secp256k1::PublicKey::from_secret_key(&secp, &signing_key);
51+
let client_node_id = client_node.channel_manager.get_our_node_id();
52+
53+
(service_node_id, client_node_id, service_node, client_node, promise_secret)
54+
}
55+
56+
#[cfg(lsps1_service)]
57+
#[test]
58+
fn lsps1_happy_path() {
59+
let expected_options_supported = LSPS1Options {
60+
min_required_channel_confirmations: 0,
61+
min_funding_confirms_within_blocks: 6,
62+
supports_zero_channel_reserve: true,
63+
max_channel_expiry_blocks: 144,
64+
min_initial_client_balance_sat: 10_000_000,
65+
max_initial_client_balance_sat: 100_000_000,
66+
min_initial_lsp_balance_sat: 100_000,
67+
max_initial_lsp_balance_sat: 100_000_000,
68+
min_channel_balance_sat: 100_000,
69+
max_channel_balance_sat: 100_000_000,
70+
};
71+
72+
let (service_node_id, client_node_id, service_node, client_node, _) =
73+
setup_test_lsps1("lsps1_happy_path", expected_options_supported.clone());
74+
75+
let client_handler = client_node.liquidity_manager.lsps1_client_handler().unwrap();
76+
77+
let service_handler = service_node.liquidity_manager.lsps1_service_handler().unwrap();
78+
79+
let request_supported_options_id = client_handler.request_supported_options(service_node_id);
80+
let request_supported_options = get_lsps_message!(client_node, service_node_id);
81+
82+
service_node
83+
.liquidity_manager
84+
.handle_custom_message(request_supported_options, client_node_id)
85+
.unwrap();
86+
87+
let get_info_message = get_lsps_message!(service_node, client_node_id);
88+
89+
client_node.liquidity_manager.handle_custom_message(get_info_message, service_node_id).unwrap();
90+
91+
let get_info_event = client_node.liquidity_manager.next_event().unwrap();
92+
if let LiquidityEvent::LSPS1Client(LSPS1ClientEvent::SupportedOptionsReady {
93+
request_id,
94+
counterparty_node_id,
95+
supported_options,
96+
}) = get_info_event
97+
{
98+
assert_eq!(request_id, request_supported_options_id);
99+
assert_eq!(counterparty_node_id, service_node_id);
100+
assert_eq!(expected_options_supported, supported_options);
101+
} else {
102+
panic!("Unexpected event");
103+
}
104+
105+
let order_params = LSPS1OrderParams {
106+
lsp_balance_sat: 100_000,
107+
client_balance_sat: 10_000_000,
108+
required_channel_confirmations: 0,
109+
funding_confirms_within_blocks: 6,
110+
channel_expiry_blocks: 144,
111+
token: None,
112+
announce_channel: true,
113+
};
114+
115+
let _create_order_id =
116+
client_handler.create_order(&service_node_id, order_params.clone(), None);
117+
let create_order = get_lsps_message!(client_node, service_node_id);
118+
119+
service_node.liquidity_manager.handle_custom_message(create_order, client_node_id).unwrap();
120+
121+
let _request_for_payment_event = service_node.liquidity_manager.next_event().unwrap();
122+
123+
if let LiquidityEvent::LSPS1Service(LSPS1ServiceEvent::RequestForPaymentDetails {
124+
request_id,
125+
counterparty_node_id,
126+
order,
127+
}) = _request_for_payment_event
128+
{
129+
assert_eq!(request_id, _create_order_id.clone());
130+
assert_eq!(counterparty_node_id, client_node_id);
131+
assert_eq!(order, order_params);
132+
} else {
133+
panic!("Unexpected event");
134+
}
135+
136+
let json_str = r#"{
137+
"state": "EXPECT_PAYMENT",
138+
"expires_at": "2025-01-01T00:00:00Z",
139+
"fee_total_sat": "9999",
140+
"order_total_sat": "200999",
141+
"address": "bc1p5uvtaxzkjwvey2tfy49k5vtqfpjmrgm09cvs88ezyy8h2zv7jhas9tu4yr",
142+
"min_onchain_payment_confirmations": 1,
143+
"min_fee_for_0conf": 253
144+
}"#;
145+
146+
let onchain: LSPS1OnchainPaymentInfo =
147+
serde_json::from_str(json_str).expect("Failed to parse JSON");
148+
let payment_info = LSPS1PaymentInfo { bolt11: None, bolt12: None, onchain: Some(onchain) };
149+
let _now = LSPSDateTime::from_str("2024-01-01T00:00:00Z").expect("Failed to parse date");
150+
151+
let _ = service_handler
152+
.send_payment_details(_create_order_id.clone(), &client_node_id, payment_info.clone(), _now)
153+
.unwrap();
154+
155+
let create_order_response = get_lsps_message!(service_node, client_node_id);
156+
157+
client_node
158+
.liquidity_manager
159+
.handle_custom_message(create_order_response, service_node_id)
160+
.unwrap();
161+
162+
let order_created_event = client_node.liquidity_manager.next_event().unwrap();
163+
let expected_order_id = if let LiquidityEvent::LSPS1Client(LSPS1ClientEvent::OrderCreated {
164+
request_id,
165+
counterparty_node_id,
166+
order_id,
167+
order,
168+
payment,
169+
channel,
170+
}) = order_created_event
171+
{
172+
assert_eq!(request_id, _create_order_id);
173+
assert_eq!(counterparty_node_id, service_node_id);
174+
assert_eq!(order, order_params);
175+
assert_eq!(payment, payment_info);
176+
assert!(channel.is_none());
177+
order_id
178+
} else {
179+
panic!("Unexpected event");
180+
};
181+
182+
let check_order_status_id =
183+
client_handler.check_order_status(&service_node_id, expected_order_id.clone());
184+
let check_order_status = get_lsps_message!(client_node, service_node_id);
185+
186+
service_node
187+
.liquidity_manager
188+
.handle_custom_message(check_order_status, client_node_id)
189+
.unwrap();
190+
191+
let _check_payment_confirmation_event = service_node.liquidity_manager.next_event().unwrap();
192+
193+
if let LiquidityEvent::LSPS1Service(LSPS1ServiceEvent::CheckPaymentConfirmation {
194+
request_id,
195+
counterparty_node_id,
196+
order_id,
197+
}) = _check_payment_confirmation_event
198+
{
199+
assert_eq!(request_id, check_order_status_id);
200+
assert_eq!(counterparty_node_id, client_node_id);
201+
assert_eq!(order_id, expected_order_id.clone());
202+
} else {
203+
panic!("Unexpected event");
204+
}
205+
206+
let _ = service_handler
207+
.update_order_status(
208+
check_order_status_id.clone(),
209+
client_node_id,
210+
expected_order_id.clone(),
211+
LSPS1OrderState::Created,
212+
None,
213+
)
214+
.unwrap();
215+
216+
let order_status_response = get_lsps_message!(service_node, client_node_id);
217+
218+
client_node
219+
.liquidity_manager
220+
.handle_custom_message(order_status_response, service_node_id)
221+
.unwrap();
222+
223+
let order_status_event = client_node.liquidity_manager.next_event().unwrap();
224+
if let LiquidityEvent::LSPS1Client(LSPS1ClientEvent::OrderStatus {
225+
request_id,
226+
counterparty_node_id,
227+
order_id,
228+
order,
229+
payment,
230+
channel,
231+
}) = order_status_event
232+
{
233+
assert_eq!(request_id, check_order_status_id);
234+
assert_eq!(counterparty_node_id, service_node_id);
235+
assert_eq!(order, order_params);
236+
assert_eq!(payment, payment_info);
237+
assert!(channel.is_none());
238+
assert_eq!(order_id, expected_order_id);
239+
} else {
240+
panic!("Unexpected event");
241+
}
242+
}

0 commit comments

Comments
 (0)