Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Decide if Zebra is at the chain tip #2722

Merged
merged 9 commits into from
Sep 6, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 26 additions & 3 deletions zebrad/src/components/sync/status.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,13 @@ pub struct SyncStatus {
}

impl SyncStatus {
/// The threshold that determines if the synchronization is at the chain
/// tip.
///
/// This is based on the fact that sync lengths are around 2-20 blocks long
/// once Zebra reaches the tip.
const MIN_DIST_FROM_TIP: usize = 20;

/// Create an instance of [`SyncStatus`].
///
/// The status is determined based on the latest counts of synchronized blocks, observed
Expand All @@ -41,9 +48,25 @@ impl SyncStatus {

/// Check if the synchronization is likely close to the chain tip.
pub fn is_close_to_tip(&self) -> bool {
let _sync_lengths = self.latest_sync_length.borrow();
let sync_lengths = self.latest_sync_length.borrow();

// Return early if sync_lengths is empty.
if sync_lengths.is_empty() {
return false;
}

// Compute the sum of the `sync_lengths`.
// The sum is computed by saturating addition in order to avoid overflowing.
let sum = sync_lengths
.iter()
.fold(0usize, |sum, rhs| sum.saturating_add(*rhs));

// Compute the average sync length.
// This value effectively represents a simple moving average.
let avg = sum / sync_lengths.len();

// TODO: Determine if the synchronization is actually close to the tip (#2592).
true
// The synchronization process is close to the chain tip once the
// average sync length falls below the threshold.
avg < Self::MIN_DIST_FROM_TIP
}
}
38 changes: 36 additions & 2 deletions zebrad/src/components/sync/status/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const DEFAULT_ASYNC_SYNCHRONIZED_TASKS_PROPTEST_CASES: u32 = 32;
/// The maximum time one test instance should run.
///
/// If the test exceeds this time it is considered to have failed.
const MAX_TEST_EXECUTION: Duration = Duration::from_secs(1);
const MAX_TEST_EXECUTION: Duration = Duration::from_secs(10);

/// The maximum time to wait for an event to be received.
///
Expand Down Expand Up @@ -120,7 +120,7 @@ proptest! {
/// looping repeatedly while [`SyncStatus`] reports that it is close to the chain tip.
/// 2. Waits until [`SyncStatus`] reports that it is close to the chain tip.
/// 3. Notifies the main task that it awoke, i.e., that the [`SyncStatus`] has finished
/// wating until it was close to the chain tip.
/// waiting until it was close to the chain tip.
async fn wait_task(
mut status: SyncStatus,
update_events: Arc<Semaphore>,
Expand All @@ -138,3 +138,37 @@ proptest! {
}
}
}

/// Test if totally empty sync lengths array is not near tip.
#[test]
fn empty_sync_lengths() {
let (status, _recent_sync_lengths) = SyncStatus::new();

assert!(!status.is_close_to_tip());
}

/// Test if sync lengths array with all zeroes is near tip.
#[test]
fn zero_sync_lengths() {
let (status, mut recent_sync_lengths) = SyncStatus::new();

for _ in 0..RecentSyncLengths::MAX_RECENT_LENGTHS {
recent_sync_lengths.push_extend_tips_length(0);
}

assert!(status.is_close_to_tip());
}

/// Test if sync lengths array with high values is not near tip.
#[test]
fn high_sync_lengths() {
let (status, mut recent_sync_lengths) = SyncStatus::new();

/// The value 500 is based on the fact that sync lengths are around 500
/// blocks long when Zebra is syncing.
oxarbitrage marked this conversation as resolved.
Show resolved Hide resolved
for _ in 0..RecentSyncLengths::MAX_RECENT_LENGTHS {
recent_sync_lengths.push_extend_tips_length(500);
}

assert!(!status.is_close_to_tip());
}