@@ -52,6 +52,31 @@ const CHAIN_POLLING_TIMEOUT_SECS: u64 = 10;
5252type BitcoindSpvClient =
5353 SpvClient < ChainPoller < Arc < BitcoindClient > , BitcoindClient > , Arc < ChainListener > > ;
5454
55+ async fn acquire_initial_wallet_sync_guard < ' a > (
56+ wallet_polling_status : & ' a Mutex < WalletSyncStatus > ,
57+ stop_sync_receiver : & mut tokio:: sync:: watch:: Receiver < ( ) > ,
58+ ) -> Option < WalletSyncGuard < ' a > > {
59+ loop {
60+ let mut pending_sync = {
61+ let mut status_lock = wallet_polling_status. lock ( ) . expect ( "lock" ) ;
62+ match status_lock. register_or_subscribe_pending_sync ( ) {
63+ Some ( pending_sync) => pending_sync,
64+ None => {
65+ return Some ( WalletSyncGuard :: new (
66+ wallet_polling_status,
67+ Error :: WalletOperationFailed ,
68+ ) ) ;
69+ } ,
70+ }
71+ } ;
72+ tokio:: select! {
73+ biased;
74+ _ = stop_sync_receiver. changed( ) => return None ,
75+ _ = pending_sync. recv( ) => { } ,
76+ }
77+ }
78+ }
79+
5580pub ( super ) struct BitcoindChainSource {
5681 api_client : Arc < BitcoindClient > ,
5782 spv_client : tokio:: sync:: Mutex < Option < BitcoindSpvClient > > ,
@@ -160,13 +185,12 @@ impl BitcoindChainSource {
160185 ) {
161186 // First register for the wallet polling status to make sure `Node::sync_wallets` calls
162187 // wait on the result before proceeding.
163- let initial_sync_guard = {
164- let mut status_lock = self . wallet_polling_status . lock ( ) . expect ( "lock" ) ;
165- if status_lock. register_or_subscribe_pending_sync ( ) . is_some ( ) {
166- debug_assert ! ( false , "Sync already in progress. This should never happen." ) ;
167- return ;
168- }
169- WalletSyncGuard :: new ( & self . wallet_polling_status , Error :: WalletOperationFailed )
188+ let Some ( initial_sync_guard) =
189+ acquire_initial_wallet_sync_guard ( & self . wallet_polling_status , & mut stop_sync_receiver)
190+ . await
191+ else {
192+ log_trace ! ( self . logger, "Stopping initial chain sync." ) ;
193+ return ;
170194 } ;
171195
172196 log_info ! (
@@ -1592,6 +1616,9 @@ impl std::error::Error for BitcoindClientError {}
15921616
15931617#[ cfg( test) ]
15941618mod tests {
1619+ use std:: sync:: Mutex ;
1620+ use std:: time:: Duration ;
1621+
15951622 use bitcoin:: hashes:: Hash ;
15961623 use bitcoin:: { FeeRate , OutPoint , ScriptBuf , Transaction , TxIn , TxOut , Txid , Witness } ;
15971624 use lightning_block_sync:: http:: JsonResponse ;
@@ -1601,9 +1628,36 @@ mod tests {
16011628 use serde_json:: json;
16021629
16031630 use crate :: chain:: bitcoind:: {
1604- FeeResponse , GetMempoolEntryResponse , GetRawMempoolResponse , GetRawTransactionResponse ,
1605- MempoolMinFeeResponse ,
1631+ acquire_initial_wallet_sync_guard , FeeResponse , GetMempoolEntryResponse ,
1632+ GetRawMempoolResponse , GetRawTransactionResponse , MempoolMinFeeResponse ,
16061633 } ;
1634+ use crate :: chain:: { WalletSyncGuard , WalletSyncStatus } ;
1635+ use crate :: Error ;
1636+
1637+ #[ tokio:: test]
1638+ async fn initial_sync_waits_for_in_progress_sync ( ) {
1639+ let status = Mutex :: new ( WalletSyncStatus :: Completed ) ;
1640+ assert ! ( status. lock( ) . expect( "lock" ) . register_or_subscribe_pending_sync( ) . is_none( ) ) ;
1641+ let in_progress_guard = WalletSyncGuard :: new ( & status, Error :: WalletOperationFailed ) ;
1642+ let ( _stop_sender, mut stop_receiver) = tokio:: sync:: watch:: channel ( ( ) ) ;
1643+ let mut acquire_guard =
1644+ Box :: pin ( acquire_initial_wallet_sync_guard ( & status, & mut stop_receiver) ) ;
1645+
1646+ let early_result =
1647+ tokio:: time:: timeout ( Duration :: from_millis ( 10 ) , acquire_guard. as_mut ( ) ) . await ;
1648+ assert ! ( early_result. is_err( ) , "background sync should wait for the active sync" ) ;
1649+
1650+ in_progress_guard. complete ( Ok ( ( ) ) ) ;
1651+ let acquired_guard = tokio:: time:: timeout ( Duration :: from_secs ( 1 ) , acquire_guard)
1652+ . await
1653+ . expect ( "background sync should resume" )
1654+ . expect ( "background sync should acquire the sync guard" ) ;
1655+ assert ! (
1656+ matches!( * status. lock( ) . expect( "lock" ) , WalletSyncStatus :: InProgress { .. } ) ,
1657+ "background sync should own the next sync"
1658+ ) ;
1659+ acquired_guard. complete ( Ok ( ( ) ) ) ;
1660+ }
16071661
16081662 prop_compose ! {
16091663 fn arbitrary_witness( ) (
0 commit comments