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

add(consensus): Add activation_heights field to NetworkParameters and implement Parameters for Network #8383

Merged
merged 37 commits into from
Apr 19, 2024
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
9db4762
minor cleanup and rename
arya2 Mar 20, 2024
4b86bd6
Adds an empty NetworkParameters struct to Network::Testnet variant, u…
arya2 Mar 20, 2024
7533e2f
Updates tests
arya2 Mar 20, 2024
06cf947
Adds `NetworkKind` and uses it instead of `Network` in `HistoryTreePa…
arya2 Mar 22, 2024
4900a20
Adds a [network.testnet_parameters] section to the config, uses `Netw…
arya2 Mar 22, 2024
cb8726b
Applies some suggestions from code review
arya2 Apr 1, 2024
d5a807a
Applies suggestions from code review
arya2 Apr 2, 2024
d108ec6
returns b58 prefix constants directly to remove From<NetworkKind> imp…
arya2 Apr 2, 2024
574b1f9
Applies more suggestions from code review.
arya2 Apr 2, 2024
05e41a2
moves conversions to zcash_primitives::consensus::Network to where th…
arya2 Apr 2, 2024
fd3d505
Apply suggestions from code review
arya2 Apr 11, 2024
f04b94b
rename `network` variables and method names typed as NetworkKind to `…
arya2 Apr 11, 2024
ea2d001
use only test block heights for the network associated with them
arya2 Apr 11, 2024
86cd919
Applies more suggestions from code review.
arya2 Apr 11, 2024
365b58e
Rename `NetworkParameters` to `Parameters` and move it a new `testnet…
arya2 Apr 11, 2024
eca7f6b
Merge branch 'main' into network-params
arya2 Apr 11, 2024
60248e3
adds activation heights field
arya2 Apr 2, 2024
b9bdf05
updates stored test config, adds a quicker test for checking that sto…
arya2 Apr 3, 2024
ad4e7dc
implement Parameters for Network
arya2 Apr 3, 2024
4347a80
Passes &Network directly instead of converting to zp_consensus::Netwo…
arya2 Apr 3, 2024
080affd
fixes a bad merge (removes a network conversion in zcash_note_encrypt…
arya2 Apr 11, 2024
2493e7e
Adds a test for the Parameters impl for zebra_chain::Network
arya2 Apr 11, 2024
997e265
fixes doc links
arya2 Apr 11, 2024
93c7a58
- Makes the `activation_heights` config field optional by adding a #[…
arya2 Apr 12, 2024
0fd4158
small refactor of activation_heights() method
arya2 Apr 12, 2024
3952caa
check that activation heights are in the right order
arya2 Apr 12, 2024
e697d36
Updates `NetworkUpgrade::activation_height()` to return the height of…
arya2 Apr 12, 2024
325a6c6
checks that the miner address is of TestnetKind on Regtest and update…
arya2 Apr 12, 2024
f724c01
Adds a DNetworkUpgradeActivationHeights struct for better control ove…
arya2 Apr 12, 2024
a37510a
moves all ordered network upgrades to a constant, adds a no_duplicate…
arya2 Apr 12, 2024
0abe873
panics if any network upgrades are configured to activate at Height(0…
arya2 Apr 12, 2024
1dfad53
Simplifies the `ParametersBuilder::activation_heights()` method and r…
arya2 Apr 12, 2024
868535b
Merge branch 'main' into activ-heights-param-impl
arya2 Apr 17, 2024
0b835f1
Adds Sapling HRPs as fields on testnet params. (#8398)
arya2 Apr 17, 2024
fb2d13a
Applies suggestions from code review.
arya2 Apr 17, 2024
fea2162
Update zebra-chain/src/parameters/network_upgrade.rs
arya2 Apr 18, 2024
9d832c3
Merge branch 'main' into activ-heights-param-impl
arya2 Apr 19, 2024
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
12 changes: 11 additions & 1 deletion zebra-chain/src/parameters/arbitrary.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

use proptest::prelude::*;

use super::NetworkUpgrade;
use super::{Network, NetworkUpgrade};

impl NetworkUpgrade {
/// Generates network upgrades.
Expand Down Expand Up @@ -32,3 +32,13 @@ impl NetworkUpgrade {
.boxed()
}
}

impl Arbitrary for Network {
type Parameters = ();

fn arbitrary_with(_args: ()) -> Self::Strategy {
prop_oneof![Just(Self::Mainnet), Just(Self::new_default_testnet())].boxed()
}

type Strategy = BoxedStrategy<Self>;
}
85 changes: 74 additions & 11 deletions zebra-chain/src/parameters/network.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,15 @@ use std::{fmt, str::FromStr, sync::Arc};

use thiserror::Error;

use zcash_primitives::constants;
use zcash_primitives::{consensus as zp_consensus, constants as zp_constants};

use crate::{
block::{self, Height, HeightDiff},
parameters::NetworkUpgrade::Canopy,
parameters::NetworkUpgrade,
};

pub mod testnet;

#[cfg(any(test, feature = "proptest-impl"))]
use proptest_derive::Arbitrary;

#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -81,7 +78,6 @@ impl From<Network> for NetworkKind {

/// An enum describing the possible network choices.
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Serialize)]
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
#[serde(into = "NetworkKind")]
pub enum Network {
/// The production mainnet.
Expand All @@ -98,17 +94,17 @@ impl NetworkKind {
/// pay-to-public-key-hash payment addresses for the network.
pub fn b58_pubkey_address_prefix(self) -> [u8; 2] {
match self {
Self::Mainnet => constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX,
Self::Testnet | Self::Regtest => constants::testnet::B58_PUBKEY_ADDRESS_PREFIX,
Self::Mainnet => zp_constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX,
Self::Testnet | Self::Regtest => zp_constants::testnet::B58_PUBKEY_ADDRESS_PREFIX,
}
}

/// Returns the human-readable prefix for Base58Check-encoded transparent pay-to-script-hash
/// payment addresses for the network.
pub fn b58_script_address_prefix(self) -> [u8; 2] {
match self {
Self::Mainnet => constants::mainnet::B58_SCRIPT_ADDRESS_PREFIX,
Self::Testnet | Self::Regtest => constants::testnet::B58_SCRIPT_ADDRESS_PREFIX,
Self::Mainnet => zp_constants::mainnet::B58_SCRIPT_ADDRESS_PREFIX,
Self::Testnet | Self::Regtest => zp_constants::testnet::B58_SCRIPT_ADDRESS_PREFIX,
}
}

Expand Down Expand Up @@ -231,7 +227,7 @@ impl Network {
//
// See the `ZIP_212_GRACE_PERIOD_DURATION` documentation for more information.

let canopy_activation = Canopy
let canopy_activation = NetworkUpgrade::Canopy
.activation_height(self)
.expect("Canopy activation height must be present for both networks");

Expand Down Expand Up @@ -279,3 +275,70 @@ impl FromStr for Network {
#[derive(Clone, Debug, Error)]
#[error("Invalid network: {0}")]
pub struct InvalidNetworkError(String);

impl zp_consensus::Parameters for Network {
fn activation_height(
&self,
nu: zcash_primitives::consensus::NetworkUpgrade,
) -> Option<zcash_primitives::consensus::BlockHeight> {
let target_nu = match nu {
zp_consensus::NetworkUpgrade::Overwinter => NetworkUpgrade::Overwinter,
zp_consensus::NetworkUpgrade::Sapling => NetworkUpgrade::Sapling,
zp_consensus::NetworkUpgrade::Blossom => NetworkUpgrade::Blossom,
zp_consensus::NetworkUpgrade::Heartwood => NetworkUpgrade::Heartwood,
zp_consensus::NetworkUpgrade::Canopy => NetworkUpgrade::Canopy,
zp_consensus::NetworkUpgrade::Nu5 => NetworkUpgrade::Nu5,
};

// Heights are hard-coded below Height::MAX or checked when the config is parsed.
target_nu
arya2 marked this conversation as resolved.
Show resolved Hide resolved
.activation_height(self)
.map(|Height(h)| zp_consensus::BlockHeight::from_u32(h))
}

fn coin_type(&self) -> u32 {
match self {
Network::Mainnet => zp_constants::mainnet::COIN_TYPE,
// The regtest cointype reuses the testnet cointype,
// See <https://github.com/satoshilabs/slips/blob/master/slip-0044.md>
Network::Testnet(_) => zp_constants::testnet::COIN_TYPE,
}
}

fn address_network(&self) -> Option<zcash_address::Network> {
match self {
Network::Mainnet => Some(zcash_address::Network::Main),
// TODO: Check if network is `Regtest` first, and if it is, return `zcash_address::Network::Regtest`
Network::Testnet(_params) => Some(zcash_address::Network::Test),
}
}

fn hrp_sapling_extended_spending_key(&self) -> &str {
match self {
Network::Mainnet => zp_constants::mainnet::HRP_SAPLING_EXTENDED_SPENDING_KEY,
Network::Testnet(params) => params.hrp_sapling_extended_spending_key(),
}
}

fn hrp_sapling_extended_full_viewing_key(&self) -> &str {
match self {
Network::Mainnet => zp_constants::mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY,
Network::Testnet(params) => params.hrp_sapling_extended_full_viewing_key(),
}
}

fn hrp_sapling_payment_address(&self) -> &str {
match self {
Network::Mainnet => zp_constants::mainnet::HRP_SAPLING_PAYMENT_ADDRESS,
Network::Testnet(params) => params.hrp_sapling_payment_address(),
}
}

fn b58_pubkey_address_prefix(&self) -> [u8; 2] {
self.kind().b58_pubkey_address_prefix()
}

fn b58_script_address_prefix(&self) -> [u8; 2] {
self.kind().b58_script_address_prefix()
}
arya2 marked this conversation as resolved.
Show resolved Hide resolved
}
214 changes: 209 additions & 5 deletions zebra-chain/src/parameters/network/testnet.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,220 @@
//! Types and implementation for Testnet consensus parameters
use std::collections::BTreeMap;

#[cfg(any(test, feature = "proptest-impl"))]
use proptest_derive::Arbitrary;
use zcash_primitives::constants as zp_constants;

use crate::{
block::Height,
parameters::{
network_upgrade::TESTNET_ACTIVATION_HEIGHTS, Network, NetworkUpgrade,
NETWORK_UPGRADES_IN_ORDER,
},
};

/// Configurable activation heights for Regtest and configured Testnets.
#[derive(Deserialize, Default)]
#[serde(rename_all = "PascalCase")]
pub struct ConfiguredActivationHeights {
/// Activation height for `BeforeOverwinter` network upgrade.
pub before_overwinter: Option<u32>,
/// Activation height for `Overwinter` network upgrade.
pub overwinter: Option<u32>,
/// Activation height for `Sapling` network upgrade.
pub sapling: Option<u32>,
/// Activation height for `Blossom` network upgrade.
pub blossom: Option<u32>,
/// Activation height for `Heartwood` network upgrade.
pub heartwood: Option<u32>,
/// Activation height for `Canopy` network upgrade.
pub canopy: Option<u32>,
/// Activation height for `NU5` network upgrade.
#[serde(rename = "NU5")]
pub nu5: Option<u32>,
}

/// Builder for the [`Parameters`] struct.
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct ParametersBuilder {
/// The network upgrade activation heights for this network, see [`Parameters::activation_heights`] for more details.
activation_heights: BTreeMap<Height, NetworkUpgrade>,
/// Sapling extended spending key human-readable prefix for this network
hrp_sapling_extended_spending_key: String,
/// Sapling extended full viewing key human-readable prefix for this network
hrp_sapling_extended_full_viewing_key: String,
/// Sapling payment address human-readable prefix for this network
hrp_sapling_payment_address: String,
}

impl Default for ParametersBuilder {
fn default() -> Self {
Self {
// # Correctness
//
// `Genesis` network upgrade activation height must always be 0
activation_heights: [
(Height(0), NetworkUpgrade::Genesis),
// TODO: Find out if `BeforeOverwinter` must always be active at Height(1), remove it here if it's not required.
(Height(1), NetworkUpgrade::BeforeOverwinter),
]
.into_iter()
.collect(),
hrp_sapling_extended_spending_key:
zp_constants::testnet::HRP_SAPLING_EXTENDED_SPENDING_KEY.to_string(),
hrp_sapling_extended_full_viewing_key:
zp_constants::testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY.to_string(),
hrp_sapling_payment_address: zp_constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS
.to_string(),
}
}
}

impl ParametersBuilder {
/// Checks that the provided network upgrade activation heights are in the correct order, then
/// sets them as the new network upgrade activation heights.
pub fn activation_heights(
mut self,
ConfiguredActivationHeights {
// TODO: Find out if `BeforeOverwinter` is required at Height(1), allow for
// configuring its activation height if it's not required to be at Height(1)
before_overwinter: _,
overwinter,
sapling,
blossom,
heartwood,
canopy,
nu5,
}: ConfiguredActivationHeights,
) -> Self {
use NetworkUpgrade::*;

// # Correctness
//
// These must be in order so that later network upgrades overwrite prior ones
// if multiple network upgrades are configured with the same activation height.
let activation_heights: BTreeMap<_, _> = overwinter
.into_iter()
.map(|h| (h, Overwinter))
.chain(sapling.into_iter().map(|h| (h, Sapling)))
.chain(blossom.into_iter().map(|h| (h, Blossom)))
.chain(heartwood.into_iter().map(|h| (h, Heartwood)))
.chain(canopy.into_iter().map(|h| (h, Canopy)))
.chain(nu5.into_iter().map(|h| (h, Nu5)))
.filter(|&(_, nu)| nu != NetworkUpgrade::BeforeOverwinter)
.map(|(h, nu)| (h.try_into().expect("activation height must be valid"), nu))
.collect();

let network_upgrades: Vec<_> = activation_heights.iter().map(|(_h, &nu)| nu).collect();

// Check that the provided network upgrade activation heights are in the same order by height as the default testnet activation heights
let mut activation_heights_iter = activation_heights.iter();
for expected_network_upgrade in NETWORK_UPGRADES_IN_ORDER {
if !network_upgrades.contains(&expected_network_upgrade) {
continue;
} else if let Some((&height, &network_upgrade)) = activation_heights_iter.next() {
assert_ne!(
height,
Height(0),
"Height(0) is reserved for the `Genesis` upgrade"
);

assert!(
network_upgrade == expected_network_upgrade,
"network upgrades must be activated in order, the correct order is {NETWORK_UPGRADES_IN_ORDER:?}"
);
}
}

// # Correctness
//
// Height(0) must be reserved for the `NetworkUpgrade::Genesis`.
self.activation_heights.split_off(&Height(2));
self.activation_heights.extend(activation_heights);

self
}

/// Converts the builder to a [`Parameters`] struct
pub fn finish(self) -> Parameters {
let Self {
activation_heights,
hrp_sapling_extended_spending_key,
hrp_sapling_extended_full_viewing_key,
hrp_sapling_payment_address,
} = self;
Parameters {
activation_heights,
hrp_sapling_extended_spending_key,
hrp_sapling_extended_full_viewing_key,
hrp_sapling_payment_address,
}
}

/// Converts the builder to a configured [`Network::Testnet`]
pub fn to_network(self) -> Network {
Network::new_configured_testnet(self.finish())
}
}

/// Network consensus parameters for test networks such as Regtest and the default Testnet.
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
pub struct Parameters {}
#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub struct Parameters {
/// The network upgrade activation heights for this network.
///
/// Note: This value is ignored by `Network::activation_list()` when `zebra-chain` is
/// compiled with the `zebra-test` feature flag AND the `TEST_FAKE_ACTIVATION_HEIGHTS`
/// environment variable is set.
activation_heights: BTreeMap<Height, NetworkUpgrade>,
/// Sapling extended spending key human-readable prefix for this network
hrp_sapling_extended_spending_key: String,
/// Sapling extended full viewing key human-readable prefix for this network
hrp_sapling_extended_full_viewing_key: String,
/// Sapling payment address human-readable prefix for this network
hrp_sapling_payment_address: String,
}

impl Default for Parameters {
/// Returns an instance of the default public testnet [`Parameters`].
fn default() -> Self {
Self {
activation_heights: TESTNET_ACTIVATION_HEIGHTS.iter().cloned().collect(),
hrp_sapling_extended_spending_key:
zp_constants::testnet::HRP_SAPLING_EXTENDED_SPENDING_KEY.to_string(),
hrp_sapling_extended_full_viewing_key:
zp_constants::testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY.to_string(),
hrp_sapling_payment_address: zp_constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS
.to_string(),
}
}
}

impl Parameters {
/// Creates a new [`ParametersBuilder`].
pub fn build() -> ParametersBuilder {
ParametersBuilder::default()
}

/// Returns true if the instance of [`Parameters`] represents the default public Testnet.
pub fn is_default_testnet(&self) -> bool {
self == &Self::default()
}

/// Returns the network upgrade activation heights
pub fn activation_heights(&self) -> &BTreeMap<Height, NetworkUpgrade> {
&self.activation_heights
}

/// Returns the `hrp_sapling_extended_spending_key` field
pub fn hrp_sapling_extended_spending_key(&self) -> &str {
&self.hrp_sapling_extended_spending_key
}

/// Returns the `hrp_sapling_extended_full_viewing_key` field
pub fn hrp_sapling_extended_full_viewing_key(&self) -> &str {
&self.hrp_sapling_extended_full_viewing_key
}

/// Returns the `hrp_sapling_payment_address` field
pub fn hrp_sapling_payment_address(&self) -> &str {
&self.hrp_sapling_payment_address
}
}
1 change: 1 addition & 0 deletions zebra-chain/src/parameters/network/tests.rs
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
mod prop;
mod vectors;
Loading
Loading