Skip to content

Commit 95da17a

Browse files
committed
Refactor CLN/LND tests and add Eclair test entry points
Add CLN splice support
1 parent 42c4e0e commit 95da17a

3 files changed

Lines changed: 760 additions & 267 deletions

File tree

tests/integration_tests_cln.rs

Lines changed: 280 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -9,119 +9,306 @@
99

1010
mod common;
1111

12-
use std::default::Default;
1312
use std::str::FromStr;
1413

15-
use clightningrpc::lightningrpc::LightningRPC;
16-
use clightningrpc::responses::NetworkAddress;
1714
use electrsd::corepc_client::client_sync::Auth;
1815
use electrsd::corepc_node::Client as BitcoindClient;
1916
use electrum_client::Client as ElectrumClient;
20-
use ldk_node::bitcoin::secp256k1::PublicKey;
21-
use ldk_node::bitcoin::Amount;
22-
use ldk_node::lightning::ln::msgs::SocketAddress;
2317
use ldk_node::{Builder, Event};
24-
use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, Description};
25-
use rand::distr::Alphanumeric;
26-
use rand::{rng, Rng};
18+
use proptest::prelude::*;
19+
use proptest::proptest;
2720

28-
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
29-
async fn test_cln() {
30-
// Setup bitcoind / electrs clients
31-
let bitcoind_client = BitcoindClient::new_with_auth(
21+
use common::cln::TestClnNode;
22+
use common::external_node::ExternalNode;
23+
use common::scenarios::channel::{
24+
open_channel_to_external, run_inbound_channel_test, test_cooperative_close_after_fee_change,
25+
test_cooperative_close_by_ldk, test_force_close_after_fee_change, test_force_close_by_external,
26+
test_force_close_by_ldk,
27+
};
28+
use common::scenarios::disconnect::test_disconnect_reconnect_idle;
29+
use common::scenarios::payment::{
30+
run_interop_property_test, test_bidirectional_payments, test_concurrent_payments,
31+
test_pay_expired_invoice, test_receive_bolt11_payment, test_receive_keysend_payment,
32+
};
33+
use common::scenarios::splice::{test_splice_from_external, test_splice_then_payment};
34+
use common::scenarios::{setup_interop_test, CloseType, PayType, Phase, Side};
35+
36+
fn setup_clients() -> (BitcoindClient, ElectrumClient, TestClnNode) {
37+
let bitcoind = BitcoindClient::new_with_auth(
3238
"http://127.0.0.1:18443",
3339
Auth::UserPass("user".to_string(), "pass".to_string()),
3440
)
3541
.unwrap();
36-
let electrs_client = ElectrumClient::new("tcp://127.0.0.1:50001").unwrap();
37-
38-
// Give electrs a kick.
39-
common::generate_blocks_and_wait(&bitcoind_client, &electrs_client, 1).await;
42+
let electrs = ElectrumClient::new("tcp://127.0.0.1:50001").unwrap();
43+
let cln = TestClnNode::from_env();
44+
(bitcoind, electrs, cln)
45+
}
4046

41-
// Setup LDK Node
47+
fn setup_ldk_node() -> ldk_node::Node {
4248
let config = common::random_config(true);
4349
let mut builder = Builder::from_config(config.node_config);
4450
builder.set_chain_source_esplora("http://127.0.0.1:3002".to_string(), None);
45-
4651
let node = builder.build(config.node_entropy).unwrap();
4752
node.start().unwrap();
53+
node
54+
}
55+
56+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
57+
async fn test_cln_basic_channel_cycle() {
58+
let (bitcoind, electrs, cln) = setup_clients();
59+
cln.wait_for_sync().await;
60+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
61+
62+
let node = setup_ldk_node();
63+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
64+
65+
let (user_channel_id, _ext_channel_id) =
66+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
67+
.await;
68+
69+
// LDK -> CLN payment
70+
let invoice = cln.create_invoice(10_000_000, "cln-test-send").await.unwrap();
71+
let parsed = lightning_invoice::Bolt11Invoice::from_str(&invoice).unwrap();
72+
node.bolt11_payment().send(&parsed, None).unwrap();
73+
common::expect_event!(node, PaymentSuccessful);
4874

49-
// Premine some funds and distribute
50-
let address = node.onchain_payment().new_address().unwrap();
51-
let premine_amount = Amount::from_sat(5_000_000);
52-
common::premine_and_distribute_funds(
53-
&bitcoind_client,
54-
&electrs_client,
55-
vec![address],
56-
premine_amount,
75+
// CLN -> LDK payment
76+
test_receive_bolt11_payment(&node, &cln, 10_000_000).await;
77+
78+
test_cooperative_close_by_ldk(&node, &cln, &user_channel_id).await;
79+
node.stop().unwrap();
80+
}
81+
82+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
83+
async fn test_cln_disconnect_reconnect() {
84+
let (bitcoind, electrs, cln) = setup_clients();
85+
cln.wait_for_sync().await;
86+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
87+
88+
let node = setup_ldk_node();
89+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
90+
let (_user_ch, _ext_ch) =
91+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
92+
.await;
93+
94+
test_disconnect_reconnect_idle(&node, &cln, &bitcoind, &electrs, &Side::Ldk).await;
95+
test_disconnect_reconnect_idle(&node, &cln, &bitcoind, &electrs, &Side::External).await;
96+
97+
node.stop().unwrap();
98+
}
99+
100+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
101+
async fn test_cln_force_close_by_ldk() {
102+
let (bitcoind, electrs, cln) = setup_clients();
103+
cln.wait_for_sync().await;
104+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
105+
106+
let node = setup_ldk_node();
107+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
108+
let (user_ch, _ext_ch) =
109+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
110+
.await;
111+
112+
test_force_close_by_ldk(&node, &cln, &bitcoind, &electrs, &user_ch).await;
113+
node.stop().unwrap();
114+
}
115+
116+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
117+
async fn test_cln_force_close_by_external() {
118+
let (bitcoind, electrs, cln) = setup_clients();
119+
cln.wait_for_sync().await;
120+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
121+
122+
let node = setup_ldk_node();
123+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
124+
let (_user_ch, ext_ch) =
125+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
126+
.await;
127+
128+
test_force_close_by_external(&node, &cln, &bitcoind, &electrs, &ext_ch).await;
129+
node.stop().unwrap();
130+
}
131+
132+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
133+
async fn test_cln_splice() {
134+
let (bitcoind, electrs, cln) = setup_clients();
135+
cln.wait_for_sync().await;
136+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
137+
138+
let node = setup_ldk_node();
139+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
140+
let (_user_ch, ext_ch) =
141+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
142+
.await;
143+
144+
test_splice_from_external(&node, &cln, &bitcoind, &electrs, &ext_ch).await;
145+
146+
// Verify the channel still works after splicing
147+
let invoice = cln.create_invoice(10_000_000, "post-splice-test").await.unwrap();
148+
let parsed = lightning_invoice::Bolt11Invoice::from_str(&invoice).unwrap();
149+
node.bolt11_payment().send(&parsed, None).unwrap();
150+
common::expect_event!(node, PaymentSuccessful);
151+
152+
test_cooperative_close_by_ldk(&node, &cln, &_user_ch).await;
153+
node.stop().unwrap();
154+
}
155+
156+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
157+
async fn test_cln_inbound_channel() {
158+
let (bitcoind, electrs, cln) = setup_clients();
159+
cln.wait_for_sync().await;
160+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
161+
162+
let node = setup_ldk_node();
163+
run_inbound_channel_test(
164+
&node,
165+
&cln,
166+
&bitcoind,
167+
&electrs,
168+
CloseType::Cooperative,
169+
Side::External,
57170
)
58171
.await;
172+
node.stop().unwrap();
173+
}
174+
175+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
176+
async fn test_cln_receive_payments() {
177+
let (bitcoind, electrs, cln) = setup_clients();
178+
cln.wait_for_sync().await;
179+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
180+
181+
let node = setup_ldk_node();
182+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
183+
let (_user_ch, _ext_ch) =
184+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
185+
.await;
186+
187+
test_receive_bolt11_payment(&node, &cln, 5_000_000).await;
188+
test_receive_keysend_payment(&node, &cln, 5_000_000).await;
189+
190+
node.stop().unwrap();
191+
}
192+
193+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
194+
async fn test_cln_bidirectional_payments() {
195+
let (bitcoind, electrs, cln) = setup_clients();
196+
cln.wait_for_sync().await;
197+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
198+
199+
let node = setup_ldk_node();
200+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
201+
let (_user_ch, ext_ch) =
202+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
203+
.await;
204+
205+
test_bidirectional_payments(&node, &cln, &ext_ch, 5_000_000).await;
206+
207+
node.stop().unwrap();
208+
}
209+
210+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
211+
async fn test_cln_pay_expired_invoice() {
212+
let (bitcoind, electrs, cln) = setup_clients();
213+
cln.wait_for_sync().await;
214+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
215+
216+
let node = setup_ldk_node();
217+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
218+
let (_user_ch, _ext_ch) =
219+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
220+
.await;
221+
222+
test_pay_expired_invoice(&node, &cln).await;
59223

60-
// Setup CLN
61-
let sock = "/tmp/lightning-rpc";
62-
let cln_client = LightningRPC::new(&sock);
63-
let cln_info = {
64-
loop {
65-
let info = cln_client.getinfo().unwrap();
66-
// Wait for CLN to sync block height before channel open.
67-
// Prevents crash due to unset blockheight (see LDK Node issue #527).
68-
if info.blockheight > 0 {
69-
break info;
70-
}
71-
tokio::time::sleep(std::time::Duration::from_millis(250)).await;
72-
}
73-
};
74-
let cln_node_id = PublicKey::from_str(&cln_info.id).unwrap();
75-
let cln_address: SocketAddress = match cln_info.binding.first().unwrap() {
76-
NetworkAddress::Ipv4 { address, port } => {
77-
std::net::SocketAddrV4::new(*address, *port).into()
78-
},
79-
NetworkAddress::Ipv6 { address, port } => {
80-
std::net::SocketAddrV6::new(*address, *port, 0, 0).into()
81-
},
82-
_ => {
83-
panic!()
84-
},
85-
};
86-
87-
node.sync_wallets().unwrap();
88-
89-
// Open the channel
90-
let funding_amount_sat = 1_000_000;
91-
92-
node.open_channel(cln_node_id, cln_address, funding_amount_sat, Some(500_000_000), None)
93-
.unwrap();
94-
95-
let funding_txo = common::expect_channel_pending_event!(node, cln_node_id);
96-
common::wait_for_tx(&electrs_client, funding_txo.txid).await;
97-
common::generate_blocks_and_wait(&bitcoind_client, &electrs_client, 6).await;
98-
node.sync_wallets().unwrap();
99-
let user_channel_id = common::expect_channel_ready_event!(node, cln_node_id);
100-
101-
// Send a payment to CLN
102-
let mut rng = rng();
103-
let rand_label: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
104-
let cln_invoice =
105-
cln_client.invoice(Some(10_000_000), &rand_label, &rand_label, None, None, None).unwrap();
106-
let parsed_invoice = Bolt11Invoice::from_str(&cln_invoice.bolt11).unwrap();
107-
108-
node.bolt11_payment().send(&parsed_invoice, None).unwrap();
109-
common::expect_event!(node, PaymentSuccessful);
110-
let cln_listed_invoices =
111-
cln_client.listinvoices(Some(&rand_label), None, None, None).unwrap().invoices;
112-
assert_eq!(cln_listed_invoices.len(), 1);
113-
assert_eq!(cln_listed_invoices.first().unwrap().status, "paid");
114-
115-
// Send a payment to LDK
116-
let rand_label: String = (0..7).map(|_| rng.sample(Alphanumeric) as char).collect();
117-
let invoice_description =
118-
Bolt11InvoiceDescription::Direct(Description::new(rand_label).unwrap());
119-
let ldk_invoice =
120-
node.bolt11_payment().receive(10_000_000, &invoice_description, 3600).unwrap();
121-
cln_client.pay(&ldk_invoice.to_string(), Default::default()).unwrap();
122-
common::expect_event!(node, PaymentReceived);
123-
124-
node.close_channel(&user_channel_id, cln_node_id).unwrap();
125-
common::expect_event!(node, ChannelClosed);
126224
node.stop().unwrap();
127225
}
226+
227+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
228+
async fn test_cln_concurrent_payments() {
229+
let (bitcoind, electrs, cln) = setup_clients();
230+
cln.wait_for_sync().await;
231+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
232+
233+
let node = setup_ldk_node();
234+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
235+
let (_user_ch, _ext_ch) =
236+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
237+
.await;
238+
239+
test_concurrent_payments(&node, &cln, 5, 1_000_000).await;
240+
241+
node.stop().unwrap();
242+
}
243+
244+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
245+
async fn test_cln_splice_then_payment() {
246+
let (bitcoind, electrs, cln) = setup_clients();
247+
cln.wait_for_sync().await;
248+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
249+
250+
let node = setup_ldk_node();
251+
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
252+
let (_user_ch, ext_ch) =
253+
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
254+
.await;
255+
256+
test_splice_then_payment(&node, &cln, &bitcoind, &electrs, &ext_ch).await;
257+
258+
node.stop().unwrap();
259+
}
260+
261+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
262+
async fn test_cln_cooperative_close_after_fee_change() {
263+
let (bitcoind, electrs, cln) = setup_clients();
264+
cln.wait_for_sync().await;
265+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
266+
267+
let node = setup_ldk_node();
268+
test_cooperative_close_after_fee_change(&node, &cln, &bitcoind, &electrs).await;
269+
node.stop().unwrap();
270+
}
271+
272+
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
273+
async fn test_cln_force_close_after_fee_change() {
274+
let (bitcoind, electrs, cln) = setup_clients();
275+
cln.wait_for_sync().await;
276+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
277+
278+
let node = setup_ldk_node();
279+
test_force_close_after_fee_change(&node, &cln, &bitcoind, &electrs).await;
280+
node.stop().unwrap();
281+
}
282+
283+
proptest! {
284+
#![proptest_config(proptest::test_runner::Config::with_cases(8))]
285+
#[test]
286+
fn test_cln_interop_proptest(
287+
disconnect_phase in prop_oneof![
288+
Just(Phase::Payment),
289+
Just(Phase::Idle),
290+
],
291+
disconnect_initiator in prop_oneof![Just(Side::Ldk), Just(Side::External)],
292+
close_type in prop_oneof![Just(CloseType::Cooperative), Just(CloseType::Force)],
293+
close_initiator in prop_oneof![Just(Side::Ldk), Just(Side::External)],
294+
payment_type in prop_oneof![Just(PayType::Bolt11), Just(PayType::Keysend)],
295+
) {
296+
let rt = tokio::runtime::Builder::new_multi_thread()
297+
.enable_all()
298+
.build()
299+
.unwrap();
300+
rt.block_on(async {
301+
let (bitcoind, electrs, cln) = setup_clients();
302+
cln.wait_for_sync().await;
303+
common::generate_blocks_and_wait(&bitcoind, &electrs, 1).await;
304+
305+
let node = setup_ldk_node();
306+
run_interop_property_test(
307+
&node, &cln, &bitcoind, &electrs,
308+
disconnect_phase, disconnect_initiator, close_type,
309+
close_initiator, payment_type,
310+
).await;
311+
node.stop().unwrap();
312+
});
313+
}
314+
}

0 commit comments

Comments
 (0)