2023-01-17 16:27:42 -08:00
|
|
|
|
//! Consensus parameters for each Zcash network.
|
|
|
|
|
|
|
|
|
|
use std::{fmt, str::FromStr};
|
2022-05-05 20:31:52 -07:00
|
|
|
|
|
|
|
|
|
use thiserror::Error;
|
2020-10-30 12:36:20 -07:00
|
|
|
|
|
2023-03-29 16:06:31 -07:00
|
|
|
|
use crate::{
|
|
|
|
|
block::{Height, HeightDiff},
|
|
|
|
|
parameters::NetworkUpgrade::Canopy,
|
|
|
|
|
};
|
2021-06-17 17:05:28 -07:00
|
|
|
|
|
2020-09-23 18:52:52 -07:00
|
|
|
|
#[cfg(any(test, feature = "proptest-impl"))]
|
2020-08-15 15:45:37 -07:00
|
|
|
|
use proptest_derive::Arbitrary;
|
|
|
|
|
|
2022-03-16 17:37:50 -07:00
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod tests;
|
|
|
|
|
|
|
|
|
|
/// The ZIP-212 grace period length after the Canopy activation height.
|
|
|
|
|
///
|
|
|
|
|
/// # Consensus
|
|
|
|
|
///
|
|
|
|
|
/// ZIP-212 requires Zcash nodes to validate that Sapling spends and Orchard actions follows a
|
|
|
|
|
/// specific plaintext format after Canopy's activation.
|
|
|
|
|
///
|
|
|
|
|
/// > [Heartwood onward] All Sapling and Orchard outputs in coinbase transactions MUST decrypt to a
|
|
|
|
|
/// > note plaintext , i.e. the procedure in § 4.19.3 ‘Decryption using a Full Viewing Key (Sapling
|
|
|
|
|
/// > and Orchard)’ on p. 67 does not return ⊥, using a sequence of 32 zero bytes as the outgoing
|
|
|
|
|
/// > viewing key . (This implies that before Canopy activation, Sapling outputs of a coinbase
|
|
|
|
|
/// > transaction MUST have note plaintext lead byte equal to 0x01.)
|
|
|
|
|
///
|
|
|
|
|
/// > [Canopy onward] Any Sapling or Orchard output of a coinbase transaction decrypted to a note
|
|
|
|
|
/// > plaintext according to the preceding rule MUST have note plaintext lead byte equal to 0x02.
|
|
|
|
|
/// > (This applies even during the “grace period” specified in [ZIP-212].)
|
|
|
|
|
///
|
2022-05-30 13:12:11 -07:00
|
|
|
|
/// <https://zips.z.cash/protocol/protocol.pdf#txnencodingandconsensus>
|
2022-03-16 17:37:50 -07:00
|
|
|
|
///
|
|
|
|
|
/// Wallets have a grace period of 32,256 blocks after Canopy's activation to validate those blocks,
|
|
|
|
|
/// but nodes do not.
|
|
|
|
|
///
|
|
|
|
|
/// > There is a "grace period" of 32256 blocks starting from the block at which this ZIP activates,
|
|
|
|
|
/// > during which note plaintexts with lead byte 0x01 MUST still be accepted [by wallets].
|
|
|
|
|
/// >
|
|
|
|
|
/// > Let ActivationHeight be the activation height of this ZIP, and let GracePeriodEndHeight be
|
|
|
|
|
/// > ActivationHeight + 32256.
|
|
|
|
|
///
|
2022-05-30 13:12:11 -07:00
|
|
|
|
/// <https://zips.z.cash/zip-0212#changes-to-the-process-of-receiving-sapling-or-orchard-notes>
|
2022-03-16 17:37:50 -07:00
|
|
|
|
///
|
|
|
|
|
/// Zebra uses `librustzcash` to validate that rule, but it won't validate it during the grace
|
|
|
|
|
/// period. Therefore Zebra must validate those blocks during the grace period using checkpoints.
|
|
|
|
|
/// Therefore the mandatory checkpoint height ([`Network::mandatory_checkpoint_height`]) must be
|
|
|
|
|
/// after the grace period.
|
2023-03-29 16:06:31 -07:00
|
|
|
|
const ZIP_212_GRACE_PERIOD_DURATION: HeightDiff = 32_256;
|
2022-03-16 17:37:50 -07:00
|
|
|
|
|
2020-08-15 15:45:37 -07:00
|
|
|
|
/// An enum describing the possible network choices.
|
2023-01-17 16:27:42 -08:00
|
|
|
|
#[derive(Copy, Clone, Debug, Default, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
2020-09-23 18:52:52 -07:00
|
|
|
|
#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
|
2020-08-15 15:45:37 -07:00
|
|
|
|
pub enum Network {
|
|
|
|
|
/// The production mainnet.
|
2023-01-17 16:27:42 -08:00
|
|
|
|
#[default]
|
2020-08-15 15:45:37 -07:00
|
|
|
|
Mainnet,
|
2023-01-17 16:27:42 -08:00
|
|
|
|
|
2023-06-19 19:42:06 -07:00
|
|
|
|
/// The oldest public test network.
|
2020-08-15 15:45:37 -07:00
|
|
|
|
Testnet,
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-04 18:04:47 -07:00
|
|
|
|
impl From<Network> for &'static str {
|
|
|
|
|
fn from(network: Network) -> &'static str {
|
2021-04-19 13:48:14 -07:00
|
|
|
|
match network {
|
|
|
|
|
Network::Mainnet => "Mainnet",
|
|
|
|
|
Network::Testnet => "Testnet",
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-04 18:04:47 -07:00
|
|
|
|
impl From<&Network> for &'static str {
|
|
|
|
|
fn from(network: &Network) -> &'static str {
|
|
|
|
|
(*network).into()
|
2021-04-21 15:14:36 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-10-30 12:36:20 -07:00
|
|
|
|
impl fmt::Display for Network {
|
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
2021-04-19 13:48:14 -07:00
|
|
|
|
f.write_str(self.into())
|
2020-10-30 12:36:20 -07:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-04 10:19:20 -07:00
|
|
|
|
impl Network {
|
|
|
|
|
/// Get the default port associated to this network.
|
|
|
|
|
pub fn default_port(&self) -> u16 {
|
|
|
|
|
match self {
|
|
|
|
|
Network::Mainnet => 8233,
|
|
|
|
|
Network::Testnet => 18233,
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-06-17 17:05:28 -07:00
|
|
|
|
|
|
|
|
|
/// Get the mandatory minimum checkpoint height for this network.
|
|
|
|
|
///
|
|
|
|
|
/// Mandatory checkpoints are a Zebra-specific feature.
|
|
|
|
|
/// If a Zcash consensus rule only applies before the mandatory checkpoint,
|
|
|
|
|
/// Zebra can skip validation of that rule.
|
|
|
|
|
pub fn mandatory_checkpoint_height(&self) -> Height {
|
2022-03-16 17:37:50 -07:00
|
|
|
|
// Currently this is after the ZIP-212 grace period.
|
|
|
|
|
//
|
|
|
|
|
// See the `ZIP_212_GRACE_PERIOD_DOCUMENTATION` for more information.
|
|
|
|
|
|
|
|
|
|
let canopy_activation = Canopy
|
2021-06-17 17:05:28 -07:00
|
|
|
|
.activation_height(*self)
|
2022-03-16 17:37:50 -07:00
|
|
|
|
.expect("Canopy activation height must be present for both networks");
|
|
|
|
|
|
|
|
|
|
(canopy_activation + ZIP_212_GRACE_PERIOD_DURATION)
|
|
|
|
|
.expect("ZIP-212 grace period ends at a valid block height")
|
2021-06-17 17:05:28 -07:00
|
|
|
|
}
|
2022-03-25 05:25:31 -07:00
|
|
|
|
|
|
|
|
|
/// 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(),
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-06-06 01:28:14 -07:00
|
|
|
|
|
|
|
|
|
/// Return the lowercase network name.
|
|
|
|
|
pub fn lowercase_name(&self) -> String {
|
|
|
|
|
self.to_string().to_ascii_lowercase()
|
|
|
|
|
}
|
2023-06-19 19:42:06 -07:00
|
|
|
|
|
|
|
|
|
/// Returns `true` if this network is a testing network.
|
|
|
|
|
pub fn is_a_test_network(&self) -> bool {
|
|
|
|
|
*self != Network::Mainnet
|
|
|
|
|
}
|
2020-09-04 10:19:20 -07:00
|
|
|
|
}
|
|
|
|
|
|
2022-05-05 20:31:52 -07:00
|
|
|
|
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),
|
|
|
|
|
_ => Err(InvalidNetworkError(string.to_owned())),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, Error)]
|
|
|
|
|
#[error("Invalid network: {0}")]
|
|
|
|
|
pub struct InvalidNetworkError(String);
|