@@ -21,6 +21,7 @@ use bitcoin::Amount;
2121use electrsd:: corepc_node:: Client as BitcoindClient ;
2222use electrum_client:: ElectrumApi ;
2323use ldk_node:: { Event , Node } ;
24+ use ldk_node:: bitcoin:: secp256k1:: PublicKey ;
2425
2526use super :: external_node:: ExternalNode ;
2627use super :: { generate_blocks_and_wait, premine_and_distribute_funds} ;
@@ -87,6 +88,33 @@ pub(crate) async fn wait_for_htlcs_settled(
8788 panic ! ( "HTLCs did not settle on {} channel {} within 15s" , peer. name( ) , ext_channel_id) ;
8889}
8990
91+ /// Blocks execution until the channel with the specified peer becomes active (`is_usable == true`).
92+ /// Maximum wait time is 15 seconds (30 attempts with a 500ms interval).
93+ pub ( crate ) async fn wait_for_channel_usable ( node : & Node , counterparty_node_id : PublicKey ) {
94+ let mut usable = false ;
95+
96+ for _ in 0 ..30 {
97+ for channel in node. list_channels ( ) {
98+ if channel. counterparty_node_id == counterparty_node_id && channel. is_usable {
99+ usable = true ;
100+ break ;
101+ }
102+ }
103+
104+ if usable {
105+ break ;
106+ }
107+
108+ tokio:: time:: sleep ( Duration :: from_millis ( 500 ) ) . await ;
109+ }
110+
111+ assert ! (
112+ usable,
113+ "Timeout waiting for channel with {} to become usable" ,
114+ counterparty_node_id
115+ ) ;
116+ }
117+
90118/// Build a fresh LDK node configured for interop tests. Uses electrum at the
91119/// docker-compose default port and bumps sync timeouts for combo stress.
92120pub ( crate ) fn setup_ldk_node ( ) -> Node {
@@ -150,9 +178,14 @@ pub(crate) async fn run_interop_scenario<N, E, F>(
150178 node. stop ( ) . unwrap ( ) ;
151179}
152180
153- /// Open a channel, send a BOLT11 payment in each direction, then cooperatively close.
154- pub ( crate ) async fn basic_channel_cycle_scenario < E : ElectrumApi > (
155- node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E ,
181+ enum PaymentProtocol {
182+ Bolt11 ,
183+ Bolt12 ,
184+ }
185+
186+ /// Open a channel, send a BOLT11/BOLT12 payment in each direction, then cooperatively close.
187+ async fn basic_channel_cycle_scenario < E : ElectrumApi > (
188+ node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E , protocol : PaymentProtocol ,
156189) {
157190 let ( user_ch, ext_ch) = channel:: open_channel_to_external (
158191 node,
@@ -164,12 +197,36 @@ pub(crate) async fn basic_channel_cycle_scenario<E: ElectrumApi>(
164197 )
165198 . await ;
166199
167- payment:: send_bolt11_to_peer ( node, peer, 10_000_000 , "basic-send" ) . await ;
168- payment:: receive_bolt11_payment ( node, peer, 10_000_000 ) . await ;
200+ match protocol {
201+ PaymentProtocol :: Bolt11 => {
202+ payment:: send_bolt11_to_peer ( node, peer, 10_000_000 , "basic-send-bolt11" ) . await ;
203+ payment:: receive_bolt11_payment ( node, peer, 10_000_000 ) . await ;
204+ }
205+ PaymentProtocol :: Bolt12 => {
206+ payment:: send_bolt12_to_peer ( node, peer, 10_000_000 , "basic-send-bolt12" ) . await ;
207+ payment:: receive_bolt12_payment ( node, peer, 10_000_000 ) . await ;
208+ }
209+ }
169210
170211 channel:: cooperative_close ( node, peer, bitcoind, electrs, & user_ch, & ext_ch, Side :: Ldk ) . await ;
171212}
172213
214+ /// Specialized version of `basic_channel_cycle_scenario` for BOLT11 payments.
215+ /// See [`basic_channel_cycle_scenario`] for details.
216+ pub ( crate ) async fn basic_channel_cycle_bolt11_scenario < E : ElectrumApi > (
217+ node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E ,
218+ ) {
219+ basic_channel_cycle_scenario ( node, peer, bitcoind, electrs, PaymentProtocol :: Bolt11 ) . await ;
220+ }
221+
222+ /// Specialized version of `basic_channel_cycle_scenario` for BOLT12 payments.
223+ /// See [`basic_channel_cycle_scenario`] for details.
224+ pub ( crate ) async fn basic_channel_cycle_bolt12_scenario < E : ElectrumApi > (
225+ node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E ,
226+ ) {
227+ basic_channel_cycle_scenario ( node, peer, bitcoind, electrs, PaymentProtocol :: Bolt12 ) . await ;
228+ }
229+
173230/// Open a channel, send keysend in both directions, then cooperatively close.
174231pub ( crate ) async fn keysend_scenario < E : ElectrumApi > (
175232 node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E ,
@@ -189,8 +246,8 @@ pub(crate) async fn keysend_scenario<E: ElectrumApi>(
189246}
190247
191248/// Open a channel, send a payment, then force-close from the LDK side.
192- pub ( crate ) async fn force_close_after_payment_scenario < E : ElectrumApi > (
193- node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E ,
249+ async fn force_close_after_payment_scenario < E : ElectrumApi > (
250+ node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E , protocol : PaymentProtocol ,
194251) {
195252 let ( user_ch, ext_ch) = channel:: open_channel_to_external (
196253 node,
@@ -201,11 +258,36 @@ pub(crate) async fn force_close_after_payment_scenario<E: ElectrumApi>(
201258 Some ( 500_000_000 ) ,
202259 )
203260 . await ;
204- payment:: send_bolt11_to_peer ( node, peer, 5_000_000 , "force-close" ) . await ;
261+
262+ match protocol {
263+ PaymentProtocol :: Bolt11 => {
264+ payment:: send_bolt11_to_peer ( node, peer, 5_000_000 , "force-close-bolt11" ) . await ;
265+ }
266+ PaymentProtocol :: Bolt12 => {
267+ payment:: send_bolt12_to_peer ( node, peer, 5_000_000 , "force-close-bolt12" ) . await ;
268+ }
269+ }
270+
205271 wait_for_htlcs_settled ( peer, & ext_ch) . await ;
206272 channel:: force_close ( node, peer, bitcoind, electrs, & user_ch, & ext_ch, Side :: Ldk ) . await ;
207273}
208274
275+ /// Specialized version of `force_close_after_payment_scenario` for BOLT11 payments.
276+ /// See [`force_close_after_payment_scenario`] for details.
277+ pub ( crate ) async fn force_close_after_payment_bolt11_scenario < E : ElectrumApi > (
278+ node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E ,
279+ ) {
280+ force_close_after_payment_scenario ( node, peer, bitcoind, electrs, PaymentProtocol :: Bolt11 ) . await ;
281+ }
282+
283+ /// Specialized version of `force_close_after_payment_scenario` for BOLT12 payments.
284+ /// See [`force_close_after_payment_scenario`] for details.
285+ pub ( crate ) async fn force_close_after_payment_bolt12_scenario < E : ElectrumApi > (
286+ node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E ,
287+ ) {
288+ force_close_after_payment_scenario ( node, peer, bitcoind, electrs, PaymentProtocol :: Bolt12 ) . await ;
289+ }
290+
209291/// Open a channel, dispatch a payment with a mid-flight disconnect+reconnect,
210292/// then cooperatively close.
211293pub ( crate ) async fn disconnect_during_payment_scenario < E : ElectrumApi > (
@@ -226,8 +308,8 @@ pub(crate) async fn disconnect_during_payment_scenario<E: ElectrumApi>(
226308}
227309
228310/// Open a channel, splice-in additional funds, send a post-splice payment, then close.
229- pub ( crate ) async fn splice_in_scenario < E : ElectrumApi > (
230- node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E ,
311+ async fn splice_in_scenario < E : ElectrumApi > (
312+ node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E , protocol : PaymentProtocol ,
231313) {
232314 let ( user_ch, ext_ch) = channel:: open_channel_to_external (
233315 node,
@@ -245,7 +327,33 @@ pub(crate) async fn splice_in_scenario<E: ElectrumApi>(
245327 sync_wallets_with_retry ( node) . await ;
246328 expect_channel_ready_event ! ( node, ext_node_id) ;
247329
248- payment:: send_bolt11_to_peer ( node, peer, 5_000_000 , "post-splice" ) . await ;
330+ match protocol {
331+ PaymentProtocol :: Bolt11 => {
332+ payment:: send_bolt11_to_peer ( node, peer, 5_000_000 , "post-splice-bolt11" ) . await ;
333+ }
334+ PaymentProtocol :: Bolt12 => {
335+ // Wait for Onion Message router updates the channel to usable state.
336+ // Without this, Bolt12 pathfinding will fail even though the channel technically fired `ChannelReady`.
337+ wait_for_channel_usable ( node, ext_node_id) . await ;
338+ payment:: send_bolt12_to_peer ( node, peer, 5_000_000 , "post-splice-bolt12" ) . await ;
339+ }
340+ }
249341
250342 channel:: cooperative_close ( node, peer, bitcoind, electrs, & user_ch, & ext_ch, Side :: Ldk ) . await ;
251343}
344+
345+ /// Specialized version of `splice_in_scenario` for BOLT11 payments.
346+ /// See [`splice_in_scenario`] for details.
347+ pub ( crate ) async fn splice_in_bolt11_scenario < E : ElectrumApi > (
348+ node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E ,
349+ ) {
350+ splice_in_scenario ( node, peer, bitcoind, electrs, PaymentProtocol :: Bolt11 ) . await ;
351+ }
352+
353+ /// Specialized version of `splice_in_scenario` for BOLT12 payments.
354+ /// See [`splice_in_scenario`] for details.
355+ pub ( crate ) async fn splice_in_bolt12_scenario < E : ElectrumApi > (
356+ node : & Node , peer : & ( impl ExternalNode + ?Sized ) , bitcoind : & BitcoindClient , electrs : & E ,
357+ ) {
358+ splice_in_scenario ( node, peer, bitcoind, electrs, PaymentProtocol :: Bolt12 ) . await ;
359+ }
0 commit comments