From f0a49d64bf9356625ce9e3ae158d7ae688377c7e Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 19 Nov 2020 12:00:10 +1000 Subject: [PATCH] Split out a median_timespan function --- zebra-state/src/service/check/difficulty.rs | 49 +++++++++++++-------- 1 file changed, 30 insertions(+), 19 deletions(-) diff --git a/zebra-state/src/service/check/difficulty.rs b/zebra-state/src/service/check/difficulty.rs index 89f118f3..5bb622cc 100644 --- a/zebra-state/src/service/check/difficulty.rs +++ b/zebra-state/src/service/check/difficulty.rs @@ -201,9 +201,10 @@ impl AdjustedDifficulty { (total / divisor).into() } - /// Calculate the median timespan. The median timespan is the difference of - /// medians of the timespan times, which are the `time`s from the previous - /// `PoWAveragingWindow + PoWMedianBlockSpan` (28) blocks in the relevant chain. + /// Calculate the bounded median timespan. The median timespan is the + /// difference of medians of the timespan times, which are the `time`s from + /// the previous `PoWAveragingWindow + PoWMedianBlockSpan` (28) blocks in the + /// relevant chain. /// /// Uses the candidate block's `height' and `network` to calculate the /// `AveragingWindowTimespan` for that block. @@ -216,27 +217,13 @@ impl AdjustedDifficulty { /// Note: This calculation only uses `PoWMedianBlockSpan` (11) times at the /// start and end of the timespan times. timespan times `[11..=16]` are ignored. fn median_timespan_bounded(&self) -> Duration { - let newer_times: [DateTime; POW_MEDIAN_BLOCK_SPAN] = self.relevant_times - [0..POW_MEDIAN_BLOCK_SPAN] - .try_into() - .expect("relevant times is the correct length"); - let newer_median = AdjustedDifficulty::median_time(newer_times); - - let older_times: [DateTime; POW_MEDIAN_BLOCK_SPAN] = self.relevant_times - [POW_AVERAGING_WINDOW..] - .try_into() - .expect("relevant times is the correct length"); - let older_median = AdjustedDifficulty::median_time(older_times); - - // `ActualTimespan` in the Zcash specification - let median_timespan = newer_median - older_median; - let averaging_window_timespan = NetworkUpgrade::averaging_window_timespan_for_height( self.network, self.candidate_height, ); // This value is exact, but we need to truncate its nanoseconds component - let damped_variance = (median_timespan - averaging_window_timespan) / POW_DAMPING_FACTOR; + let damped_variance = + (self.median_timespan() - averaging_window_timespan) / POW_DAMPING_FACTOR; // num_seconds truncates negative values towards zero, matching the Zcash specification let damped_variance = Duration::seconds(damped_variance.num_seconds()); @@ -256,6 +243,30 @@ impl AdjustedDifficulty { ) } + /// Calculate the median timespan. The median timespan is the difference of + /// medians of the timespan times, which are the `time`s from the previous + /// `PoWAveragingWindow + PoWMedianBlockSpan` (28) blocks in the relevant chain. + /// + /// Implements `ActualTimespan` from the Zcash specification. + /// + /// See `median_timespan_bounded` for details. + fn median_timespan(&self) -> Duration { + let newer_times: [DateTime; POW_MEDIAN_BLOCK_SPAN] = self.relevant_times + [0..POW_MEDIAN_BLOCK_SPAN] + .try_into() + .expect("relevant times is the correct length"); + let newer_median = AdjustedDifficulty::median_time(newer_times); + + let older_times: [DateTime; POW_MEDIAN_BLOCK_SPAN] = self.relevant_times + [POW_AVERAGING_WINDOW..] + .try_into() + .expect("relevant times is the correct length"); + let older_median = AdjustedDifficulty::median_time(older_times); + + // `ActualTimespan` in the Zcash specification + newer_median - older_median + } + /// Calculate the median of the `median_block_span_times`: the `time`s from a /// slice of `PoWMedianBlockSpan` (11) blocks in the relevant chain. ///