Skip to content

Commit a4461ac

Browse files
committed
f Keep bitcoind background sync alive
Wait for an active manual sync and retry initial ownership so startup races do not permanently stop background polling. Co-Authored-By: HAL 9000
1 parent 0b7a380 commit a4461ac

1 file changed

Lines changed: 63 additions & 9 deletions

File tree

src/chain/bitcoind.rs

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,31 @@ use crate::{Error, PersistedNodeMetrics};
4949
const CHAIN_POLLING_INTERVAL_SECS: u64 = 2;
5050
const 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+
5277
pub(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)]
15231547
mod 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

Comments
 (0)