From 750f096a99c04d3bd66ab877c2e248e062d9bda5 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 19 Nov 2020 18:00:56 +1000 Subject: [PATCH] Implement testnet minimum difficulty --- zebra-chain/src/parameters/network_upgrade.rs | 33 ++++++++++++++++++- zebra-state/src/service/check/difficulty.rs | 18 ++++++++-- 2 files changed, 47 insertions(+), 4 deletions(-) diff --git a/zebra-chain/src/parameters/network_upgrade.rs b/zebra-chain/src/parameters/network_upgrade.rs index 0734bb1c6..dd7b7facb 100644 --- a/zebra-chain/src/parameters/network_upgrade.rs +++ b/zebra-chain/src/parameters/network_upgrade.rs @@ -8,7 +8,7 @@ use crate::parameters::{Network, Network::*}; use std::collections::{BTreeMap, HashMap}; use std::ops::Bound::*; -use chrono::Duration; +use chrono::{DateTime, Duration, Utc}; /// A Zcash network upgrade. /// @@ -229,6 +229,37 @@ impl NetworkUpgrade { } } + /// Returns true if the gap between `block_time` and `previous_block_time` is + /// greater than the Testnet minimum difficulty time gap. This time gap + /// depends on the `network` and `block_height`. + /// + /// Returns false on Mainnet, when `block_height` is less than the minimum + /// difficulty start height, and when the time gap is too small. + /// + /// `block_time` can be less than, equal to, or greater than + /// `previous_block_time`, because block times are provided by miners. + /// + /// Implements the Testnet minimum difficulty adjustment from ZIPs 205 and 208. + /// + /// Spec Note: Some parts of ZIPs 205 and 208 previously specified an incorrect + /// check for the time gap. This function implements the correct "greater than" + /// check. + pub fn is_testnet_min_difficulty_block( + network: Network, + block_height: block::Height, + block_time: DateTime, + previous_block_time: DateTime, + ) -> bool { + let block_time_gap = block_time - previous_block_time; + if let Some(min_difficulty_gap) = + NetworkUpgrade::minimum_difficulty_spacing_for_height(network, block_height) + { + block_time_gap > min_difficulty_gap + } else { + false + } + } + /// Returns the averaging window timespan for the network upgrade. /// /// `AveragingWindowTimespan` from the Zcash specification. diff --git a/zebra-state/src/service/check/difficulty.rs b/zebra-state/src/service/check/difficulty.rs index 1a5cd2a79..3013f49d3 100644 --- a/zebra-state/src/service/check/difficulty.rs +++ b/zebra-state/src/service/check/difficulty.rs @@ -32,7 +32,6 @@ pub const POW_MAX_ADJUST_UP_PERCENT: i32 = 16; pub const POW_MAX_ADJUST_DOWN_PERCENT: i32 = 32; /// Contains the context needed to calculate the adjusted difficulty for a block. -#[allow(dead_code)] pub(super) struct AdjustedDifficulty { /// The `header.time` field from the candidate block candidate_time: DateTime, @@ -149,8 +148,21 @@ impl AdjustedDifficulty { /// Implements `ThresholdBits` from the Zcash specification, and the Testnet /// minimum difficulty adjustment from ZIPs 205 and 208. pub fn expected_difficulty_threshold(&self) -> CompactDifficulty { - // TODO: Testnet minimum difficulty - self.threshold_bits() + if NetworkUpgrade::is_testnet_min_difficulty_block( + self.network, + self.candidate_height, + self.candidate_time, + self.relevant_times[0], + ) { + assert_eq!( + self.network, + Network::Testnet, + "invalid network: the minimum difficulty rule only applies on testnet" + ); + ExpandedDifficulty::target_difficulty_limit(self.network).to_compact() + } else { + self.threshold_bits() + } } /// Calculate the `difficulty_threshold` for a candidate block, based on the