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/network): Add an empty Parameters struct in Network::Testnet #8368

Merged
merged 16 commits into from
Apr 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
4 changes: 2 additions & 2 deletions zebra-chain/src/block/tests/vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ fn block_test_vectors_height_mainnet() {
fn block_test_vectors_height_testnet() {
let _init_guard = zebra_test::init();

block_test_vectors_height(Testnet);
block_test_vectors_height(Network::new_default_testnet());
}

/// Test that the block test vector indexes match the heights in the block data,
Expand Down Expand Up @@ -245,7 +245,7 @@ fn block_commitment_mainnet() {
fn block_commitment_testnet() {
let _init_guard = zebra_test::init();

block_commitment(Testnet);
block_commitment(Network::new_default_testnet());
}

/// Check that the block commitment field parses without errors.
Expand Down
4 changes: 2 additions & 2 deletions zebra-chain/src/history_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -372,8 +372,8 @@ impl NonEmptyHistoryTree {
}

/// Return the network where this tree is used.
pub fn network(&self) -> Network {
self.network.clone()
pub fn network(&self) -> &Network {
&self.network
}
}

Expand Down
13 changes: 7 additions & 6 deletions zebra-chain/src/history_tree/tests/vectors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ use eyre::Result;
/// higher level API.
#[test]
fn push_and_prune() -> Result<()> {
push_and_prune_for_network_upgrade(Network::Mainnet, NetworkUpgrade::Heartwood)?;
push_and_prune_for_network_upgrade(Network::Testnet, NetworkUpgrade::Heartwood)?;
push_and_prune_for_network_upgrade(Network::Mainnet, NetworkUpgrade::Canopy)?;
push_and_prune_for_network_upgrade(Network::Testnet, NetworkUpgrade::Canopy)?;
for network in Network::iter() {
push_and_prune_for_network_upgrade(network.clone(), NetworkUpgrade::Heartwood)?;
push_and_prune_for_network_upgrade(network, NetworkUpgrade::Canopy)?;
}
Ok(())
}

Expand Down Expand Up @@ -109,8 +109,9 @@ fn push_and_prune_for_network_upgrade(
fn upgrade() -> Result<()> {
// The history tree only exists Hearwood-onward, and the only upgrade for which
// we have vectors since then is Canopy. Therefore, only test the Heartwood->Canopy upgrade.
upgrade_for_network_upgrade(Network::Mainnet, NetworkUpgrade::Canopy)?;
upgrade_for_network_upgrade(Network::Testnet, NetworkUpgrade::Canopy)?;
for network in Network::iter() {
upgrade_for_network_upgrade(network, NetworkUpgrade::Canopy)?;
}
Ok(())
}

Expand Down
2 changes: 1 addition & 1 deletion zebra-chain/src/parameters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ mod transaction;
pub mod arbitrary;

pub use genesis::*;
pub use network::Network;
pub use network::{testnet, Network, NetworkKind};
pub use network_upgrade::*;
pub use transaction::*;

Expand Down
157 changes: 127 additions & 30 deletions zebra-chain/src/parameters/network.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
//! Consensus parameters for each Zcash network.

use std::{fmt, str::FromStr};
use std::{fmt, str::FromStr, sync::Arc};

use thiserror::Error;

use zcash_primitives::constants;

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

pub mod testnet;

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

Expand Down Expand Up @@ -51,52 +55,102 @@ mod tests;
/// after the grace period.
const ZIP_212_GRACE_PERIOD_DURATION: HeightDiff = 32_256;

/// An enum describing the kind of network, whether it's the production mainnet or a testnet.
// Note: The order of these variants is important for correct bincode (de)serialization
// of history trees in the db format.
// TODO: Replace bincode (de)serialization of `HistoryTreeParts` in a db format upgrade?
#[derive(Copy, Clone, Default, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)]
pub enum NetworkKind {
/// The production mainnet.
#[default]
Mainnet,

/// A test network.
Testnet,

/// Regtest mode, not yet implemented
// TODO: Add `new_regtest()` and `is_regtest` methods on `Network`.
Regtest,
}

impl From<Network> for NetworkKind {
fn from(network: Network) -> Self {
network.kind()
}
}

/// An enum describing the possible network choices.
#[derive(Clone, Debug, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
#[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.
#[default]
Mainnet,

/// The oldest public test network.
Testnet,
/// A test network such as the default public testnet,
/// a configured testnet, or Regtest.
Testnet(Arc<testnet::Parameters>),
}

use zcash_primitives::consensus::{Network as ZcashPrimitivesNetwork, Parameters as _};
impl Network {
impl NetworkKind {
/// Returns the human-readable prefix for Base58Check-encoded transparent
/// pay-to-public-key-hash payment addresses for the network.
pub fn b58_pubkey_address_prefix(&self) -> [u8; 2] {
<ZcashPrimitivesNetwork>::from(self).b58_pubkey_address_prefix()
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,
}
}

/// 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] {
<ZcashPrimitivesNetwork>::from(self).b58_script_address_prefix()
}
/// 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(&self, height: block::Height) -> bool {
pub fn b58_script_address_prefix(self) -> [u8; 2] {
match self {
Network::Mainnet => true,
Network::Testnet => height >= super::TESTNET_MAX_TIME_START_HEIGHT,
Self::Mainnet => constants::mainnet::B58_SCRIPT_ADDRESS_PREFIX,
Self::Testnet | Self::Regtest => constants::testnet::B58_SCRIPT_ADDRESS_PREFIX,
}
}

/// Return the network name as defined in
/// [BIP70](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#paymentdetailspaymentrequest)
pub fn bip70_network_name(&self) -> String {
if *self == Self::Mainnet {
"main".to_string()
} else {
"test".to_string()
}
}
}

impl From<NetworkKind> for &'static str {
fn from(network: NetworkKind) -> &'static str {
// These should be different from the `Display` impl for `Network` so that its lowercase form
// can't be parsed as the default Testnet in the `Network` `FromStr` impl, it's easy to
// distinguish them in logs, and so it's generally harder to confuse the two.
match network {
NetworkKind::Mainnet => "MainnetKind",
NetworkKind::Testnet => "TestnetKind",
NetworkKind::Regtest => "RegtestKind",
}
}
}

