@@ -49,6 +49,31 @@ use crate::{Error, PersistedNodeMetrics};
4949const CHAIN_POLLING_INTERVAL_SECS : u64 = 2 ;
5050const CHAIN_POLLING_TIMEOUT_SECS : u64 = 10 ;
5151
52+ async fn acquire_initial_wallet_sync_guard < ' a > (
53+ wallet_polling_status : & ' a Mutex < WalletSyncStatus > ,
54+ stop_sync_receiver : & mut tokio:: sync:: watch:: Receiver < ( ) > ,
55+ ) -> Option < WalletSyncGuard < ' a > > {
56+ loop {
57+ let mut pending_sync = {
58+ let mut status_lock = wallet_polling_status. lock ( ) . expect ( "lock" ) ;
59+ match status_lock. register_or_subscribe_pending_sync ( ) {
60+ Some ( pending_sync) => pending_sync,
61+ None => {
62+ return Some ( WalletSyncGuard :: new (
63+ wallet_polling_status,
64+ Error :: WalletOperationFailed ,
65+ ) ) ;
66+ } ,
67+ }
68+ } ;
69+ tokio:: select! {
70+ biased;
71+ _ = stop_sync_receiver. changed( ) => return None ,
72+ _ = pending_sync. recv( ) => { } ,
73+ }
74+ }
75+ }
76+
5277pub ( super ) struct BitcoindChainSource {
5378 api_client : Arc < BitcoindClient > ,
5479 latest_chain_tip : RwLock < Option < ValidatedBlockHeader > > ,
@@ -152,13 +177,12 @@ impl BitcoindChainSource {
152177 ) {
153178 // First register for the wallet polling status to make sure `Node::sync_wallets` calls
154179 // wait on the result before proceeding.
155- let initial_sync_guard = {
156- let mut status_lock = self . wallet_polling_status . lock ( ) . expect ( "lock" ) ;
157- if status_lock. register_or_subscribe_pending_sync ( ) . is_some ( ) {
158- debug_assert ! ( false , "Sync already in progress. This should never happen." ) ;
159- return ;
160- }
161- WalletSyncGuard :: new ( & self . wallet_polling_status , Error :: WalletOperationFailed )
180+ let Some ( initial_sync_guard) =
181+ acquire_initial_wallet_sync_guard ( & self . wallet_polling_status , & mut stop_sync_receiver)
182+ . await
183+ else {
184+ log_trace ! ( self . logger, "Stopping initial chain sync." ) ;
185+ return ;
162186 } ;
163187
164188 log_info ! (
@@ -1521,6 +1545,9 @@ impl std::error::Error for BitcoindClientError {}
15211545
15221546#[ cfg( test) ]
15231547mod tests {
1548+ use std:: sync:: Mutex ;
1549+ use std:: time:: Duration ;
1550+
15241551 use bitcoin:: hashes:: Hash ;
15251552 use bitcoin:: { FeeRate , OutPoint , ScriptBuf , Transaction , TxIn , TxOut , Txid , Witness } ;
15261553 use lightning_block_sync:: http:: JsonResponse ;
@@ -1530,9 +1557,36 @@ mod tests {
15301557 use serde_json:: json;
15311558
15321559 use crate :: chain:: bitcoind:: {
1533- FeeResponse , GetMempoolEntryResponse , GetRawMempoolResponse , GetRawTransactionResponse ,
1534- MempoolMinFeeResponse ,
1560+ acquire_initial_wallet_sync_guard , FeeResponse , GetMempoolEntryResponse ,
1561+ GetRawMempoolResponse , GetRawTransactionResponse , MempoolMinFeeResponse ,
15351562 } ;
1563+ use crate :: chain:: { WalletSyncGuard , WalletSyncStatus } ;
1564+ use crate :: Error ;
1565+
1566+ #[ tokio:: test]
1567+ async fn initial_sync_waits_for_in_progress_sync ( ) {
1568+ let status = Mutex :: new ( WalletSyncStatus :: Completed ) ;
1569+ assert ! ( status. lock( ) . expect( "lock" ) . register_or_subscribe_pending_sync( ) . is_none( ) ) ;
1570+ let in_progress_guard = WalletSyncGuard :: new ( & status, Error :: WalletOperationFailed ) ;
1571+ let ( _stop_sender, mut stop_receiver) = tokio:: sync:: watch:: channel ( ( ) ) ;
1572+ let mut acquire_guard =
1573+ Box :: pin ( acquire_initial_wallet_sync_guard ( & status, & mut stop_receiver) ) ;
1574+
1575+ let early_result =
1576+ tokio:: time:: timeout ( Duration :: from_millis ( 10 ) , acquire_guard. as_mut ( ) ) . await ;
1577+ assert ! ( early_result. is_err( ) , "background sync should wait for the active sync" ) ;
1578+
1579+ in_progress_guard. complete ( Ok ( ( ) ) ) ;
1580+ let acquired_guard = tokio:: time:: timeout ( Duration :: from_secs ( 1 ) , acquire_guard)
1581+ . await
1582+ . expect ( "background sync should resume" )
1583+ . expect ( "background sync should acquire the sync guard" ) ;
1584+ assert ! (
1585+ matches!( * status. lock( ) . expect( "lock" ) , WalletSyncStatus :: InProgress { .. } ) ,
1586+ "background sync should own the next sync"
1587+ ) ;
1588+ acquired_guard. complete ( Ok ( ( ) ) ) ;
1589+ }
15361590
15371591 prop_compose ! {
15381592 fn arbitrary_witness( ) (
0 commit comments