From 5b336806193ad5b37fe331ddddad6bf31e449f2c Mon Sep 17 00:00:00 2001 From: Arya Date: Fri, 3 May 2024 12:12:53 -0400 Subject: [PATCH 1/2] - Adds `slow_start_interval` field to `testnet::Parameters` - Moves SLOW_START_INTERVAL/SLOW_START_SHIFT constants to zebra-chain --- zebra-chain/src/parameters.rs | 1 + zebra-chain/src/parameters/constants.rs | 17 +++++ zebra-chain/src/parameters/network.rs | 8 --- zebra-chain/src/parameters/network/testnet.rs | 65 ++++++++++++++++++- zebra-consensus/src/block/check.rs | 4 +- zebra-consensus/src/block/subsidy/general.rs | 26 +++----- zebra-consensus/src/block/tests.rs | 4 +- zebra-consensus/src/parameters/subsidy.rs | 12 ---- 8 files changed, 95 insertions(+), 42 deletions(-) create mode 100644 zebra-chain/src/parameters/constants.rs diff --git a/zebra-chain/src/parameters.rs b/zebra-chain/src/parameters.rs index 2974bd78cce..acae466fc6d 100644 --- a/zebra-chain/src/parameters.rs +++ b/zebra-chain/src/parameters.rs @@ -12,6 +12,7 @@ //! Typically, consensus parameters are accessed via a function that takes a //! `Network` and `block::Height`. +pub mod constants; mod genesis; mod network; mod network_upgrade; diff --git a/zebra-chain/src/parameters/constants.rs b/zebra-chain/src/parameters/constants.rs new file mode 100644 index 00000000000..cb988c36c4e --- /dev/null +++ b/zebra-chain/src/parameters/constants.rs @@ -0,0 +1,17 @@ +//! Definitions of Zebra chain constants, including: +//! - slow start interval, +//! - slow start shift + +use crate::block::Height; + +/// An initial period from Genesis to this Height where the block subsidy is gradually incremented. [What is slow-start mining][slow-mining] +/// +/// [slow-mining]: https://z.cash/support/faq/#what-is-slow-start-mining +pub const SLOW_START_INTERVAL: Height = Height(20_000); + +/// `SlowStartShift()` as described in [protocol specification §7.8][7.8] +/// +/// [7.8]: https://zips.z.cash/protocol/protocol.pdf#subsidies +/// +/// This calculation is exact, because `SLOW_START_INTERVAL` is divisible by 2. +pub const SLOW_START_SHIFT: Height = Height(SLOW_START_INTERVAL.0 / 2); diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index 0bd9518dd2d..163509792c4 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -189,14 +189,6 @@ impl Network { } } - /// Returns true if proof-of-work validation should be disabled for this network - pub fn disable_pow(&self) -> bool { - if let Self::Testnet(params) = self { - params.disable_pow() - } else { - false - } - } /// Returns the [`NetworkKind`] for this network. pub fn kind(&self) -> NetworkKind { match self { diff --git a/zebra-chain/src/parameters/network/testnet.rs b/zebra-chain/src/parameters/network/testnet.rs index aa1b1e192ff..5819e460fbb 100644 --- a/zebra-chain/src/parameters/network/testnet.rs +++ b/zebra-chain/src/parameters/network/testnet.rs @@ -6,8 +6,9 @@ use zcash_primitives::constants as zp_constants; use crate::{ block::{self, Height}, parameters::{ - network_upgrade::TESTNET_ACTIVATION_HEIGHTS, Network, NetworkUpgrade, - NETWORK_UPGRADES_IN_ORDER, + constants::{SLOW_START_INTERVAL, SLOW_START_SHIFT}, + network_upgrade::TESTNET_ACTIVATION_HEIGHTS, + Network, NetworkUpgrade, NETWORK_UPGRADES_IN_ORDER, }, }; @@ -71,6 +72,8 @@ pub struct ParametersBuilder { hrp_sapling_extended_full_viewing_key: String, /// Sapling payment address human-readable prefix for this network hrp_sapling_payment_address: String, + /// Slow start interval for this network + slow_start_interval: Height, /// A flag for disabling proof-of-work checks when Zebra is validating blocks disable_pow: bool, } @@ -93,6 +96,7 @@ impl Default for ParametersBuilder { genesis_hash: TESTNET_GENESIS_HASH .parse() .expect("hard-coded hash parses"), + slow_start_interval: SLOW_START_INTERVAL, disable_pow: false, } } @@ -234,6 +238,12 @@ impl ParametersBuilder { self } + /// Sets the `disable_pow` flag to be used in the [`Parameters`] being built. + pub fn with_slow_start_interval(mut self, slow_start_interval: Height) -> Self { + self.slow_start_interval = slow_start_interval; + self + } + /// Sets the `disable_pow` flag to be used in the [`Parameters`] being built. pub fn with_disable_pow(mut self, disable_pow: bool) -> Self { self.disable_pow = disable_pow; @@ -249,6 +259,7 @@ impl ParametersBuilder { hrp_sapling_extended_spending_key, hrp_sapling_extended_full_viewing_key, hrp_sapling_payment_address, + slow_start_interval, disable_pow, } = self; Parameters { @@ -258,6 +269,8 @@ impl ParametersBuilder { hrp_sapling_extended_spending_key, hrp_sapling_extended_full_viewing_key, hrp_sapling_payment_address, + slow_start_interval, + slow_start_shift: Height(slow_start_interval.0 / 2), disable_pow, } } @@ -287,6 +300,10 @@ pub struct Parameters { hrp_sapling_extended_full_viewing_key: String, /// Sapling payment address human-readable prefix for this network hrp_sapling_payment_address: String, + /// Slow start interval for this network + slow_start_interval: Height, + /// Slow start shift for this network, always half the slow start interval + slow_start_shift: Height, /// A flag for disabling proof-of-work checks when Zebra is validating blocks disable_pow: bool, } @@ -316,6 +333,7 @@ impl Parameters { ..Self::build() .with_genesis_hash(REGTEST_GENESIS_HASH) .with_disable_pow(true) + .with_slow_start_interval(Height::MIN) .with_sapling_hrps( zp_constants::regtest::HRP_SAPLING_EXTENDED_SPENDING_KEY, zp_constants::regtest::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY, @@ -346,6 +364,8 @@ impl Parameters { hrp_sapling_extended_spending_key, hrp_sapling_extended_full_viewing_key, hrp_sapling_payment_address, + slow_start_interval, + slow_start_shift, disable_pow, } = Self::new_regtest(); @@ -354,6 +374,8 @@ impl Parameters { && self.hrp_sapling_extended_spending_key == hrp_sapling_extended_spending_key && self.hrp_sapling_extended_full_viewing_key == hrp_sapling_extended_full_viewing_key && self.hrp_sapling_payment_address == hrp_sapling_payment_address + && self.slow_start_interval == slow_start_interval + && self.slow_start_shift == slow_start_shift && self.disable_pow == disable_pow } @@ -387,8 +409,47 @@ impl Parameters { &self.hrp_sapling_payment_address } + /// Returns slow start interval for this network + pub fn slow_start_interval(&self) -> Height { + self.slow_start_interval + } + + /// Returns slow start shift for this network + pub fn slow_start_shift(&self) -> Height { + self.slow_start_shift + } + /// Returns true if proof-of-work validation should be disabled for this network pub fn disable_pow(&self) -> bool { self.disable_pow } } + +impl Network { + /// Returns true if proof-of-work validation should be disabled for this network + pub fn disable_pow(&self) -> bool { + if let Self::Testnet(params) = self { + params.disable_pow() + } else { + false + } + } + + /// Returns slow start interval for this network + pub fn slow_start_interval(&self) -> Height { + if let Self::Testnet(params) = self { + params.slow_start_interval() + } else { + SLOW_START_INTERVAL + } + } + + /// Returns slow start shift for this network + pub fn slow_start_shift(&self) -> Height { + if let Self::Testnet(params) = self { + params.slow_start_shift() + } else { + SLOW_START_SHIFT + } + } +} diff --git a/zebra-consensus/src/block/check.rs b/zebra-consensus/src/block/check.rs index e40723f18c5..349d14bb611 100644 --- a/zebra-consensus/src/block/check.rs +++ b/zebra-consensus/src/block/check.rs @@ -15,7 +15,7 @@ use zebra_chain::{ }, }; -use crate::{error::*, parameters::SLOW_START_INTERVAL}; +use crate::error::*; use super::subsidy; @@ -162,7 +162,7 @@ pub fn subsidy_is_valid(block: &Block, network: &Network) -> Result<(), BlockErr let slow_start_interval = if network.disable_pow() { Height(0) } else { - SLOW_START_INTERVAL + network.slow_start_interval() }; if height < slow_start_interval { diff --git a/zebra-consensus/src/block/subsidy/general.rs b/zebra-consensus/src/block/subsidy/general.rs index ab3c1b1a0d2..84c9ba0ccce 100644 --- a/zebra-consensus/src/block/subsidy/general.rs +++ b/zebra-consensus/src/block/subsidy/general.rs @@ -25,20 +25,13 @@ pub fn halving_divisor(height: Height, network: &Network) -> Option { .activation_height(network) .expect("blossom activation height should be available"); - // TODO: Add this as a field on `testnet::Parameters` instead of checking `disable_pow()`, this is 0 for Regtest in zcashd, - // see - let slow_start_shift = if network.disable_pow() { - Height(0) - } else { - SLOW_START_SHIFT - }; - - if height < slow_start_shift { + if height < network.slow_start_shift() { unreachable!( - "unsupported block height {height:?}: checkpoints should handle blocks below {slow_start_shift:?}", + "unsupported block height {height:?}: checkpoints should handle blocks below {:?}", + network.slow_start_shift() ) } else if height < blossom_height { - let pre_blossom_height = height - slow_start_shift; + let pre_blossom_height = height - network.slow_start_shift(); let halving_shift = pre_blossom_height / PRE_BLOSSOM_HALVING_INTERVAL; let halving_div = 1u64 @@ -51,7 +44,7 @@ pub fn halving_divisor(height: Height, network: &Network) -> Option { Some(halving_div) } else { - let pre_blossom_height = blossom_height - slow_start_shift; + let pre_blossom_height = blossom_height - network.slow_start_shift(); let scaled_pre_blossom_height = pre_blossom_height * HeightDiff::from(BLOSSOM_POW_TARGET_SPACING_RATIO); @@ -87,9 +80,10 @@ pub fn block_subsidy(height: Height, network: &Network) -> Result - if height < SLOW_START_INTERVAL && !network.disable_pow() { + if height < network.slow_start_interval() && !network.disable_pow() { unreachable!( - "unsupported block height {height:?}: callers should handle blocks below {SLOW_START_INTERVAL:?}", + "unsupported block height {height:?}: callers should handle blocks below {:?}", + network.slow_start_interval() ) } else if height < blossom_height { // this calculation is exact, because the halving divisor is 1 here @@ -145,7 +139,7 @@ mod test { assert_eq!( 1, - halving_divisor((SLOW_START_INTERVAL + 1).unwrap(), network).unwrap() + halving_divisor((network.slow_start_interval() + 1).unwrap(), network).unwrap() ); assert_eq!( 1, @@ -274,7 +268,7 @@ mod test { // https://z.cash/support/faq/#what-is-slow-start-mining assert_eq!( Amount::try_from(1_250_000_000), - block_subsidy((SLOW_START_INTERVAL + 1).unwrap(), network) + block_subsidy((network.slow_start_interval() + 1).unwrap(), network) ); assert_eq!( Amount::try_from(1_250_000_000), diff --git a/zebra-consensus/src/block/tests.rs b/zebra-consensus/src/block/tests.rs index 52c24a1f3e7..f5b93faa6a8 100644 --- a/zebra-consensus/src/block/tests.rs +++ b/zebra-consensus/src/block/tests.rs @@ -20,7 +20,7 @@ use zebra_chain::{ use zebra_script::CachedFfiTransaction; use zebra_test::transcript::{ExpectedTranscriptError, Transcript}; -use crate::{parameters::SLOW_START_SHIFT, transaction}; +use crate::transaction; use super::*; @@ -470,7 +470,7 @@ fn miner_fees_validation_for_network(network: Network) -> Result<(), Report> { let block_iter = network.block_iter(); for (&height, block) in block_iter { - if Height(height) > SLOW_START_SHIFT { + if Height(height) > network.slow_start_shift() { let block = Block::zcash_deserialize(&block[..]).expect("block should deserialize"); // fake the miner fee to a big amount diff --git a/zebra-consensus/src/parameters/subsidy.rs b/zebra-consensus/src/parameters/subsidy.rs index 119442e9d71..268221c6669 100644 --- a/zebra-consensus/src/parameters/subsidy.rs +++ b/zebra-consensus/src/parameters/subsidy.rs @@ -10,18 +10,6 @@ use zebra_chain::{ parameters::{Network, NetworkKind, NetworkUpgrade}, }; -/// An initial period from Genesis to this Height where the block subsidy is gradually incremented. [What is slow-start mining][slow-mining] -/// -/// [slow-mining]: https://z.cash/support/faq/#what-is-slow-start-mining -pub const SLOW_START_INTERVAL: Height = Height(20_000); - -/// `SlowStartShift()` as described in [protocol specification §7.8][7.8] -/// -/// [7.8]: https://zips.z.cash/protocol/protocol.pdf#subsidies -/// -/// This calculation is exact, because `SLOW_START_INTERVAL` is divisible by 2. -pub const SLOW_START_SHIFT: Height = Height(SLOW_START_INTERVAL.0 / 2); - /// The largest block subsidy, used before the first halving. /// /// We use `25 / 2` instead of `12.5`, so that we can calculate the correct value without using floating-point. From ac4b587719401bec644cf8a88d98799045938df0 Mon Sep 17 00:00:00 2001 From: Arya Date: Wed, 8 May 2024 10:51:41 -0400 Subject: [PATCH 2/2] Apply suggestions from code review Co-authored-by: Marek --- zebra-chain/src/parameters/network/testnet.rs | 2 +- zebra-consensus/src/block/subsidy/general.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/zebra-chain/src/parameters/network/testnet.rs b/zebra-chain/src/parameters/network/testnet.rs index 5819e460fbb..3ca4d0f5b7a 100644 --- a/zebra-chain/src/parameters/network/testnet.rs +++ b/zebra-chain/src/parameters/network/testnet.rs @@ -238,7 +238,7 @@ impl ParametersBuilder { self } - /// Sets the `disable_pow` flag to be used in the [`Parameters`] being built. + /// Sets the slow start interval to be used in the [`Parameters`] being built. pub fn with_slow_start_interval(mut self, slow_start_interval: Height) -> Self { self.slow_start_interval = slow_start_interval; self diff --git a/zebra-consensus/src/block/subsidy/general.rs b/zebra-consensus/src/block/subsidy/general.rs index 84c9ba0ccce..d7013c84ed4 100644 --- a/zebra-consensus/src/block/subsidy/general.rs +++ b/zebra-consensus/src/block/subsidy/general.rs @@ -26,7 +26,7 @@ pub fn halving_divisor(height: Height, network: &Network) -> Option { .expect("blossom activation height should be available"); if height < network.slow_start_shift() { - unreachable!( + panic!( "unsupported block height {height:?}: checkpoints should handle blocks below {:?}", network.slow_start_shift() )