impl fmt::Display for NetworkKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_str((*self).into())
}
}

impl From<&Network> for &'static str {
fn from(network: &Network) -> &'static str {
match network {
Network::Mainnet => "Mainnet",
Network::Testnet => "Testnet",
// TODO:
// - Add a `name` field to use here instead of checking `is_default_testnet()`
// - zcashd calls the Regtest cache dir 'regtest' (#8327).
Network::Testnet(params) if params.is_default_testnet() => "Testnet",
Network::Testnet(_params) => "UnknownTestnet",
}
}
}
Expand All @@ -108,17 +162,62 @@ impl fmt::Display for Network {
}

impl Network {
/// Creates a new [`Network::Testnet`] with the default Testnet [`testnet::Parameters`].
pub fn new_default_testnet() -> Self {
Self::Testnet(Arc::new(testnet::Parameters::default()))
}

/// Creates a new configured [`Network::Testnet`] with the provided Testnet [`testnet::Parameters`].
pub fn new_configured_testnet(params: testnet::Parameters) -> Self {
Self::Testnet(Arc::new(params))
}

/// Returns true if the network is the default Testnet, or false otherwise.
pub fn is_default_testnet(&self) -> bool {
if let Self::Testnet(params) = self {
params.is_default_testnet()
} else {
false
}
}

/// Returns the [`NetworkKind`] for this network.
pub fn kind(&self) -> NetworkKind {
match self {
Network::Mainnet => NetworkKind::Mainnet,
// TODO: Return `NetworkKind::Regtest` if the parameters match the default Regtest params
Network::Testnet(_) => NetworkKind::Testnet,
}
}

/// Returns an iterator over [`Network`] variants.
pub fn iter() -> impl Iterator<Item = Self> {
// TODO: Use default values of `Testnet` variant when adding fields for #7845.
[Self::Mainnet, Self::Testnet].into_iter()
[Self::Mainnet, Self::new_default_testnet()].into_iter()
}

/// 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(&self, height: block::Height) -> bool {
match self {
Network::Mainnet => true,
// TODO: Move `TESTNET_MAX_TIME_START_HEIGHT` to a field on testnet::Parameters (#8364)
Network::Testnet(_params) => height >= super::TESTNET_MAX_TIME_START_HEIGHT,
}
}

/// Get the default port associated to this network.
pub fn default_port(&self) -> u16 {
match self {
Network::Mainnet => 8233,
Network::Testnet => 18233,
// TODO: Add a `default_port` field to `testnet::Parameters` to return here. (zcashd uses 18344 for Regtest)
Network::Testnet(_params) => 18233,
}
}

Expand All @@ -143,10 +242,7 @@ impl Network {
/// Return the network name as defined in
/// [BIP70](https://github.com/bitcoin/bips/blob/master/bip-0070.mediawiki#paymentdetailspaymentrequest)
pub fn bip70_network_name(&self) -> String {
match self {
Network::Mainnet => "main".to_string(),
Network::Testnet => "test".to_string(),
}
self.kind().bip70_network_name()
}

/// Return the lowercase network name.
Expand All @@ -167,13 +263,14 @@ impl Network {
}
}

