use tokio::sync::watch;
use zebra_chain::chain_sync_status::ChainSyncStatus;
use super::RecentSyncLengths;
#[cfg(any(test, feature = "proptest-impl"))]
pub mod mock;
#[cfg(test)]
mod tests;
#[derive(Clone, Debug)]
pub struct SyncStatus {
latest_sync_length: watch::Receiver<Vec<usize>>,
is_regtest: bool,
}
impl SyncStatus {
const MIN_DIST_FROM_TIP: usize = 20;
pub fn new_for_network(
network: &zebra_chain::parameters::Network,
) -> (Self, RecentSyncLengths) {
let (recent_sync_lengths, latest_sync_length) = RecentSyncLengths::new();
let status = SyncStatus {
latest_sync_length,
is_regtest: network.is_regtest(),
};
(status, recent_sync_lengths)
}
pub fn new() -> (Self, RecentSyncLengths) {
let (recent_sync_lengths, latest_sync_length) = RecentSyncLengths::new();
let status = SyncStatus {
latest_sync_length,
is_regtest: false,
};
(status, recent_sync_lengths)
}
pub async fn wait_until_close_to_tip(&mut self) -> Result<(), watch::error::RecvError> {
while !self.is_close_to_tip() {
self.latest_sync_length.changed().await?;
}
Ok(())
}
}
impl ChainSyncStatus for SyncStatus {
fn is_close_to_tip(&self) -> bool {
if self.is_regtest {
return true;
}
let sync_lengths = self.latest_sync_length.borrow();
if sync_lengths.is_empty() {
return false;
}
let sum = sync_lengths
.iter()
.fold(0usize, |sum, rhs| sum.saturating_add(*rhs));
let avg = sum / sync_lengths.len();
avg < Self::MIN_DIST_FROM_TIP
}
}