55// http://opensource.org/licenses/MIT>, at your option. You may not use this file except in
66// accordance with one or both of these licenses.
77
8- #![ cfg( any( test, cln_test, lnd_test, vss_test) ) ]
8+ #![ cfg( any( test, cln_test, lnd_test, eclair_test , vss_test) ) ]
99#![ allow( dead_code) ]
1010
1111pub ( crate ) mod external_node;
@@ -55,9 +55,24 @@ use rand::distr::Alphanumeric;
5555use rand:: { rng, Rng } ;
5656use serde_json:: { json, Value } ;
5757
58+ /// Shared timeout (in seconds) for waiting on LDK events and external node operations.
59+ pub ( crate ) const INTEROP_TIMEOUT_SECS : u64 = 60 ;
60+
5861macro_rules! expect_event {
5962 ( $node: expr, $event_type: ident) => { {
60- match $node. next_event_async( ) . await {
63+ let event = tokio:: time:: timeout(
64+ std:: time:: Duration :: from_secs( crate :: common:: INTEROP_TIMEOUT_SECS ) ,
65+ $node. next_event_async( ) ,
66+ )
67+ . await
68+ . unwrap_or_else( |_| {
69+ panic!(
70+ "{} timed out waiting for {} event after 60s" ,
71+ $node. node_id( ) ,
72+ std:: stringify!( $event_type)
73+ )
74+ } ) ;
75+ match event {
6176 ref e @ Event :: $event_type { .. } => {
6277 println!( "{} got event {:?}" , $node. node_id( ) , e) ;
6378 $node. event_handled( ) . unwrap( ) ;
@@ -73,7 +88,15 @@ pub(crate) use expect_event;
7388
7489macro_rules! expect_channel_pending_event {
7590 ( $node: expr, $counterparty_node_id: expr) => { {
76- match $node. next_event_async( ) . await {
91+ let event = tokio:: time:: timeout(
92+ std:: time:: Duration :: from_secs( crate :: common:: INTEROP_TIMEOUT_SECS ) ,
93+ $node. next_event_async( ) ,
94+ )
95+ . await
96+ . unwrap_or_else( |_| {
97+ panic!( "{} timed out waiting for ChannelPending event after 60s" , $node. node_id( ) )
98+ } ) ;
99+ match event {
77100 ref e @ Event :: ChannelPending { funding_txo, counterparty_node_id, .. } => {
78101 println!( "{} got event {:?}" , $node. node_id( ) , e) ;
79102 assert_eq!( counterparty_node_id, $counterparty_node_id) ;
@@ -91,7 +114,15 @@ pub(crate) use expect_channel_pending_event;
91114
92115macro_rules! expect_channel_ready_event {
93116 ( $node: expr, $counterparty_node_id: expr) => { {
94- match $node. next_event_async( ) . await {
117+ let event = tokio:: time:: timeout(
118+ std:: time:: Duration :: from_secs( crate :: common:: INTEROP_TIMEOUT_SECS ) ,
119+ $node. next_event_async( ) ,
120+ )
121+ . await
122+ . unwrap_or_else( |_| {
123+ panic!( "{} timed out waiting for ChannelReady event after 60s" , $node. node_id( ) )
124+ } ) ;
125+ match event {
95126 ref e @ Event :: ChannelReady { user_channel_id, counterparty_node_id, .. } => {
96127 println!( "{} got event {:?}" , $node. node_id( ) , e) ;
97128 assert_eq!( counterparty_node_id, Some ( $counterparty_node_id) ) ;
@@ -111,7 +142,15 @@ macro_rules! expect_channel_ready_events {
111142 ( $node: expr, $counterparty_node_id_a: expr, $counterparty_node_id_b: expr) => { {
112143 let mut ids = Vec :: new( ) ;
113144 for _ in 0 ..2 {
114- match $node. next_event_async( ) . await {
145+ let event = tokio:: time:: timeout(
146+ std:: time:: Duration :: from_secs( crate :: common:: INTEROP_TIMEOUT_SECS ) ,
147+ $node. next_event_async( ) ,
148+ )
149+ . await
150+ . unwrap_or_else( |_| {
151+ panic!( "{} timed out waiting for ChannelReady event after 60s" , $node. node_id( ) )
152+ } ) ;
153+ match event {
115154 ref e @ Event :: ChannelReady { counterparty_node_id, .. } => {
116155 println!( "{} got event {:?}" , $node. node_id( ) , e) ;
117156 ids. push( counterparty_node_id) ;
@@ -137,7 +176,15 @@ pub(crate) use expect_channel_ready_events;
137176
138177macro_rules! expect_splice_pending_event {
139178 ( $node: expr, $counterparty_node_id: expr) => { {
140- match $node. next_event_async( ) . await {
179+ let event = tokio:: time:: timeout(
180+ std:: time:: Duration :: from_secs( crate :: common:: INTEROP_TIMEOUT_SECS ) ,
181+ $node. next_event_async( ) ,
182+ )
183+ . await
184+ . unwrap_or_else( |_| {
185+ panic!( "{} timed out waiting for SplicePending event after 60s" , $node. node_id( ) )
186+ } ) ;
187+ match event {
141188 ref e @ Event :: SplicePending { new_funding_txo, counterparty_node_id, .. } => {
142189 println!( "{} got event {:?}" , $node. node_id( ) , e) ;
143190 assert_eq!( counterparty_node_id, $counterparty_node_id) ;
@@ -155,19 +202,27 @@ pub(crate) use expect_splice_pending_event;
155202
156203macro_rules! expect_payment_received_event {
157204 ( $node: expr, $amount_msat: expr) => { {
158- match $node. next_event_async( ) . await {
205+ let event = tokio:: time:: timeout(
206+ std:: time:: Duration :: from_secs( crate :: common:: INTEROP_TIMEOUT_SECS ) ,
207+ $node. next_event_async( ) ,
208+ )
209+ . await
210+ . unwrap_or_else( |_| {
211+ panic!( "{} timed out waiting for PaymentReceived event after 60s" , $node. node_id( ) )
212+ } ) ;
213+ match event {
159214 ref e @ Event :: PaymentReceived { payment_id, amount_msat, .. } => {
160215 println!( "{} got event {:?}" , $node. node_id( ) , e) ;
161216 assert_eq!( amount_msat, $amount_msat) ;
162217 let payment = $node. payment( & payment_id. unwrap( ) ) . unwrap( ) ;
163- if !matches!( payment. kind, PaymentKind :: Onchain { .. } ) {
218+ if !matches!( payment. kind, ldk_node :: payment :: PaymentKind :: Onchain { .. } ) {
164219 assert_eq!( payment. fee_paid_msat, None ) ;
165220 }
166221 $node. event_handled( ) . unwrap( ) ;
167222 payment_id
168223 } ,
169224 ref e => {
170- panic!( "{} got unexpected event!: {:?}" , std:: stringify!( node_b ) , e) ;
225+ panic!( "{} got unexpected event!: {:?}" , std:: stringify!( $node ) , e) ;
171226 } ,
172227 }
173228 } } ;
@@ -177,7 +232,18 @@ pub(crate) use expect_payment_received_event;
177232
178233macro_rules! expect_payment_claimable_event {
179234 ( $node: expr, $payment_id: expr, $payment_hash: expr, $claimable_amount_msat: expr) => { {
180- match $node. next_event_async( ) . await {
235+ let event = tokio:: time:: timeout(
236+ std:: time:: Duration :: from_secs( crate :: common:: INTEROP_TIMEOUT_SECS ) ,
237+ $node. next_event_async( ) ,
238+ )
239+ . await
240+ . unwrap_or_else( |_| {
241+ panic!(
242+ "{} timed out waiting for PaymentClaimable event after 60s" ,
243+ std:: stringify!( $node)
244+ )
245+ } ) ;
246+ match event {
181247 ref e @ Event :: PaymentClaimable {
182248 payment_id,
183249 payment_hash,
@@ -202,7 +268,15 @@ pub(crate) use expect_payment_claimable_event;
202268
203269macro_rules! expect_payment_successful_event {
204270 ( $node: expr, $payment_id: expr, $fee_paid_msat: expr) => { {
205- match $node. next_event_async( ) . await {
271+ let event = tokio:: time:: timeout(
272+ std:: time:: Duration :: from_secs( crate :: common:: INTEROP_TIMEOUT_SECS ) ,
273+ $node. next_event_async( ) ,
274+ )
275+ . await
276+ . unwrap_or_else( |_| {
277+ panic!( "{} timed out waiting for PaymentSuccessful event after 60s" , $node. node_id( ) )
278+ } ) ;
279+ match event {
206280 ref e @ Event :: PaymentSuccessful { payment_id, fee_paid_msat, .. } => {
207281 println!( "{} got event {:?}" , $node. node_id( ) , e) ;
208282 if let Some ( fee_msat) = $fee_paid_msat {
@@ -390,6 +464,9 @@ macro_rules! setup_builder {
390464
391465pub ( crate ) use setup_builder;
392466
467+ #[ cfg( any( cln_test, lnd_test, eclair_test) ) ]
468+ pub ( crate ) mod scenarios;
469+
393470pub ( crate ) fn setup_two_nodes (
394471 chain_source : & TestChainSource , allow_0conf : bool , anchor_channels : bool ,
395472 anchors_trusted_no_reserve : bool ,
@@ -1699,3 +1776,72 @@ impl TestSyncStoreInner {
16991776 self . do_list ( primary_namespace, secondary_namespace)
17001777 }
17011778}
1779+
1780+ /// Generates 16 individual `#[tokio::test]` functions covering every combination
1781+ /// of (Phase, disconnect Side, CloseType, close Side):
1782+ /// 2 phases × 2 disconnect sides × 2 close types × 2 close initiators = 16.
1783+ ///
1784+ /// PayType is fixed to Bolt11 — keysend vs bolt11 doesn't affect channel close
1785+ /// behavior and is already covered by dedicated named tests (`test_*_receive_keysend`,
1786+ /// `test_*_receive_payments`). Do NOT add a Keysend axis here: CLN and Eclair
1787+ /// have known keysend interop issues (see `#[ignore]` tests in their entry points).
1788+ ///
1789+ /// Usage (inside each `integration_tests_*.rs`):
1790+ /// ```ignore
1791+ /// interop_combo_tests!(test_lnd, setup_clients, setup_ldk_node);
1792+ /// ```
1793+ #[ macro_export]
1794+ macro_rules! interop_combo_tests {
1795+ ( $prefix: ident, $setup_clients: ident, $setup_ldk_node: ident) => {
1796+ $crate:: interop_combo_tests!(
1797+ @phase $prefix, $setup_clients, $setup_ldk_node,
1798+ [ payment, Phase :: Payment ] , [ idle, Phase :: Idle ]
1799+ ) ;
1800+ } ;
1801+
1802+ ( @phase $prefix: ident, $sc: ident, $sn: ident, $( [ $pn: ident, $pv: expr] ) ,+) => {
1803+ $(
1804+ $crate:: interop_combo_tests!(
1805+ @disc $prefix, $sc, $sn, $pn, $pv,
1806+ [ ldk, Side :: Ldk ] , [ ext, Side :: External ]
1807+ ) ;
1808+ ) +
1809+ } ;
1810+
1811+ ( @disc $prefix: ident, $sc: ident, $sn: ident, $pn: ident, $pv: expr, $( [ $dn: ident, $dv: expr] ) ,+) => {
1812+ $(
1813+ $crate:: interop_combo_tests!(
1814+ @close $prefix, $sc, $sn, $pn, $pv, $dn, $dv,
1815+ [ coop, CloseType :: Cooperative ] , [ force, CloseType :: Force ]
1816+ ) ;
1817+ ) +
1818+ } ;
1819+
1820+ ( @close $prefix: ident, $sc: ident, $sn: ident, $pn: ident, $pv: expr, $dn: ident, $dv: expr,
1821+ $( [ $cn: ident, $cv: expr] ) ,+) => {
1822+ $(
1823+ $crate:: interop_combo_tests!(
1824+ @ci $prefix, $sc, $sn, $pn, $pv, $dn, $dv, $cn, $cv,
1825+ [ ldk, Side :: Ldk ] , [ ext, Side :: External ]
1826+ ) ;
1827+ ) +
1828+ } ;
1829+
1830+ ( @ci $prefix: ident, $sc: ident, $sn: ident, $pn: ident, $pv: expr, $dn: ident, $dv: expr,
1831+ $cn: ident, $cv: expr, $( [ $cin: ident, $civ: expr] ) ,+) => {
1832+ $(
1833+ paste:: paste! {
1834+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
1835+ async fn [ <$prefix _combo_ $pn _ $dn _ $cn _ $cin>] ( ) {
1836+ let ( bitcoind, electrs, peer) = $sc( ) . await ;
1837+ let node = $sn( ) ;
1838+ run_interop_combo_test(
1839+ & node, & peer, & bitcoind, & electrs,
1840+ $pv, $dv, $cv, $civ, PayType :: Bolt11 ,
1841+ ) . await ;
1842+ node. stop( ) . unwrap( ) ;
1843+ }
1844+ }
1845+ ) +
1846+ } ;
1847+ }
0 commit comments