@@ -8,11 +8,27 @@ use proptest::prelude::prop;
88use proptest:: proptest;
99
1010use crate :: common:: {
11- expect_event, generate_blocks_and_wait , invalidate_blocks , open_channel ,
12- premine_and_distribute_funds, random_chain_source, random_config, setup_bitcoind_and_electrsd ,
13- setup_node, wait_for_outpoint_spend,
11+ expect_event, exponential_backoff_poll , generate_blocks_and_wait , invalidate_blocks ,
12+ open_channel , premine_and_distribute_funds, random_chain_source, random_config,
13+ setup_bitcoind_and_electrsd , setup_node, wait_for_outpoint_spend, wait_for_tx ,
1414} ;
1515
16+ async fn wait_for_pending_sweep_balance < F > (
17+ node : & ldk_node:: Node , mut matches_balance : F ,
18+ ) -> PendingSweepBalance
19+ where
20+ F : FnMut ( & PendingSweepBalance ) -> bool ,
21+ {
22+ exponential_backoff_poll ( || {
23+ node. sync_wallets ( ) . unwrap ( ) ;
24+ node. list_balances ( )
25+ . pending_balances_from_channel_closures
26+ . into_iter ( )
27+ . find ( |balance| matches_balance ( balance) )
28+ } )
29+ . await
30+ }
31+
1632proptest ! {
1733 #![ proptest_config( proptest:: test_runner:: Config :: with_cases( 5 ) ) ]
1834 #[ test]
@@ -76,7 +92,9 @@ proptest! {
7692 nodes_funding_tx. insert( node. node_id( ) , funding_txo) ;
7793 }
7894
79- generate_blocks_and_wait( bitcoind, electrs, 6 ) . await ;
95+ // Keep funding confirmed across the deepest reorg. rust-lightning PR #4231 exempts
96+ // only trusted zero-conf channels; regular channels still force-close at zero confirmations.
97+ generate_blocks_and_wait( bitcoind, electrs, 7 ) . await ;
8098 sync_wallets!( ) ;
8199
82100 reorg!( reorg_depth) ;
@@ -144,40 +162,60 @@ proptest! {
144162 sync_wallets!( ) ;
145163
146164 if force_close {
147- for node in & nodes {
148- node. sync_wallets( ) . unwrap( ) ;
149- // If there is no more balance, there is nothing to process here.
150- if node. list_balances( ) . lightning_balances. len( ) < 1 {
151- return ;
152- }
153- match node. list_balances( ) . lightning_balances[ 0 ] {
154- LightningBalance :: ClaimableAwaitingConfirmations {
155- confirmation_height,
156- ..
157- } => {
158- let cur_height = node. status( ) . current_best_block. height;
159- let blocks_to_go = confirmation_height - cur_height;
160- generate_blocks_and_wait( bitcoind, electrs, blocks_to_go as usize ) . await ;
161- node. sync_wallets( ) . unwrap( ) ;
162- } ,
163- _ => panic!( "Unexpected balance state for node_hub!" ) ,
164- }
165+ let claimable_nodes = nodes
166+ . iter( )
167+ . filter_map( |node| {
168+ node. list_balances( ) . lightning_balances. iter( ) . find_map( |balance| {
169+ match balance {
170+ LightningBalance :: ClaimableAwaitingConfirmations {
171+ confirmation_height,
172+ ..
173+ } => Some ( ( node, * confirmation_height) ) ,
174+ _ => None ,
175+ }
176+ } )
177+ } )
178+ . collect:: <Vec <_>>( ) ;
179+ let confirmation_height = claimable_nodes
180+ . iter( )
181+ . map( |( _, confirmation_height) | * confirmation_height)
182+ . max( )
183+ . expect( "Missing claimable force-close balance" ) ;
184+ let cur_height = nodes[ 0 ] . status( ) . current_best_block. height;
185+ let blocks_to_go = confirmation_height. saturating_sub( cur_height) ;
186+ if blocks_to_go > 0 {
187+ generate_blocks_and_wait( bitcoind, electrs, blocks_to_go as usize ) . await ;
188+ sync_wallets!( ) ;
189+ }
165190
166- assert!( node. list_balances( ) . lightning_balances. len( ) < 2 ) ;
167- assert!( node. list_balances( ) . pending_balances_from_channel_closures. len( ) > 0 ) ;
168- match node. list_balances( ) . pending_balances_from_channel_closures[ 0 ] {
169- PendingSweepBalance :: BroadcastAwaitingConfirmation { .. } => { } ,
170- _ => panic!( "Unexpected balance state!" ) ,
191+ // Mining for one node advances the shared chain for every node. Mature all
192+ // claimable outputs together, wait for every sweep to reach the mempool, then
193+ // confirm them and wait for `AwaitingThresholdConfirmations`.
194+ for ( node, _) in & claimable_nodes {
195+ let pending_balance = wait_for_pending_sweep_balance( node, |balance| {
196+ matches!(
197+ balance,
198+ PendingSweepBalance :: BroadcastAwaitingConfirmation { .. }
199+ | PendingSweepBalance :: AwaitingThresholdConfirmations { .. }
200+ )
201+ } )
202+ . await ;
203+ if let PendingSweepBalance :: BroadcastAwaitingConfirmation {
204+ latest_spending_txid,
205+ ..
206+ } = pending_balance
207+ {
208+ wait_for_tx( electrs, latest_spending_txid) . await ;
171209 }
210+ }
172211
173- generate_blocks_and_wait( & bitcoind, electrs, 1 ) . await ;
174- node. sync_wallets( ) . unwrap( ) ;
175- assert!( node. list_balances( ) . lightning_balances. len( ) < 2 ) ;
176- assert!( node. list_balances( ) . pending_balances_from_channel_closures. len( ) > 0 ) ;
177- match node. list_balances( ) . pending_balances_from_channel_closures[ 0 ] {
178- PendingSweepBalance :: AwaitingThresholdConfirmations { .. } => { } ,
179- _ => panic!( "Unexpected balance state!" ) ,
180- }
212+ generate_blocks_and_wait( bitcoind, electrs, 1 ) . await ;
213+ sync_wallets!( ) ;
214+ for ( node, _) in & claimable_nodes {
215+ wait_for_pending_sweep_balance( node, |balance| {
216+ matches!( balance, PendingSweepBalance :: AwaitingThresholdConfirmations { .. } )
217+ } )
218+ . await ;
181219 }
182220 }
183221
0 commit comments