// This is used for parsing a command-line argument for the `TipHeight` command in zebrad.
impl FromStr for Network {
type Err = InvalidNetworkError;

fn from_str(string: &str) -> Result<Self, Self::Err> {
match string.to_lowercase().as_str() {
"mainnet" => Ok(Network::Mainnet),
"testnet" => Ok(Network::Testnet),
"testnet" => Ok(Network::new_default_testnet()),
_ => Err(InvalidNetworkError(string.to_owned())),
}
}
Expand Down
16 changes: 16 additions & 0 deletions zebra-chain/src/parameters/network/testnet.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//! Types and implementation for Testnet consensus parameters

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

/// 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 {}

impl Parameters {
/// Returns true if the instance of [`Parameters`] represents the default public Testnet.
pub fn is_default_testnet(&self) -> bool {
self == &Self::default()
}
}
2 changes: 1 addition & 1 deletion zebra-chain/src/parameters/network/tests/prop.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,6 @@ proptest! {
let _init_guard = zebra_test::init();

assert!(Network::Mainnet.is_max_block_time_enforced(height));
assert_eq!(Network::Testnet.is_max_block_time_enforced(height), TESTNET_MAX_TIME_START_HEIGHT <= height);
assert_eq!(Network::new_default_testnet().is_max_block_time_enforced(height), TESTNET_MAX_TIME_START_HEIGHT <= height);
}
}
12 changes: 9 additions & 3 deletions zebra-chain/src/parameters/network_upgrade.rs
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,8 @@ impl Network {
};
match self {
Mainnet => mainnet_heights,
Testnet => testnet_heights,
// TODO: Add an `activation_heights` field to `testnet::Parameters` to return here. (#7970)
Testnet(_params) => testnet_heights,
}
.iter()
.cloned()
Expand Down Expand Up @@ -394,9 +395,14 @@ impl NetworkUpgrade {
height: block::Height,
) -> Option<Duration> {
match (network, height) {
(Network::Testnet, height) if height < TESTNET_MINIMUM_DIFFICULTY_START_HEIGHT => None,
// TODO: Move `TESTNET_MINIMUM_DIFFICULTY_START_HEIGHT` to a field on testnet::Parameters (#8364)
(Network::Testnet(_params), height)
if height < TESTNET_MINIMUM_DIFFICULTY_START_HEIGHT =>
{
None
}
(Network::Mainnet, _) => None,
(Network::Testnet, _) => {
(Network::Testnet(_params), _) => {
let network_upgrade = NetworkUpgrade::current(network, height);
Some(network_upgrade.target_spacing() * TESTNET_MINIMUM_DIFFICULTY_GAP_MULTIPLIER)
}
Expand Down
10 changes: 5 additions & 5 deletions zebra-chain/src/parameters/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ fn activation_bijective() {
let mainnet_nus: HashSet<&NetworkUpgrade> = mainnet_activations.values().collect();
assert_eq!(MAINNET_ACTIVATION_HEIGHTS.len(), mainnet_nus.len());

let testnet_activations = Testnet.activation_list();
let testnet_activations = Network::new_default_testnet().activation_list();
let testnet_heights: HashSet<&block::Height> = testnet_activations.keys().collect();
assert_eq!(TESTNET_ACTIVATION_HEIGHTS.len(), testnet_heights.len());

Expand All @@ -38,7 +38,7 @@ fn activation_extremes_mainnet() {
#[test]
fn activation_extremes_testnet() {
let _init_guard = zebra_test::init();
activation_extremes(Testnet)
activation_extremes(Network::new_default_testnet())
}

/// Test the activation_list, activation_height, current, and next functions
Expand Down Expand Up @@ -115,7 +115,7 @@ fn activation_consistent_mainnet() {
#[test]
fn activation_consistent_testnet() {
let _init_guard = zebra_test::init();
activation_consistent(Testnet)
activation_consistent(Network::new_default_testnet())
}

/// Check that the `activation_height`, `is_activation_height`,
Expand Down Expand Up @@ -178,7 +178,7 @@ fn branch_id_extremes_mainnet() {
#[test]
fn branch_id_extremes_testnet() {
let _init_guard = zebra_test::init();
branch_id_extremes(Testnet)
branch_id_extremes(Network::new_default_testnet())
}

/// Test the branch_id_list, branch_id, and current functions for `network` with
Expand Down Expand Up @@ -217,7 +217,7 @@ fn branch_id_consistent_mainnet() {
#[test]
fn branch_id_consistent_testnet() {
let _init_guard = zebra_test::init();
branch_id_consistent(Testnet)
branch_id_consistent(Network::new_default_testnet())
}

/// Check that the branch_id and current functions are consistent for `network`.
Expand Down
Loading
Loading