Skip to content

Commit 681b659

Browse files
committed
refactor(test): DRY up interop tests and un-ignore CLN tests
- Move test_receive_keysend into interop_tests! macro, removing per-file duplicates across CLN, LND, and Eclair - Un-ignore test_cln_splice_in (will fail until rust-lightning bump past #4472, tracked in lightningdevkit#857) - Remove unused supports_splice() from ExternalNode trait
1 parent ed23e90 commit 681b659

8 files changed

Lines changed: 42 additions & 129 deletions

File tree

tests/common/cln.rs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -270,16 +270,6 @@ impl ExternalNode for TestClnNode {
270270
Ok(channels)
271271
}
272272

273-
// CLN v25 with --experimental-splicing advertises BOLT-spec bit 62
274-
// (OPT_SPLICE), so feature negotiation with LDK succeeds. However,
275-
// rust-lightning panics during tx_signatures exchange due to a
276-
// debug_assert (fixed in rust-lightning#4472, not yet in pinned rev).
277-
// Flip to true after ldk-node bumps rust-lightning past that fix.
278-
// Tracking: ldk-node#857
279-
fn supports_splice(&self) -> bool {
280-
false
281-
}
282-
283273
async fn splice_in(&self, channel_id: &str, amount_sat: u64) -> Result<(), TestFailure> {
284274
// Step 1: splice_init with positive relative_amount
285275
let ch_id = channel_id.to_string();

tests/common/eclair.rs

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -280,14 +280,6 @@ impl ExternalNode for TestEclairNode {
280280
Ok(channels)
281281
}
282282

283-
// Eclair uses custom prototype feature bit 154 for splice, not the
284-
// BOLT-specified bit 62/63 that LDK uses. Splice interop is not possible
285-
// until Eclair migrates to the standard feature bits.
286-
// Ref: https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala
287-
fn supports_splice(&self) -> bool {
288-
false
289-
}
290-
291283
async fn splice_in(&self, channel_id: &str, amount_sat: u64) -> Result<(), TestFailure> {
292284
let amount_str = amount_sat.to_string();
293285
self.post("/splicein", &[("channelId", channel_id), ("amountIn", &amount_str)]).await?;

tests/common/external_node.rs

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -145,18 +145,6 @@ pub(crate) trait ExternalNode: Send + Sync {
145145
Err(self.make_error(format!("did not reach height {} after 60s", min_height)))
146146
}
147147

148-
/// Whether this implementation supports channel splicing with LDK.
149-
///
150-
/// Feature bit status:
151-
/// - LDK uses BOLT-finalized bit 62/63 ([BOLT 9](https://github.com/lightning/bolts/blob/master/09-features.md))
152-
/// - CLN v25 `--experimental-splicing` advertises both standard bit 62 and
153-
/// experimental bit 162 ([features.h](https://github.com/ElementsProject/lightning/blob/v25.12/common/features.h)) -- interop works
154-
/// - Eclair v0.14 uses custom prototype bit 154 ([Features.scala](https://github.com/ACINQ/eclair/blob/master/eclair-core/src/main/scala/fr/acinq/eclair/Features.scala)) -- not compatible
155-
/// - LND does not implement splice
156-
fn supports_splice(&self) -> bool {
157-
false
158-
}
159-
160148
/// Splice additional funds into an existing channel.
161149
///
162150
/// Not all implementations support splicing. The default returns `NotSupported`.

tests/common/scenarios/mod.rs

Lines changed: 2 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ pub(crate) enum CloseType {
4747
#[derive(Debug, Clone, Copy)]
4848
pub(crate) enum PayType {
4949
Bolt11,
50+
Keysend,
5051
}
5152

5253
/// Find a specific channel on the external node by its channel ID.
@@ -126,7 +127,7 @@ where
126127
/// Generated tests:
127128
/// - `setup_ldk_node()` -- creates and starts an LDK node with electrum backend
128129
/// - `test_scenarios()` -- runs the full sequential scenario suite
129-
/// - `test_combos()` -- runs all 16 disconnect/close permutations
130+
/// - `test_combos()` -- runs all 32 disconnect/close/payment permutations
130131
macro_rules! interop_tests {
131132
($setup_clients:ident) => {
132133
fn setup_ldk_node() -> ldk_node::Node {
@@ -156,29 +157,6 @@ macro_rules! interop_tests {
156157
node.stop().unwrap();
157158
}
158159

159-
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
160-
async fn test_send_keysend() {
161-
let (bitcoind, electrs, ext) = $setup_clients().await;
162-
let node = setup_ldk_node();
163-
common::scenarios::setup_interop_test(&node, &ext, &bitcoind, &electrs).await;
164-
let ext_node_id = ext.get_node_id().await.unwrap();
165-
let (user_ch, _ext_ch) = common::scenarios::channel::open_channel_to_external(
166-
&node,
167-
&ext,
168-
&bitcoind,
169-
&electrs,
170-
1_000_000,
171-
Some(500_000_000),
172-
)
173-
.await;
174-
node.spontaneous_payment().send(5_000_000, ext_node_id, None).unwrap();
175-
common::expect_event!(node, PaymentSuccessful);
176-
common::scenarios::channel::cooperative_close_by_ldk(
177-
&node, &ext, &bitcoind, &electrs, &user_ch,
178-
)
179-
.await;
180-
node.stop().unwrap();
181-
}
182160
};
183161
}
184162

tests/common/scenarios/suite.rs

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,16 @@ use super::connectivity::{
2525
};
2626
use super::payment::{
2727
bidirectional_payments, concurrent_payments, pay_expired_invoice, receive_bolt11_payment,
28+
receive_keysend_payment,
2829
};
2930
use super::{CloseType, PayType, Phase, Side};
3031

3132
/// Run the standard interop test sequence that is identical across all implementations.
3233
///
34+
/// Covers: basic channel cycle (BOLT11 send/receive), disconnect/reconnect, force close
35+
/// (both sides), inbound channels, bidirectional payments, expired invoices, concurrent
36+
/// payments, keysend (send + receive), and fee-change close scenarios.
37+
///
3338
/// Caller must have called `setup_interop_test` before this function.
3439
/// Does NOT call `node.stop()` -- caller handles that.
3540
pub(crate) async fn run_common_tests<E: ElectrumApi>(
@@ -87,6 +92,15 @@ pub(crate) async fn run_common_tests<E: ElectrumApi>(
8792
concurrent_payments(node, peer, 5, 1_000_000).await;
8893
cooperative_close_by_ldk(node, peer, bitcoind, electrs, &user_ch).await;
8994

95+
// Keysend (send + receive in one channel)
96+
let (user_ch, _ext_ch) =
97+
open_channel_to_external(node, peer, bitcoind, electrs, 1_000_000, Some(500_000_000)).await;
98+
let ext_node_id = peer.get_node_id().await.unwrap();
99+
node.spontaneous_payment().send(5_000_000, ext_node_id, None).unwrap();
100+
expect_event!(node, PaymentSuccessful);
101+
receive_keysend_payment(node, peer, 5_000_000).await;
102+
cooperative_close_by_ldk(node, peer, bitcoind, electrs, &user_ch).await;
103+
90104
// Fee change scenarios
91105
cooperative_close_after_fee_change(node, peer, bitcoind, electrs).await;
92106

@@ -124,6 +138,10 @@ async fn run_combo<E: ElectrumApi>(
124138
node.bolt11_payment().send(&parsed, None).unwrap();
125139
expect_event!(node, PaymentSuccessful);
126140
},
141+
PayType::Keysend => {
142+
node.spontaneous_payment().send(payment_amount_msat, ext_node_id, None).unwrap();
143+
expect_event!(node, PaymentSuccessful);
144+
},
127145
}
128146

129147
close_channel(
@@ -139,7 +157,7 @@ async fn run_combo<E: ElectrumApi>(
139157
.await;
140158
}
141159

142-
/// Run all 16 combo permutations (phase × disconnect side × close type × close initiator).
160+
/// Run all 32 combo permutations (phase × disconnect side × close type × close initiator × pay type).
143161
///
144162
/// Caller must have called `setup_interop_test` before this function.
145163
/// Does NOT call `node.stop()` -- caller handles that.
@@ -164,28 +182,21 @@ pub(crate) async fn run_combos<E: ElectrumApi>(
164182
(Phase::Idle, Side::External, CloseType::Force, Side::Ldk),
165183
(Phase::Idle, Side::External, CloseType::Force, Side::External),
166184
];
167-
168-
for (i, (phase, disc, close, initiator)) in combos.iter().enumerate() {
169-
println!(
170-
"=== combo {}/{}: {:?} {:?} {:?} {:?} ===",
171-
i + 1,
172-
combos.len(),
173-
phase,
174-
disc,
175-
close,
176-
initiator
177-
);
178-
run_combo(
179-
node,
180-
peer,
181-
bitcoind,
182-
electrs,
183-
*phase,
184-
*disc,
185-
*close,
186-
*initiator,
187-
PayType::Bolt11,
188-
)
189-
.await;
185+
let pay_types = [PayType::Bolt11, PayType::Keysend];
186+
let total = combos.len() * pay_types.len();
187+
188+
let mut i = 0;
189+
for (phase, disc, close, initiator) in combos.iter() {
190+
for pay_type in pay_types.iter() {
191+
i += 1;
192+
println!(
193+
"=== combo {}/{}: {:?} {:?} {:?} {:?} {:?} ===",
194+
i, total, phase, disc, close, initiator, pay_type
195+
);
196+
run_combo(
197+
node, peer, bitcoind, electrs, *phase, *disc, *close, *initiator, *pay_type,
198+
)
199+
.await;
200+
}
190201
}
191202
}

tests/integration_tests_cln.rs

Lines changed: 5 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use common::cln::TestClnNode;
1515
use common::external_node::ExternalNode;
1616
use common::scenarios::channel::{cooperative_close_by_ldk, open_channel_to_external};
1717
use common::scenarios::interop_tests;
18-
use common::scenarios::payment::receive_keysend_payment;
1918
use common::scenarios::setup_interop_test;
2019
use electrsd::corepc_client::client_sync::Auth;
2120
use electrsd::corepc_node::Client as BitcoindClient;
@@ -37,8 +36,12 @@ interop_tests!(setup_clients);
3736

3837
/// Test splice-in: LDK adds funds to an existing LDK↔CLN channel.
3938
/// Requires CLN --experimental-splicing (advertises OPT_SPLICE bit 62).
39+
///
40+
/// Known issue: rust-lightning panics during tx_signatures exchange
41+
/// (channel.rs debug_assert). Fix merged in rust-lightning#4472 but not yet
42+
/// in the pinned rev. Will pass once ldk-node bumps rust-lightning.
43+
/// Tracking: ldk-node#857
4044
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
41-
#[ignore = "rust-lightning panics during tx_signatures exchange (channel.rs debug_assert), fix merged in rust-lightning#4472 but not yet in pinned rev, see ldk-node#857"]
4245
async fn test_cln_splice_in() {
4346
let (bitcoind, electrs, cln) = setup_clients().await;
4447
let node = setup_ldk_node();
@@ -66,20 +69,3 @@ async fn test_cln_splice_in() {
6669
cooperative_close_by_ldk(&node, &cln, &bitcoind, &electrs, &user_ch).await;
6770
node.stop().unwrap();
6871
}
69-
70-
/// CLN keysend plugin sets min_final_cltv_expiry=22, but LDK requires at least
71-
/// 42 (HTLC_FAIL_BACK_BUFFER(39) + 3). CLN's keysend RPC has no parameter to
72-
/// override this value. See: plugins/keysend.c in CLN source.
73-
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
74-
#[ignore = "CLN keysend final_cltv=22 < LDK minimum 42 -- needs CLN upstream fix"]
75-
async fn test_cln_receive_keysend() {
76-
let (bitcoind, electrs, cln) = setup_clients().await;
77-
let node = setup_ldk_node();
78-
setup_interop_test(&node, &cln, &bitcoind, &electrs).await;
79-
let (user_ch, _ext_ch) =
80-
open_channel_to_external(&node, &cln, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
81-
.await;
82-
receive_keysend_payment(&node, &cln, 5_000_000).await;
83-
cooperative_close_by_ldk(&node, &cln, &bitcoind, &electrs, &user_ch).await;
84-
node.stop().unwrap();
85-
}

tests/integration_tests_eclair.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,7 @@ mod common;
1111

1212
use base64::prelude::{Engine as _, BASE64_STANDARD};
1313
use common::eclair::TestEclairNode;
14-
use common::external_node::ExternalNode;
15-
use common::scenarios::channel::{cooperative_close_by_ldk, open_channel_to_external};
1614
use common::scenarios::interop_tests;
17-
use common::scenarios::payment::receive_keysend_payment;
1815
use common::scenarios::setup_interop_test;
1916
use electrsd::corepc_client::client_sync::Auth;
2017
use electrsd::corepc_node::Client as BitcoindClient;
@@ -50,16 +47,3 @@ async fn setup_clients() -> (BitcoindClient, ElectrumClient, TestEclairNode) {
5047
}
5148

5249
interop_tests!(setup_clients);
53-
54-
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
55-
async fn test_eclair_receive_keysend() {
56-
let (bitcoind, electrs, eclair) = setup_clients().await;
57-
let node = setup_ldk_node();
58-
setup_interop_test(&node, &eclair, &bitcoind, &electrs).await;
59-
let (user_ch, _ext_ch) =
60-
open_channel_to_external(&node, &eclair, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
61-
.await;
62-
receive_keysend_payment(&node, &eclair, 5_000_000).await;
63-
cooperative_close_by_ldk(&node, &eclair, &bitcoind, &electrs, &user_ch).await;
64-
node.stop().unwrap();
65-
}

tests/integration_tests_lnd.rs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,8 @@
99

1010
mod common;
1111

12-
use common::external_node::ExternalNode;
1312
use common::lnd::TestLndNode;
14-
use common::scenarios::channel::{cooperative_close_by_ldk, open_channel_to_external};
1513
use common::scenarios::interop_tests;
16-
use common::scenarios::payment::receive_keysend_payment;
1714
use common::scenarios::setup_interop_test;
1815
use electrsd::corepc_client::client_sync::Auth;
1916
use electrsd::corepc_node::Client as BitcoindClient;
@@ -32,16 +29,3 @@ async fn setup_clients() -> (BitcoindClient, ElectrumClient, TestLndNode) {
3229
}
3330

3431
interop_tests!(setup_clients);
35-
36-
#[tokio::test(flavor = "multi_thread", worker_threads = 1)]
37-
async fn test_lnd_receive_keysend() {
38-
let (bitcoind, electrs, lnd) = setup_clients().await;
39-
let node = setup_ldk_node();
40-
setup_interop_test(&node, &lnd, &bitcoind, &electrs).await;
41-
let (user_ch, _ext_ch) =
42-
open_channel_to_external(&node, &lnd, &bitcoind, &electrs, 1_000_000, Some(500_000_000))
43-
.await;
44-
receive_keysend_payment(&node, &lnd, 5_000_000).await;
45-
cooperative_close_by_ldk(&node, &lnd, &bitcoind, &electrs, &user_ch).await;
46-
node.stop().unwrap();
47-
}

0 commit comments

Comments
 (0)