@@ -546,9 +546,9 @@ fn has_onchain_tx_type<F: Fn(&TransactionType) -> bool>(node: &TestNode, predica
546546
547547fn assert_any_node_has_onchain_tx_type < F : Fn ( & TransactionType ) -> bool + Copy > (
548548 nodes : & [ ( & str , & TestNode ) ] , tx_type_name : & str , predicate : F ,
549- ) {
549+ ) -> Result < ( ) , String > {
550550 if nodes. iter ( ) . any ( |( _, node) | has_onchain_tx_type ( node, predicate) ) {
551- return ;
551+ return Ok ( ( ) ) ;
552552 }
553553
554554 let observed: Vec < String > = nodes
@@ -560,14 +560,14 @@ fn assert_any_node_has_onchain_tx_type<F: Fn(&TransactionType) -> bool + Copy>(
560560 } )
561561 } )
562562 . collect ( ) ;
563- panic ! ( "Expected on-chain payment with tx_type {}; observed {:?}" , tx_type_name, observed) ;
563+ Err ( format ! ( "Expected on-chain payment with tx_type {}; observed {:?}" , tx_type_name, observed) )
564564}
565565
566566fn assert_all_nodes_have_onchain_tx_type < F : Fn ( & TransactionType ) -> bool + Copy > (
567567 nodes : & [ ( & str , & TestNode ) ] , panic_msg : & str , tx_type_name : & str , predicate : F ,
568- ) {
568+ ) -> Result < ( ) , String > {
569569 if nodes. iter ( ) . all ( |( _, node) | has_onchain_tx_type ( node, predicate) ) {
570- return ;
570+ return Ok ( ( ) ) ;
571571 }
572572
573573 let observed: Vec < String > = nodes
@@ -579,10 +579,10 @@ fn assert_all_nodes_have_onchain_tx_type<F: Fn(&TransactionType) -> bool + Copy>
579579 } )
580580 } )
581581 . collect ( ) ;
582- panic ! (
582+ return Err ( format ! (
583583 "Expected {}nodes to have on-chain payment with tx_type {}; observed {:?}" ,
584584 panic_msg, tx_type_name, observed
585- ) ;
585+ ) ) ;
586586}
587587
588588async fn settle_force_close_balance < E : ElectrumApi > (
@@ -600,7 +600,12 @@ async fn settle_force_close_balance<E: ElectrumApi>(
600600 assert_eq ! ( actual_counterparty_node_id, counterparty_node_id) ;
601601 let cur_height = node. status ( ) . current_best_block . height ;
602602 let blocks_to_go = confirmation_height - cur_height;
603- generate_blocks_and_wait ( bitcoind, electrsd, blocks_to_go as usize ) . await ;
603+ let new_height =
604+ generate_blocks_and_wait ( bitcoind, electrsd, blocks_to_go as usize ) . await ;
605+ wait_for_node_tip ( node, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
606+ wait_for_node_tip ( peer_node, new_height)
607+ . await
608+ . expect ( "node hasn't synced to the tip" ) ;
604609 node. sync_wallets ( ) . unwrap ( ) ;
605610 peer_node. sync_wallets ( ) . unwrap ( ) ;
606611 } ,
@@ -615,7 +620,9 @@ async fn settle_force_close_balance<E: ElectrumApi>(
615620 if node. list_balances ( ) . lightning_balances . is_empty ( ) {
616621 break ;
617622 }
618- generate_blocks_and_wait ( bitcoind, electrsd, 1 ) . await ;
623+ let new_height = generate_blocks_and_wait ( bitcoind, electrsd, 1 ) . await ;
624+ wait_for_node_tip ( node, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
625+ wait_for_node_tip ( peer_node, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
619626 node. sync_wallets ( ) . unwrap ( ) ;
620627 peer_node. sync_wallets ( ) . unwrap ( ) ;
621628 }
@@ -624,8 +631,14 @@ async fn settle_force_close_balance<E: ElectrumApi>(
624631 assert ! ( balances. lightning_balances. is_empty( ) , "Unexpected balance state: {:?}" , balances) ;
625632 assert_eq ! ( balances. pending_balances_from_channel_closures. len( ) , 1 ) ;
626633 match balances. pending_balances_from_channel_closures [ 0 ] {
627- PendingSweepBalance :: BroadcastAwaitingConfirmation { .. } => {
628- generate_blocks_and_wait ( bitcoind, electrsd, 1 ) . await ;
634+ PendingSweepBalance :: BroadcastAwaitingConfirmation { latest_spending_txid, .. } => {
635+ // The balance flips as soon as the sweeper generates the transaction, before it has
636+ // been relayed to bitcoind. Make sure it is in the mempool so the next block
637+ // includes it.
638+ wait_for_tx ( electrsd, latest_spending_txid) . await ;
639+ let new_height = generate_blocks_and_wait ( bitcoind, electrsd, 1 ) . await ;
640+ wait_for_node_tip ( node, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
641+ wait_for_node_tip ( peer_node, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
629642 node. sync_wallets ( ) . unwrap ( ) ;
630643 peer_node. sync_wallets ( ) . unwrap ( ) ;
631644
@@ -640,7 +653,9 @@ async fn settle_force_close_balance<E: ElectrumApi>(
640653 _ => panic ! ( "Unexpected balance state!" ) ,
641654 }
642655
643- generate_blocks_and_wait ( bitcoind, electrsd, 5 ) . await ;
656+ let new_height = generate_blocks_and_wait ( bitcoind, electrsd, 5 ) . await ;
657+ wait_for_node_tip ( node, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
658+ wait_for_node_tip ( peer_node, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
644659 node. sync_wallets ( ) . unwrap ( ) ;
645660 peer_node. sync_wallets ( ) . unwrap ( ) ;
646661}
@@ -906,7 +921,7 @@ fn start_node(node: TestNode) -> TestNode {
906921
907922pub ( crate ) async fn generate_blocks_and_wait < E : ElectrumApi > (
908923 bitcoind : & BitcoindClient , electrs : & E , num : usize ,
909- ) {
924+ ) -> usize {
910925 let _ = bitcoind. create_wallet ( "ldk_node_test" ) ;
911926 let _ = bitcoind. load_wallet ( "ldk_node_test" ) ;
912927 print ! ( "Generating {} blocks..." , num) ;
@@ -915,9 +930,11 @@ pub(crate) async fn generate_blocks_and_wait<E: ElectrumApi>(
915930 let address = bitcoind. new_address ( ) . expect ( "failed to get new address" ) ;
916931 // TODO: expect this Result once the WouldBlock issue is resolved upstream.
917932 let _block_hashes_res = bitcoind. generate_to_address ( num, & address) ;
918- wait_for_block ( bitcoind, electrs, cur_height as usize + num) . await ;
933+ let new_height = cur_height as usize + num;
934+ wait_for_block ( bitcoind, electrs, new_height) . await ;
919935 print ! ( " Done!" ) ;
920936 println ! ( "\n " ) ;
937+ return new_height;
921938}
922939
923940pub ( crate ) fn invalidate_blocks ( bitcoind : & BitcoindClient , num_blocks : usize ) {
@@ -946,14 +963,16 @@ pub(crate) async fn wait_for_block<E: ElectrumApi>(
946963 }
947964 bitcoind. get_block_hash ( min_height as u64 ) . ok ( ) ?. block_hash ( ) . ok ( )
948965 } )
949- . await ;
966+ . await
967+ . expect ( "reached max tries" ) ;
950968 // A height-only wait can return the old header during a same-height reorg. Require the
951969 // replacement hash so callers cannot sync against the stale chain by mistake.
952970 exponential_backoff_poll ( || {
953971 let header = electrs. block_header ( min_height) . ok ( ) ?;
954972 ( header. block_hash ( ) == expected_block_hash) . then_some ( ( ) )
955973 } )
956- . await ;
974+ . await
975+ . expect ( "reached max tries" ) ;
957976}
958977
959978pub ( crate ) async fn wait_for_tx < E : ElectrumApi > ( electrs : & E , txid : Txid ) {
@@ -965,7 +984,8 @@ pub(crate) async fn wait_for_tx<E: ElectrumApi>(electrs: &E, txid: Txid) {
965984 electrs. ping ( ) . unwrap ( ) ;
966985 electrs. transaction_get ( & txid) . ok ( )
967986 } )
968- . await ;
987+ . await
988+ . expect ( "reached max tries" ) ;
969989}
970990
971991pub ( crate ) async fn wait_for_outpoint_spend < E : ElectrumApi > ( electrs : & E , outpoint : OutPoint ) {
@@ -982,7 +1002,8 @@ pub(crate) async fn wait_for_outpoint_spend<E: ElectrumApi>(electrs: &E, outpoin
9821002 } ) ;
9831003 is_spent. then_some ( ( ) )
9841004 } )
985- . await ;
1005+ . await
1006+ . expect ( "reached max tries" ) ;
9861007}
9871008
9881009/// Polls the channel from `source_node` to `counterparty_node` until it reports `is_usable`
@@ -1016,34 +1037,46 @@ pub(crate) async fn wait_for_channel_ready_to_send(
10161037 ) ;
10171038}
10181039
1019- pub ( crate ) async fn exponential_backoff_poll < T , F > ( mut poll : F ) -> T
1040+ pub ( crate ) async fn wait_for_node_tip ( node : & Node , height : usize ) -> Option < ( ) > {
1041+ // Pull-based chain sources (Esplora, Electrum) only advance the tip when a sync runs, so
1042+ // trigger one on every try instead of relying on the slow background interval.
1043+ exponential_backoff_poll ( || {
1044+ node. sync_wallets ( ) . unwrap ( ) ;
1045+ ( node. status ( ) . current_best_block . height as usize >= height) . then_some ( ( ) )
1046+ } )
1047+ . await
1048+ }
1049+
1050+ pub ( crate ) async fn exponential_backoff_poll < T , F > ( mut poll : F ) -> Option < T >
10201051where
10211052 F : FnMut ( ) -> Option < T > ,
10221053{
10231054 let mut delay = Duration :: from_millis ( 64 ) ;
10241055 let mut tries = 0 ;
10251056 loop {
10261057 match poll ( ) {
1027- Some ( data) => break data,
1058+ Some ( data) => return Some ( data) ,
10281059 None if delay. as_millis ( ) < 512 => {
10291060 delay = delay. mul_f32 ( 2.0 ) ;
10301061 } ,
10311062
10321063 None => { } ,
10331064 }
1034- assert ! ( tries < 20 , "Reached max tries." ) ;
1065+ if tries >= 20 {
1066+ return None ;
1067+ }
10351068 tries += 1 ;
10361069 tokio:: time:: sleep ( delay) . await ;
10371070 }
10381071}
10391072
10401073pub ( crate ) async fn premine_and_distribute_funds < E : ElectrumApi > (
10411074 bitcoind : & BitcoindClient , electrs : & E , addrs : Vec < Address > , amount : Amount ,
1042- ) {
1075+ ) -> usize {
10431076 premine_blocks ( bitcoind, electrs) . await ;
10441077
10451078 distribute_funds_unconfirmed ( bitcoind, electrs, addrs, amount) . await ;
1046- generate_blocks_and_wait ( bitcoind, electrs, 1 ) . await ;
1079+ generate_blocks_and_wait ( bitcoind, electrs, 1 ) . await
10471080}
10481081
10491082pub ( crate ) async fn premine_blocks < E : ElectrumApi > ( bitcoind : & BitcoindClient , electrs : & E ) {
@@ -1259,13 +1292,15 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
12591292
12601293 let premine_amount_sat = if expect_anchor_channel { 2_125_000 } else { 2_100_000 } ;
12611294
1262- premine_and_distribute_funds (
1295+ let new_height = premine_and_distribute_funds (
12631296 & bitcoind,
12641297 electrsd,
12651298 vec ! [ addr_a, addr_b] ,
12661299 Amount :: from_sat ( premine_amount_sat) ,
12671300 )
12681301 . await ;
1302+ wait_for_node_tip ( & node_a, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
1303+ wait_for_node_tip ( & node_b, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
12691304 node_a. sync_wallets ( ) . unwrap ( ) ;
12701305 node_b. sync_wallets ( ) . unwrap ( ) ;
12711306 assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
@@ -1341,7 +1376,9 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
13411376 wait_for_tx ( electrsd, funding_txo_a. txid ) . await ;
13421377
13431378 if !allow_0conf {
1344- generate_blocks_and_wait ( & bitcoind, electrsd, 6 ) . await ;
1379+ let new_height = generate_blocks_and_wait ( & bitcoind, electrsd, 6 ) . await ;
1380+ wait_for_node_tip ( & node_a, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
1381+ wait_for_node_tip ( & node_b, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
13451382 }
13461383
13471384 node_a. sync_wallets ( ) . unwrap ( ) ;
@@ -1709,7 +1746,9 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
17091746 ) ;
17101747
17111748 // Mine a block to give time for the HTLC to resolve
1712- generate_blocks_and_wait ( & bitcoind, electrsd, 1 ) . await ;
1749+ let new_height = generate_blocks_and_wait ( & bitcoind, electrsd, 1 ) . await ;
1750+ wait_for_node_tip ( & node_a, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
1751+ wait_for_node_tip ( & node_b, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
17131752
17141753 println ! ( "\n B splices out to pay A" ) ;
17151754 let addr_a = node_a. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
@@ -1721,7 +1760,9 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
17211760 let splice_out_txo = expect_splice_negotiated_event ! ( node_b, node_a. node_id( ) ) ;
17221761 wait_for_tx ( electrsd, splice_out_txo. txid ) . await ;
17231762
1724- generate_blocks_and_wait ( & bitcoind, electrsd, 6 ) . await ;
1763+ let new_height = generate_blocks_and_wait ( & bitcoind, electrsd, 6 ) . await ;
1764+ wait_for_node_tip ( & node_a, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
1765+ wait_for_node_tip ( & node_b, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
17251766 node_a. sync_wallets ( ) . unwrap ( ) ;
17261767 node_b. sync_wallets ( ) . unwrap ( ) ;
17271768
@@ -1743,7 +1784,9 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
17431784 let splice_in_txo = expect_splice_negotiated_event ! ( node_a, node_b. node_id( ) ) ;
17441785 wait_for_tx ( electrsd, splice_in_txo. txid ) . await ;
17451786
1746- generate_blocks_and_wait ( & bitcoind, electrsd, 6 ) . await ;
1787+ let new_height = generate_blocks_and_wait ( & bitcoind, electrsd, 6 ) . await ;
1788+ wait_for_node_tip ( & node_a, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
1789+ wait_for_node_tip ( & node_b, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
17471790 node_a. sync_wallets ( ) . unwrap ( ) ;
17481791 node_b. sync_wallets ( ) . unwrap ( ) ;
17491792
@@ -1819,7 +1862,9 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
18191862
18201863 wait_for_outpoint_spend ( electrsd, splice_in_txo) . await ;
18211864
1822- generate_blocks_and_wait ( & bitcoind, electrsd, 1 ) . await ;
1865+ let new_height = generate_blocks_and_wait ( & bitcoind, electrsd, 1 ) . await ;
1866+ wait_for_node_tip ( & node_a, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
1867+ wait_for_node_tip ( & node_b, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
18231868 node_a. sync_wallets ( ) . unwrap ( ) ;
18241869 node_b. sync_wallets ( ) . unwrap ( ) ;
18251870
@@ -1864,7 +1909,10 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
18641909
18651910 assert_eq ! ( node_a_blocks_to_go, node_b_blocks_to_go) ;
18661911
1867- generate_blocks_and_wait ( & bitcoind, electrsd, node_a_blocks_to_go as usize ) . await ;
1912+ let new_height =
1913+ generate_blocks_and_wait ( & bitcoind, electrsd, node_a_blocks_to_go as usize ) . await ;
1914+ wait_for_node_tip ( & node_a, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
1915+ wait_for_node_tip ( & node_b, new_height) . await . expect ( "node hasn't synced to the tip" ) ;
18681916 node_a. sync_wallets ( ) . unwrap ( ) ;
18691917 node_b. sync_wallets ( ) . unwrap ( ) ;
18701918
@@ -1886,19 +1934,22 @@ pub(crate) async fn do_channel_full_cycle<E: ElectrumApi>(
18861934 "no " ,
18871935 "UnilateralClose" ,
18881936 |tx_type| !matches ! ( tx_type, TransactionType :: UnilateralClose { .. } ) ,
1889- ) ;
1937+ )
1938+ . unwrap ( ) ;
18901939 assert_any_node_has_onchain_tx_type (
18911940 & [ ( "node_a" , & node_a) , ( "node_b" , & node_b) ] ,
18921941 "Sweep" ,
18931942 |tx_type| matches ! ( tx_type, TransactionType :: Sweep { .. } ) ,
1894- ) ;
1943+ )
1944+ . unwrap ( ) ;
18951945 } else {
18961946 assert_all_nodes_have_onchain_tx_type (
18971947 & [ ( "node_a" , & node_a) , ( "node_b" , & node_b) ] ,
18981948 "all " ,
18991949 "CooperativeClose" ,
19001950 |tx_type| matches ! ( tx_type, TransactionType :: CooperativeClose { .. } ) ,
1901- ) ;
1951+ )
1952+ . unwrap ( ) ;
19021953 // Peer removed after cooperative close — no further reason to reconnect.
19031954 assert ! (
19041955 !node_a. list_peers( ) . iter( ) . any( |p| p. node_id == node_b. node_id( ) && p. is_persisted) ,
0 commit comments