|
9 | 9 |
|
10 | 10 | mod common; |
11 | 11 |
|
12 | | -use std::default::Default; |
13 | 12 | use std::str::FromStr; |
14 | 13 |
|
15 | | -use clightningrpc::lightningrpc::LightningRPC; |
16 | | -use clightningrpc::responses::NetworkAddress; |
| 14 | +use common::cln::TestClnNode; |
| 15 | +use common::external_node::ExternalNode; |
| 16 | +use common::scenarios::channel::{ |
| 17 | + open_channel_to_external, run_inbound_channel_test, test_cooperative_close_after_fee_change, |
| 18 | + test_cooperative_close_by_ldk, test_force_close_after_fee_change, test_force_close_by_external, |
| 19 | + test_force_close_by_ldk, |
| 20 | +}; |
| 21 | +use common::scenarios::disconnect::test_disconnect_reconnect_idle; |
| 22 | +use common::scenarios::payment::{ |
| 23 | + run_interop_property_test, test_bidirectional_payments, test_concurrent_payments, |
| 24 | + test_pay_expired_invoice, test_receive_bolt11_payment, |
| 25 | +}; |
| 26 | +use common::scenarios::splice::{test_splice_from_external, test_splice_then_payment}; |
| 27 | +use common::scenarios::{setup_interop_test, CloseType, PayType, Phase, Side}; |
17 | 28 | use electrsd::corepc_client::client_sync::Auth; |
18 | 29 | use electrsd::corepc_node::Client as BitcoindClient; |
19 | 30 | 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; |
23 | 31 | use ldk_node::{Builder, Event}; |
24 | | -use lightning_invoice::{Bolt11Invoice, Bolt11InvoiceDescription, Description}; |
25 | | -use rand::distr::Alphanumeric; |
26 | | -use rand::{rng, Rng}; |
27 | 32 |
|
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( |
| 33 | +async fn setup_clients() -> (BitcoindClient, ElectrumClient, TestClnNode) { |
| 34 | + let bitcoind = BitcoindClient::new_with_auth( |
32 | 35 | "http://127.0.0.1:18443", |
33 | 36 | Auth::UserPass("user".to_string(), "pass".to_string()), |
34 | 37 | ) |
35 | 38 | .unwrap(); |
36 | | - let electrs_client = ElectrumClient::new("tcp://127.0.0.1:50001").unwrap(); |
| 39 | + let electrs = ElectrumClient::new("tcp://127.0.0.1:50001").unwrap(); |
37 | 40 |
|
38 | | - // Give electrs a kick. |
39 | | - common::generate_blocks_and_wait(&bitcoind_client, &electrs_client, 1).await; |
| 41 | + let cln = TestClnNode::from_env(); |
| 42 | + (bitcoind, electrs, cln) |
| 43 | +} |
40 | 44 |
|
41 | | - // Setup LDK Node |
| 45 | +fn setup_ldk_node() -> ldk_node::Node { |
42 | 46 | let config = common::random_config(true); |
43 | 47 | let mut builder = Builder::from_config(config.node_config); |
44 | | - builder.set_chain_source_esplora("http://127.0.0.1:3002".to_string(), None); |
45 | | - |
| 48 | + builder.set_chain_source_electrum("tcp://127.0.0.1:50001".to_string(), None); |
46 | 49 | let node = builder.build(config.node_entropy).unwrap(); |
47 | 50 | node.start().unwrap(); |
| 51 | + node |
| 52 | +} |
| 53 | + |
| 54 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 55 | +async fn test_cln_basic_channel_cycle() { |
| 56 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 57 | + let node = setup_ldk_node(); |
| 58 | + setup_interop_test(&node, &cln, &bitcoind, &electrs).await; |
| 59 | + |
| 60 | + let (user_channel_id, _ext_channel_id) = |
| 61 | + open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000)) |
| 62 | + .await; |
| 63 | + |
| 64 | + // LDK -> CLN payment |
| 65 | + let invoice = cln.create_invoice(10_000_000, "cln-test-send").await.unwrap(); |
| 66 | + let parsed = lightning_invoice::Bolt11Invoice::from_str(&invoice).unwrap(); |
| 67 | + node.bolt11_payment().send(&parsed, None).unwrap(); |
| 68 | + common::expect_event!(node, PaymentSuccessful); |
| 69 | + |
| 70 | + // CLN -> LDK payment |
| 71 | + test_receive_bolt11_payment(&node, &cln, 10_000_000).await; |
| 72 | + |
| 73 | + test_cooperative_close_by_ldk(&node, &cln, &bitcoind, &electrs, &user_channel_id).await; |
| 74 | + node.stop().unwrap(); |
| 75 | +} |
| 76 | + |
| 77 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 78 | +async fn test_cln_disconnect_reconnect() { |
| 79 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 80 | + let node = setup_ldk_node(); |
| 81 | + setup_interop_test(&node, &cln, &bitcoind, &electrs).await; |
| 82 | + let (_user_ch, _ext_ch) = |
| 83 | + open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000)) |
| 84 | + .await; |
| 85 | + |
| 86 | + test_disconnect_reconnect_idle(&node, &cln, &bitcoind, &electrs, &Side::Ldk).await; |
| 87 | + test_disconnect_reconnect_idle(&node, &cln, &bitcoind, &electrs, &Side::External).await; |
| 88 | + |
| 89 | + node.stop().unwrap(); |
| 90 | +} |
| 91 | + |
| 92 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 93 | +async fn test_cln_force_close_by_ldk() { |
| 94 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 95 | + let node = setup_ldk_node(); |
| 96 | + setup_interop_test(&node, &cln, &bitcoind, &electrs).await; |
| 97 | + let (user_ch, _ext_ch) = |
| 98 | + open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000)) |
| 99 | + .await; |
| 100 | + |
| 101 | + test_force_close_by_ldk(&node, &cln, &bitcoind, &electrs, &user_ch).await; |
| 102 | + node.stop().unwrap(); |
| 103 | +} |
| 104 | + |
| 105 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 106 | +async fn test_cln_force_close_by_external() { |
| 107 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 108 | + let node = setup_ldk_node(); |
| 109 | + setup_interop_test(&node, &cln, &bitcoind, &electrs).await; |
| 110 | + let (_user_ch, ext_ch) = |
| 111 | + open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000)) |
| 112 | + .await; |
| 113 | + |
| 114 | + test_force_close_by_external(&node, &cln, &bitcoind, &electrs, &ext_ch).await; |
| 115 | + node.stop().unwrap(); |
| 116 | +} |
| 117 | + |
| 118 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 119 | +async fn test_cln_splice() { |
| 120 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 121 | + let node = setup_ldk_node(); |
| 122 | + setup_interop_test(&node, &cln, &bitcoind, &electrs).await; |
| 123 | + let (_user_ch, ext_ch) = |
| 124 | + open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000)) |
| 125 | + .await; |
| 126 | + |
| 127 | + test_splice_from_external(&node, &cln, &bitcoind, &electrs, &ext_ch).await; |
| 128 | + |
| 129 | + node.stop().unwrap(); |
| 130 | +} |
| 131 | + |
| 132 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 133 | +async fn test_cln_splice_then_payment() { |
| 134 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 135 | + let node = setup_ldk_node(); |
| 136 | + setup_interop_test(&node, &cln, &bitcoind, &electrs).await; |
| 137 | + let (_user_ch, ext_ch) = |
| 138 | + open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000)) |
| 139 | + .await; |
| 140 | + |
| 141 | + test_splice_then_payment(&node, &cln, &bitcoind, &electrs, &ext_ch).await; |
| 142 | + |
| 143 | + node.stop().unwrap(); |
| 144 | +} |
48 | 145 |
|
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, |
| 146 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 147 | +async fn test_cln_inbound_channel() { |
| 148 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 149 | + let node = setup_ldk_node(); |
| 150 | + run_inbound_channel_test( |
| 151 | + &node, |
| 152 | + &cln, |
| 153 | + &bitcoind, |
| 154 | + &electrs, |
| 155 | + CloseType::Cooperative, |
| 156 | + Side::External, |
57 | 157 | ) |
58 | 158 | .await; |
| 159 | + node.stop().unwrap(); |
| 160 | +} |
| 161 | + |
| 162 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 163 | +async fn test_cln_receive_payments() { |
| 164 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 165 | + let node = setup_ldk_node(); |
| 166 | + setup_interop_test(&node, &cln, &bitcoind, &electrs).await; |
| 167 | + let (_user_ch, _ext_ch) = |
| 168 | + open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000)) |
| 169 | + .await; |
| 170 | + |
| 171 | + test_receive_bolt11_payment(&node, &cln, 5_000_000).await; |
| 172 | + // TODO: CLN v24.08+ includes a `payment_secret` in outbound keysend payments. |
| 173 | + // LDK treats any inbound HTLC that carries a `payment_secret` as a BOLT 11 payment and |
| 174 | + // attempts to verify it against a stored invoice; since no invoice exists for a spontaneous |
| 175 | + // payment, it fails with WIRE_INCORRECT_OR_UNKNOWN_PAYMENT_DETAILS. |
| 176 | + // This is an LDK-side issue: when a valid `keysend_preimage` TLV is present, |
| 177 | + // `payment_secret` verification should be skipped. |
| 178 | + // Tracked upstream: CLN keysend interop issue (CLN includes payment_secret in keysend HTLCs) |
| 179 | + // test_receive_keysend_payment(&node, &cln, 5_000_000).await; |
| 180 | + |
| 181 | + node.stop().unwrap(); |
| 182 | +} |
| 183 | + |
| 184 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 185 | +async fn test_cln_bidirectional_payments() { |
| 186 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 187 | + let node = setup_ldk_node(); |
| 188 | + setup_interop_test(&node, &cln, &bitcoind, &electrs).await; |
| 189 | + let (_user_ch, ext_ch) = |
| 190 | + open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000)) |
| 191 | + .await; |
| 192 | + |
| 193 | + test_bidirectional_payments(&node, &cln, &ext_ch, 5_000_000).await; |
59 | 194 |
|
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); |
126 | 195 | node.stop().unwrap(); |
127 | 196 | } |
| 197 | + |
| 198 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 199 | +async fn test_cln_pay_expired_invoice() { |
| 200 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 201 | + let node = setup_ldk_node(); |
| 202 | + setup_interop_test(&node, &cln, &bitcoind, &electrs).await; |
| 203 | + let (_user_ch, _ext_ch) = |
| 204 | + open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000)) |
| 205 | + .await; |
| 206 | + |
| 207 | + test_pay_expired_invoice(&node, &cln).await; |
| 208 | + |
| 209 | + node.stop().unwrap(); |
| 210 | +} |
| 211 | + |
| 212 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 213 | +async fn test_cln_concurrent_payments() { |
| 214 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 215 | + let node = setup_ldk_node(); |
| 216 | + setup_interop_test(&node, &cln, &bitcoind, &electrs).await; |
| 217 | + let (_user_ch, _ext_ch) = |
| 218 | + open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000)) |
| 219 | + .await; |
| 220 | + |
| 221 | + test_concurrent_payments(&node, &cln, 5, 1_000_000).await; |
| 222 | + |
| 223 | + node.stop().unwrap(); |
| 224 | +} |
| 225 | + |
| 226 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 227 | +async fn test_cln_cooperative_close_after_fee_change() { |
| 228 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 229 | + let node = setup_ldk_node(); |
| 230 | + test_cooperative_close_after_fee_change(&node, &cln, &bitcoind, &electrs).await; |
| 231 | + node.stop().unwrap(); |
| 232 | +} |
| 233 | + |
| 234 | +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] |
| 235 | +async fn test_cln_force_close_after_fee_change() { |
| 236 | + let (bitcoind, electrs, cln) = setup_clients().await; |
| 237 | + let node = setup_ldk_node(); |
| 238 | + test_force_close_after_fee_change(&node, &cln, &bitcoind, &electrs).await; |
| 239 | + node.stop().unwrap(); |
| 240 | +} |
| 241 | + |
| 242 | +interop_combo_tests!(test_cln, setup_clients, setup_ldk_node); |
0 commit comments