diff --git a/zebra-chain/src/parameters/network_upgrade.rs b/zebra-chain/src/parameters/network_upgrade.rs index e4da0db51..132368a19 100644 --- a/zebra-chain/src/parameters/network_upgrade.rs +++ b/zebra-chain/src/parameters/network_upgrade.rs @@ -118,6 +118,12 @@ const TESTNET_MINIMUM_DIFFICULTY_GAP_MULTIPLIER: i32 = 6; /// Based on https://zips.z.cash/zip-0208#minimum-difficulty-blocks-on-the-test-network const TESTNET_MINIMUM_DIFFICULTY_START_HEIGHT: block::Height = block::Height(299_188); +/// The activation height for the block maximum time rule on Testnet. +/// +/// Part of the block header consensus rules in the Zcash specification at +/// https://zips.z.cash/protocol/protocol.pdf#blockheader +pub const TESTNET_MAX_TIME_START_HEIGHT: block::Height = block::Height(653_606); + impl NetworkUpgrade { /// Returns a BTreeMap of activation heights and network upgrades for /// `network`. @@ -274,6 +280,21 @@ impl NetworkUpgrade { ) -> Duration { NetworkUpgrade::current(network, height).averaging_window_timespan() } + + /// Returns true if the maximum block time rule is active for `network` and `height`. + /// + /// Always returns true if `network` is the Mainnet. + /// If `network` is the Testnet, the `height` should be at least + /// TESTNET_MAX_TIME_START_HEIGHT to return true. + /// Returns false otherwise. + /// + /// Part of the consensus rules at https://zips.z.cash/protocol/protocol.pdf#blockheader + pub fn is_max_block_time_enforced(network: Network, height: block::Height) -> bool { + match network { + Network::Mainnet => true, + Network::Testnet => height >= TESTNET_MAX_TIME_START_HEIGHT, + } + } } impl ConsensusBranchId { diff --git a/zebra-state/src/service/check.rs b/zebra-state/src/service/check.rs index f9c580ea2..bdb8bc28c 100644 --- a/zebra-state/src/service/check.rs +++ b/zebra-state/src/service/check.rs @@ -5,8 +5,8 @@ use std::borrow::Borrow; use chrono::Duration; use zebra_chain::{ block::{self, Block}, - parameters::Network, parameters::POW_AVERAGING_WINDOW, + parameters::{Network, NetworkUpgrade}, work::difficulty::CompactDifficulty, }; @@ -14,7 +14,7 @@ use crate::{PreparedBlock, ValidateContextError}; use super::check; -use difficulty::{AdjustedDifficulty, POW_MEDIAN_BLOCK_SPAN, TESTNET_MAX_TIME_START_HEIGHT}; +use difficulty::{AdjustedDifficulty, POW_MEDIAN_BLOCK_SPAN}; pub(crate) mod difficulty; @@ -148,7 +148,7 @@ fn difficulty_threshold_is_valid( } // The maximum time rule is only active on Testnet from a specific height - if (network == Network::Mainnet || candidate_height >= TESTNET_MAX_TIME_START_HEIGHT) + if NetworkUpgrade::is_max_block_time_enforced(network, candidate_height) && candidate_time > block_time_max { Err(ValidateContextError::TimeTooLate { diff --git a/zebra-state/src/service/check/difficulty.rs b/zebra-state/src/service/check/difficulty.rs index f71538f61..44bf03120 100644 --- a/zebra-state/src/service/check/difficulty.rs +++ b/zebra-state/src/service/check/difficulty.rs @@ -42,11 +42,6 @@ pub const POW_MAX_ADJUST_DOWN_PERCENT: i32 = 32; /// Part of the block header consensus rules in the Zcash specification. pub const BLOCK_MAX_TIME_SINCE_MEDIAN: i64 = 90 * 60; -/// The activation height for the block maximum time rule on Testnet. -/// -/// Part of the block header consensus rules in the Zcash specification. -pub const TESTNET_MAX_TIME_START_HEIGHT: block::Height = block::Height(653_606); - /// Contains the context needed to calculate the adjusted difficulty for a block. pub(super) struct AdjustedDifficulty { /// The `header.time` field from the candidate block