2020-04-23 20:38:54 -07:00
|
|
|
//! Consensus logic and parameters.
|
2019-11-25 07:41:14 -08:00
|
|
|
|
2020-08-05 13:08:58 -07:00
|
|
|
use std::cmp::{Ord, Ordering};
|
2019-11-27 05:12:28 -08:00
|
|
|
use std::convert::TryFrom;
|
2019-11-26 15:44:57 -08:00
|
|
|
use std::fmt;
|
2021-05-11 09:10:21 -07:00
|
|
|
use std::ops::{Add, Bound, RangeBounds, Sub};
|
2019-11-26 15:44:57 -08:00
|
|
|
|
2020-08-05 13:27:40 -07:00
|
|
|
use crate::constants;
|
|
|
|
|
2020-09-18 09:40:30 -07:00
|
|
|
/// A wrapper type representing blockchain heights. Safe conversion from
|
|
|
|
/// various integer types, as well as addition and subtraction, are provided.
|
2020-08-05 13:08:58 -07:00
|
|
|
#[repr(transparent)]
|
|
|
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
|
|
|
|
pub struct BlockHeight(u32);
|
|
|
|
|
|
|
|
pub const H0: BlockHeight = BlockHeight(0);
|
|
|
|
|
|
|
|
impl BlockHeight {
|
|
|
|
pub const fn from_u32(v: u32) -> BlockHeight {
|
|
|
|
BlockHeight(v)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for BlockHeight {
|
|
|
|
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
self.0.fmt(formatter)
|
|
|
|
}
|
|
|
|
}
|
2019-11-26 15:44:57 -08:00
|
|
|
|
2020-08-05 13:08:58 -07:00
|
|
|
impl Ord for BlockHeight {
|
|
|
|
fn cmp(&self, other: &Self) -> Ordering {
|
|
|
|
self.0.cmp(&other.0)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PartialOrd for BlockHeight {
|
|
|
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
|
|
|
Some(self.cmp(other))
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<u32> for BlockHeight {
|
|
|
|
fn from(value: u32) -> Self {
|
|
|
|
BlockHeight(value)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-22 19:44:06 -07:00
|
|
|
impl From<BlockHeight> for u32 {
|
|
|
|
fn from(value: BlockHeight) -> u32 {
|
|
|
|
value.0
|
2020-08-05 13:08:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-22 19:44:06 -07:00
|
|
|
impl TryFrom<u64> for BlockHeight {
|
2020-08-05 13:08:58 -07:00
|
|
|
type Error = std::num::TryFromIntError;
|
|
|
|
|
2020-07-22 19:44:06 -07:00
|
|
|
fn try_from(value: u64) -> Result<Self, Self::Error> {
|
2020-08-05 13:08:58 -07:00
|
|
|
u32::try_from(value).map(BlockHeight)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-22 19:44:06 -07:00
|
|
|
impl From<BlockHeight> for u64 {
|
|
|
|
fn from(value: BlockHeight) -> u64 {
|
|
|
|
value.0 as u64
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl TryFrom<i32> for BlockHeight {
|
2020-08-05 13:08:58 -07:00
|
|
|
type Error = std::num::TryFromIntError;
|
|
|
|
|
2020-07-22 19:44:06 -07:00
|
|
|
fn try_from(value: i32) -> Result<Self, Self::Error> {
|
2020-08-05 13:08:58 -07:00
|
|
|
u32::try_from(value).map(BlockHeight)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-07-22 19:44:06 -07:00
|
|
|
impl TryFrom<i64> for BlockHeight {
|
|
|
|
type Error = std::num::TryFromIntError;
|
2020-08-05 13:08:58 -07:00
|
|
|
|
2020-07-22 19:44:06 -07:00
|
|
|
fn try_from(value: i64) -> Result<Self, Self::Error> {
|
|
|
|
u32::try_from(value).map(BlockHeight)
|
2020-08-05 13:08:58 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl From<BlockHeight> for i64 {
|
|
|
|
fn from(value: BlockHeight) -> i64 {
|
|
|
|
value.0 as i64
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Add<u32> for BlockHeight {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn add(self, other: u32) -> Self {
|
|
|
|
BlockHeight(self.0 + other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Add for BlockHeight {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn add(self, other: Self) -> Self {
|
|
|
|
self + other.0
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Sub<u32> for BlockHeight {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn sub(self, other: u32) -> Self {
|
|
|
|
if other > self.0 {
|
|
|
|
panic!("Subtraction resulted in negative block height.");
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
2020-08-05 13:08:58 -07:00
|
|
|
|
|
|
|
BlockHeight(self.0 - other)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Sub for BlockHeight {
|
|
|
|
type Output = Self;
|
|
|
|
|
|
|
|
fn sub(self, other: Self) -> Self {
|
|
|
|
self - other.0
|
|
|
|
}
|
|
|
|
}
|
2019-11-26 15:44:57 -08:00
|
|
|
|
|
|
|
/// Zcash consensus parameters.
|
2020-09-18 09:40:30 -07:00
|
|
|
pub trait Parameters: Clone {
|
|
|
|
/// Returns the activation height for a particular network upgrade,
|
|
|
|
/// if an activation height has been set.
|
2020-08-05 13:27:40 -07:00
|
|
|
fn activation_height(&self, nu: NetworkUpgrade) -> Option<BlockHeight>;
|
|
|
|
|
2020-10-21 13:12:30 -07:00
|
|
|
/// Determines whether the specified network upgrade is active as of the
|
|
|
|
/// provided block height on the network to which this Parameters value applies.
|
|
|
|
fn is_nu_active(&self, nu: NetworkUpgrade, height: BlockHeight) -> bool {
|
|
|
|
self.activation_height(nu).map_or(false, |h| h <= height)
|
|
|
|
}
|
|
|
|
|
2020-10-20 16:09:31 -07:00
|
|
|
/// The coin type for ZEC, as defined by [SLIP 44].
|
|
|
|
///
|
|
|
|
/// [SLIP 44]: https://github.com/satoshilabs/slips/blob/master/slip-0044.md
|
|
|
|
fn coin_type(&self) -> u32;
|
|
|
|
|
2021-01-12 19:45:28 -08:00
|
|
|
/// Returns the human-readable prefix for Bech32-encoded Sapling extended spending keys
|
2020-10-21 13:12:30 -07:00
|
|
|
/// the network to which this Parameters value applies.
|
|
|
|
///
|
|
|
|
/// Defined in [ZIP 32].
|
|
|
|
///
|
|
|
|
/// [`ExtendedSpendingKey`]: zcash_primitives::zip32::ExtendedSpendingKey
|
|
|
|
/// [ZIP 32]: https://github.com/zcash/zips/blob/master/zip-0032.rst
|
|
|
|
fn hrp_sapling_extended_spending_key(&self) -> &str;
|
|
|
|
|
2021-01-12 19:45:28 -08:00
|
|
|
/// Returns the human-readable prefix for Bech32-encoded Sapling extended full
|
2020-09-18 09:40:30 -07:00
|
|
|
/// viewing keys for the network to which this Parameters value applies.
|
2020-10-21 13:12:30 -07:00
|
|
|
///
|
|
|
|
/// Defined in [ZIP 32].
|
|
|
|
///
|
|
|
|
/// [`ExtendedFullViewingKey`]: zcash_primitives::zip32::ExtendedFullViewingKey
|
|
|
|
/// [ZIP 32]: https://github.com/zcash/zips/blob/master/zip-0032.rst
|
2020-08-05 13:27:40 -07:00
|
|
|
fn hrp_sapling_extended_full_viewing_key(&self) -> &str;
|
|
|
|
|
2020-10-21 13:12:30 -07:00
|
|
|
/// Returns the Bech32-encoded human-readable prefix for Sapling payment addresses
|
2020-09-18 09:40:30 -07:00
|
|
|
/// viewing keys for the network to which this Parameters value applies.
|
2020-10-21 13:12:30 -07:00
|
|
|
///
|
|
|
|
/// Defined in section 5.6.4 of the [Zcash Protocol Specification].
|
|
|
|
///
|
|
|
|
/// [`PaymentAddress`]: zcash_primitives::primitives::PaymentAddress
|
|
|
|
/// [Zcash Protocol Specification]: https://github.com/zcash/zips/blob/master/protocol/protocol.pdf
|
2020-08-05 13:27:40 -07:00
|
|
|
fn hrp_sapling_payment_address(&self) -> &str;
|
|
|
|
|
2021-01-12 19:45:28 -08:00
|
|
|
/// Returns the human-readable prefix for Base58Check-encoded transparent
|
2020-10-21 13:12:30 -07:00
|
|
|
/// pay-to-public-key-hash payment addresses for the network to which this Parameters value
|
|
|
|
/// applies.
|
|
|
|
///
|
|
|
|
/// [`TransparentAddress::PublicKey`]: zcash_primitives::legacy::TransparentAddress::PublicKey
|
2020-08-05 13:27:40 -07:00
|
|
|
fn b58_pubkey_address_prefix(&self) -> [u8; 2];
|
2019-11-26 15:44:57 -08:00
|
|
|
|
2021-01-12 19:45:28 -08:00
|
|
|
/// Returns the human-readable prefix for Base58Check-encoded transparent pay-to-script-hash
|
2020-09-18 09:40:30 -07:00
|
|
|
/// payment addresses for the network to which this Parameters value applies.
|
2020-10-21 13:12:30 -07:00
|
|
|
///
|
|
|
|
/// [`TransparentAddress::Script`]: zcash_primitives::legacy::TransparentAddress::Script
|
2020-08-05 13:27:40 -07:00
|
|
|
fn b58_script_address_prefix(&self) -> [u8; 2];
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Marker struct for the production network.
|
2020-09-18 09:40:30 -07:00
|
|
|
#[derive(PartialEq, Copy, Clone, Debug)]
|
2019-11-26 15:44:57 -08:00
|
|
|
pub struct MainNetwork;
|
|
|
|
|
2020-09-18 09:40:30 -07:00
|
|
|
pub const MAIN_NETWORK: MainNetwork = MainNetwork;
|
2020-09-17 10:55:39 -07:00
|
|
|
|
2019-11-26 15:44:57 -08:00
|
|
|
impl Parameters for MainNetwork {
|
2020-09-17 10:55:39 -07:00
|
|
|
fn activation_height(&self, nu: NetworkUpgrade) -> Option<BlockHeight> {
|
2019-11-26 15:44:57 -08:00
|
|
|
match nu {
|
2020-09-17 10:55:39 -07:00
|
|
|
NetworkUpgrade::Overwinter => Some(BlockHeight(347_500)),
|
|
|
|
NetworkUpgrade::Sapling => Some(BlockHeight(419_200)),
|
|
|
|
NetworkUpgrade::Blossom => Some(BlockHeight(653_600)),
|
|
|
|
NetworkUpgrade::Heartwood => Some(BlockHeight(903_000)),
|
|
|
|
NetworkUpgrade::Canopy => Some(BlockHeight(1_046_400)),
|
2021-05-11 09:10:21 -07:00
|
|
|
NetworkUpgrade::Nu5 => None,
|
2020-09-23 09:53:48 -07:00
|
|
|
#[cfg(feature = "zfuture")]
|
2020-09-22 09:06:54 -07:00
|
|
|
NetworkUpgrade::ZFuture => None,
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
}
|
2020-09-17 10:55:39 -07:00
|
|
|
|
2020-10-20 16:09:31 -07:00
|
|
|
fn coin_type(&self) -> u32 {
|
|
|
|
constants::mainnet::COIN_TYPE
|
|
|
|
}
|
|
|
|
|
2020-10-21 13:12:30 -07:00
|
|
|
fn hrp_sapling_extended_spending_key(&self) -> &str {
|
|
|
|
constants::mainnet::HRP_SAPLING_EXTENDED_SPENDING_KEY
|
|
|
|
}
|
|
|
|
|
2020-09-17 10:55:39 -07:00
|
|
|
fn hrp_sapling_extended_full_viewing_key(&self) -> &str {
|
|
|
|
constants::mainnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY
|
|
|
|
}
|
|
|
|
|
|
|
|
fn hrp_sapling_payment_address(&self) -> &str {
|
|
|
|
constants::mainnet::HRP_SAPLING_PAYMENT_ADDRESS
|
|
|
|
}
|
|
|
|
|
|
|
|
fn b58_pubkey_address_prefix(&self) -> [u8; 2] {
|
|
|
|
constants::mainnet::B58_PUBKEY_ADDRESS_PREFIX
|
|
|
|
}
|
|
|
|
|
|
|
|
fn b58_script_address_prefix(&self) -> [u8; 2] {
|
|
|
|
constants::mainnet::B58_SCRIPT_ADDRESS_PREFIX
|
|
|
|
}
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Marker struct for the test network.
|
2020-09-18 09:40:30 -07:00
|
|
|
#[derive(PartialEq, Copy, Clone, Debug)]
|
2019-11-26 15:44:57 -08:00
|
|
|
pub struct TestNetwork;
|
|
|
|
|
2020-09-18 09:40:30 -07:00
|
|
|
pub const TEST_NETWORK: TestNetwork = TestNetwork;
|
2020-09-17 10:55:39 -07:00
|
|
|
|
2019-11-26 15:44:57 -08:00
|
|
|
impl Parameters for TestNetwork {
|
2020-09-17 10:55:39 -07:00
|
|
|
fn activation_height(&self, nu: NetworkUpgrade) -> Option<BlockHeight> {
|
2019-11-26 15:44:57 -08:00
|
|
|
match nu {
|
2020-09-17 10:55:39 -07:00
|
|
|
NetworkUpgrade::Overwinter => Some(BlockHeight(207_500)),
|
|
|
|
NetworkUpgrade::Sapling => Some(BlockHeight(280_000)),
|
|
|
|
NetworkUpgrade::Blossom => Some(BlockHeight(584_000)),
|
|
|
|
NetworkUpgrade::Heartwood => Some(BlockHeight(903_800)),
|
|
|
|
NetworkUpgrade::Canopy => Some(BlockHeight(1_028_500)),
|
2021-05-11 09:10:21 -07:00
|
|
|
NetworkUpgrade::Nu5 => None,
|
2020-09-23 09:53:48 -07:00
|
|
|
#[cfg(feature = "zfuture")]
|
2020-09-22 09:06:54 -07:00
|
|
|
NetworkUpgrade::ZFuture => None,
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
}
|
2020-09-17 10:55:39 -07:00
|
|
|
|
2020-10-20 16:09:31 -07:00
|
|
|
fn coin_type(&self) -> u32 {
|
|
|
|
constants::testnet::COIN_TYPE
|
|
|
|
}
|
|
|
|
|
2020-10-21 13:12:30 -07:00
|
|
|
fn hrp_sapling_extended_spending_key(&self) -> &str {
|
|
|
|
constants::testnet::HRP_SAPLING_EXTENDED_SPENDING_KEY
|
|
|
|
}
|
|
|
|
|
2020-09-17 10:55:39 -07:00
|
|
|
fn hrp_sapling_extended_full_viewing_key(&self) -> &str {
|
|
|
|
constants::testnet::HRP_SAPLING_EXTENDED_FULL_VIEWING_KEY
|
|
|
|
}
|
|
|
|
|
|
|
|
fn hrp_sapling_payment_address(&self) -> &str {
|
|
|
|
constants::testnet::HRP_SAPLING_PAYMENT_ADDRESS
|
|
|
|
}
|
|
|
|
|
|
|
|
fn b58_pubkey_address_prefix(&self) -> [u8; 2] {
|
|
|
|
constants::testnet::B58_PUBKEY_ADDRESS_PREFIX
|
|
|
|
}
|
|
|
|
|
|
|
|
fn b58_script_address_prefix(&self) -> [u8; 2] {
|
|
|
|
constants::testnet::B58_SCRIPT_ADDRESS_PREFIX
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-18 09:40:30 -07:00
|
|
|
#[derive(PartialEq, Copy, Clone, Debug)]
|
2020-08-05 13:27:40 -07:00
|
|
|
pub enum Network {
|
|
|
|
MainNetwork,
|
|
|
|
TestNetwork,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Parameters for Network {
|
|
|
|
fn activation_height(&self, nu: NetworkUpgrade) -> Option<BlockHeight> {
|
|
|
|
match self {
|
2020-09-17 10:55:39 -07:00
|
|
|
Network::MainNetwork => MAIN_NETWORK.activation_height(nu),
|
|
|
|
Network::TestNetwork => TEST_NETWORK.activation_height(nu),
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-20 16:09:31 -07:00
|
|
|
fn coin_type(&self) -> u32 {
|
|
|
|
match self {
|
|
|
|
Network::MainNetwork => MAIN_NETWORK.coin_type(),
|
|
|
|
Network::TestNetwork => TEST_NETWORK.coin_type(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 13:12:30 -07:00
|
|
|
fn hrp_sapling_extended_spending_key(&self) -> &str {
|
|
|
|
match self {
|
|
|
|
Network::MainNetwork => MAIN_NETWORK.hrp_sapling_extended_spending_key(),
|
|
|
|
Network::TestNetwork => TEST_NETWORK.hrp_sapling_extended_spending_key(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-08-05 13:27:40 -07:00
|
|
|
fn hrp_sapling_extended_full_viewing_key(&self) -> &str {
|
|
|
|
match self {
|
2020-09-17 10:55:39 -07:00
|
|
|
Network::MainNetwork => MAIN_NETWORK.hrp_sapling_extended_full_viewing_key(),
|
|
|
|
Network::TestNetwork => TEST_NETWORK.hrp_sapling_extended_full_viewing_key(),
|
2020-08-05 13:27:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn hrp_sapling_payment_address(&self) -> &str {
|
|
|
|
match self {
|
2020-09-17 10:55:39 -07:00
|
|
|
Network::MainNetwork => MAIN_NETWORK.hrp_sapling_payment_address(),
|
|
|
|
Network::TestNetwork => TEST_NETWORK.hrp_sapling_payment_address(),
|
2020-08-05 13:27:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn b58_pubkey_address_prefix(&self) -> [u8; 2] {
|
|
|
|
match self {
|
2020-09-17 10:55:39 -07:00
|
|
|
Network::MainNetwork => MAIN_NETWORK.b58_pubkey_address_prefix(),
|
|
|
|
Network::TestNetwork => TEST_NETWORK.b58_pubkey_address_prefix(),
|
2020-08-05 13:27:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn b58_script_address_prefix(&self) -> [u8; 2] {
|
|
|
|
match self {
|
2020-09-17 10:55:39 -07:00
|
|
|
Network::MainNetwork => MAIN_NETWORK.b58_script_address_prefix(),
|
|
|
|
Network::TestNetwork => TEST_NETWORK.b58_script_address_prefix(),
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// An event that occurs at a specified height on the Zcash chain, at which point the
|
|
|
|
/// consensus rules enforced by the network are altered.
|
|
|
|
///
|
|
|
|
/// See [ZIP 200](https://zips.z.cash/zip-0200) for more details.
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub enum NetworkUpgrade {
|
|
|
|
/// The [Overwinter] network upgrade.
|
|
|
|
///
|
|
|
|
/// [Overwinter]: https://z.cash/upgrade/overwinter/
|
|
|
|
Overwinter,
|
|
|
|
/// The [Sapling] network upgrade.
|
|
|
|
///
|
|
|
|
/// [Sapling]: https://z.cash/upgrade/sapling/
|
|
|
|
Sapling,
|
|
|
|
/// The [Blossom] network upgrade.
|
|
|
|
///
|
|
|
|
/// [Blossom]: https://z.cash/upgrade/blossom/
|
|
|
|
Blossom,
|
|
|
|
/// The [Heartwood] network upgrade.
|
|
|
|
///
|
|
|
|
/// [Heartwood]: https://z.cash/upgrade/heartwood/
|
|
|
|
Heartwood,
|
2020-06-04 00:44:15 -07:00
|
|
|
/// The [Canopy] network upgrade.
|
|
|
|
///
|
|
|
|
/// [Canopy]: https://z.cash/upgrade/canopy/
|
|
|
|
Canopy,
|
2021-05-11 09:10:21 -07:00
|
|
|
/// The [Nu5] network upgrade.
|
|
|
|
///
|
|
|
|
/// [Nu5]: https://z.cash/upgrade/nu5/
|
|
|
|
Nu5,
|
2021-03-04 09:41:08 -08:00
|
|
|
/// The ZFUTURE network upgrade.
|
2020-09-08 11:24:29 -07:00
|
|
|
///
|
|
|
|
/// This upgrade is expected never to activate on mainnet;
|
|
|
|
/// it is intended for use in integration testing of functionality
|
|
|
|
/// that is a candidate for integration in a future network upgrade.
|
2020-09-23 09:53:48 -07:00
|
|
|
#[cfg(feature = "zfuture")]
|
2020-09-22 09:06:54 -07:00
|
|
|
ZFuture,
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for NetworkUpgrade {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
NetworkUpgrade::Overwinter => write!(f, "Overwinter"),
|
|
|
|
NetworkUpgrade::Sapling => write!(f, "Sapling"),
|
|
|
|
NetworkUpgrade::Blossom => write!(f, "Blossom"),
|
|
|
|
NetworkUpgrade::Heartwood => write!(f, "Heartwood"),
|
2020-06-04 00:44:15 -07:00
|
|
|
NetworkUpgrade::Canopy => write!(f, "Canopy"),
|
2021-05-11 09:10:21 -07:00
|
|
|
NetworkUpgrade::Nu5 => write!(f, "Nu5"),
|
2020-09-23 09:53:48 -07:00
|
|
|
#[cfg(feature = "zfuture")]
|
2020-09-22 09:06:54 -07:00
|
|
|
NetworkUpgrade::ZFuture => write!(f, "ZFUTURE"),
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl NetworkUpgrade {
|
|
|
|
fn branch_id(self) -> BranchId {
|
|
|
|
match self {
|
|
|
|
NetworkUpgrade::Overwinter => BranchId::Overwinter,
|
|
|
|
NetworkUpgrade::Sapling => BranchId::Sapling,
|
|
|
|
NetworkUpgrade::Blossom => BranchId::Blossom,
|
|
|
|
NetworkUpgrade::Heartwood => BranchId::Heartwood,
|
2020-06-04 00:44:15 -07:00
|
|
|
NetworkUpgrade::Canopy => BranchId::Canopy,
|
2021-05-11 09:10:21 -07:00
|
|
|
NetworkUpgrade::Nu5 => BranchId::Nu5,
|
2020-09-23 09:53:48 -07:00
|
|
|
#[cfg(feature = "zfuture")]
|
2020-09-22 09:06:54 -07:00
|
|
|
NetworkUpgrade::ZFuture => BranchId::ZFuture,
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// The network upgrades on the Zcash chain in order of activation.
|
|
|
|
///
|
|
|
|
/// This order corresponds to the activation heights, but because Rust enums are
|
|
|
|
/// full-fledged algebraic data types, we need to define it manually.
|
|
|
|
const UPGRADES_IN_ORDER: &[NetworkUpgrade] = &[
|
|
|
|
NetworkUpgrade::Overwinter,
|
|
|
|
NetworkUpgrade::Sapling,
|
|
|
|
NetworkUpgrade::Blossom,
|
|
|
|
NetworkUpgrade::Heartwood,
|
2020-06-04 00:44:15 -07:00
|
|
|
NetworkUpgrade::Canopy,
|
2021-05-11 09:10:21 -07:00
|
|
|
NetworkUpgrade::Nu5,
|
2019-11-26 15:44:57 -08:00
|
|
|
];
|
|
|
|
|
2020-08-02 22:39:36 -07:00
|
|
|
pub const ZIP212_GRACE_PERIOD: u32 = 32256;
|
|
|
|
|
2019-11-25 07:41:14 -08:00
|
|
|
/// A globally-unique identifier for a set of consensus rules within the Zcash chain.
|
|
|
|
///
|
|
|
|
/// Each branch ID in this enum corresponds to one of the epochs between a pair of Zcash
|
|
|
|
/// network upgrades. For example, `BranchId::Overwinter` corresponds to the blocks
|
|
|
|
/// starting at Overwinter activation, and ending the block before Sapling activation.
|
|
|
|
///
|
|
|
|
/// The main use of the branch ID is in signature generation: transactions commit to a
|
|
|
|
/// specific branch ID by including it as part of [`signature_hash`]. This ensures
|
|
|
|
/// two-way replay protection for transactions across network upgrades.
|
|
|
|
///
|
|
|
|
/// See [ZIP 200](https://zips.z.cash/zip-0200) for more details.
|
|
|
|
///
|
2021-03-30 15:07:52 -07:00
|
|
|
/// [`signature_hash`]: crate::transaction::sighash::signature_hash
|
2019-11-26 15:44:57 -08:00
|
|
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
2019-11-25 07:41:14 -08:00
|
|
|
pub enum BranchId {
|
|
|
|
/// The consensus rules at the launch of Zcash.
|
|
|
|
Sprout,
|
2019-11-26 15:44:57 -08:00
|
|
|
/// The consensus rules deployed by [`NetworkUpgrade::Overwinter`].
|
2019-11-25 07:41:14 -08:00
|
|
|
Overwinter,
|
2019-11-26 15:44:57 -08:00
|
|
|
/// The consensus rules deployed by [`NetworkUpgrade::Sapling`].
|
2019-11-25 07:41:14 -08:00
|
|
|
Sapling,
|
2019-11-26 15:44:57 -08:00
|
|
|
/// The consensus rules deployed by [`NetworkUpgrade::Blossom`].
|
2019-11-25 07:41:14 -08:00
|
|
|
Blossom,
|
2019-11-26 15:44:57 -08:00
|
|
|
/// The consensus rules deployed by [`NetworkUpgrade::Heartwood`].
|
2019-11-25 07:41:14 -08:00
|
|
|
Heartwood,
|
2020-06-04 00:44:15 -07:00
|
|
|
/// The consensus rules deployed by [`NetworkUpgrade::Canopy`].
|
|
|
|
Canopy,
|
2021-05-11 09:10:21 -07:00
|
|
|
/// The consensus rules deployed by [`NetworkUpgrade::Nu5`].
|
|
|
|
Nu5,
|
2020-09-08 11:24:29 -07:00
|
|
|
/// Candidates for future consensus rules; this branch will never
|
|
|
|
/// activate on mainnet.
|
2020-09-23 09:53:48 -07:00
|
|
|
#[cfg(feature = "zfuture")]
|
2020-09-22 09:06:54 -07:00
|
|
|
ZFuture,
|
2019-11-25 07:41:14 -08:00
|
|
|
}
|
|
|
|
|
2019-11-27 05:12:28 -08:00
|
|
|
impl TryFrom<u32> for BranchId {
|
|
|
|
type Error = &'static str;
|
|
|
|
|
|
|
|
fn try_from(value: u32) -> Result<Self, Self::Error> {
|
|
|
|
match value {
|
|
|
|
0 => Ok(BranchId::Sprout),
|
|
|
|
0x5ba8_1b19 => Ok(BranchId::Overwinter),
|
|
|
|
0x76b8_09bb => Ok(BranchId::Sapling),
|
|
|
|
0x2bb4_0e60 => Ok(BranchId::Blossom),
|
|
|
|
0xf5b9_230b => Ok(BranchId::Heartwood),
|
2020-06-04 00:44:15 -07:00
|
|
|
0xe9ff_75a6 => Ok(BranchId::Canopy),
|
2021-05-11 09:10:21 -07:00
|
|
|
0xf919_a198 => Ok(BranchId::Nu5),
|
2020-09-23 09:53:48 -07:00
|
|
|
#[cfg(feature = "zfuture")]
|
2020-09-22 09:06:54 -07:00
|
|
|
0xffff_ffff => Ok(BranchId::ZFuture),
|
2019-11-27 05:12:28 -08:00
|
|
|
_ => Err("Unknown consensus branch ID"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-25 07:41:14 -08:00
|
|
|
impl From<BranchId> for u32 {
|
|
|
|
fn from(consensus_branch_id: BranchId) -> u32 {
|
|
|
|
match consensus_branch_id {
|
|
|
|
BranchId::Sprout => 0,
|
|
|
|
BranchId::Overwinter => 0x5ba8_1b19,
|
|
|
|
BranchId::Sapling => 0x76b8_09bb,
|
|
|
|
BranchId::Blossom => 0x2bb4_0e60,
|
|
|
|
BranchId::Heartwood => 0xf5b9_230b,
|
2020-06-04 00:44:15 -07:00
|
|
|
BranchId::Canopy => 0xe9ff_75a6,
|
2021-05-11 09:10:21 -07:00
|
|
|
BranchId::Nu5 => 0xf919_a198,
|
2020-09-23 09:53:48 -07:00
|
|
|
#[cfg(feature = "zfuture")]
|
2020-09-22 09:06:54 -07:00
|
|
|
BranchId::ZFuture => 0xffff_ffff,
|
2019-11-25 07:41:14 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-11-26 15:44:57 -08:00
|
|
|
|
|
|
|
impl BranchId {
|
|
|
|
/// Returns the branch ID corresponding to the consensus rule set that is active at
|
|
|
|
/// the given height.
|
|
|
|
///
|
|
|
|
/// This is the branch ID that should be used when creating transactions.
|
2020-08-05 13:27:40 -07:00
|
|
|
pub fn for_height<P: Parameters>(parameters: &P, height: BlockHeight) -> Self {
|
2019-11-26 15:44:57 -08:00
|
|
|
for nu in UPGRADES_IN_ORDER.iter().rev() {
|
2020-08-05 13:27:40 -07:00
|
|
|
if parameters.is_nu_active(*nu, height) {
|
2019-11-26 15:44:57 -08:00
|
|
|
return nu.branch_id();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Sprout rules apply before any network upgrade
|
|
|
|
BranchId::Sprout
|
|
|
|
}
|
2021-05-11 09:10:21 -07:00
|
|
|
|
|
|
|
/// Returns the range of heights for the consensus epoch associated with this branch id.
|
|
|
|
///
|
|
|
|
/// The resulting tuple implements the [`RangeBounds<BlockHeight>`] trait.
|
|
|
|
pub fn height_range<P: Parameters>(&self, params: &P) -> Option<impl RangeBounds<BlockHeight>> {
|
|
|
|
self.height_bounds(params).map(|(lower, upper)| {
|
|
|
|
(
|
|
|
|
Bound::Included(lower),
|
|
|
|
upper.map_or(Bound::Unbounded, Bound::Excluded),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Returns the range of heights for the consensus epoch associated with this branch id.
|
|
|
|
///
|
2021-05-27 15:33:46 -07:00
|
|
|
/// The return type of this value is slightly more precise than [`Self::height_range`]:
|
2021-05-31 10:08:45 -07:00
|
|
|
/// - `Some((x, Some(y)))` means that the consensus rules corresponding to this branch id
|
2021-05-27 15:33:46 -07:00
|
|
|
/// are in effect for the range `x..y`
|
2021-05-31 10:08:45 -07:00
|
|
|
/// - `Some((x, None))` means that the consensus rules corresponding to this branch id are
|
2021-05-27 15:33:46 -07:00
|
|
|
/// in effect for the range `x..`
|
|
|
|
/// - `None` means that the consensus rules corresponding to this branch id are never in effect.
|
2021-05-11 09:10:21 -07:00
|
|
|
pub fn height_bounds<P: Parameters>(
|
|
|
|
&self,
|
|
|
|
params: &P,
|
|
|
|
) -> Option<(BlockHeight, Option<BlockHeight>)> {
|
|
|
|
match self {
|
|
|
|
BranchId::Sprout => params
|
|
|
|
.activation_height(NetworkUpgrade::Overwinter)
|
|
|
|
.map(|upper| (BlockHeight(0), Some(upper))),
|
|
|
|
BranchId::Overwinter => params
|
|
|
|
.activation_height(NetworkUpgrade::Overwinter)
|
|
|
|
.map(|lower| (lower, params.activation_height(NetworkUpgrade::Sapling))),
|
|
|
|
BranchId::Sapling => params
|
|
|
|
.activation_height(NetworkUpgrade::Sapling)
|
|
|
|
.map(|lower| (lower, params.activation_height(NetworkUpgrade::Blossom))),
|
|
|
|
BranchId::Blossom => params
|
|
|
|
.activation_height(NetworkUpgrade::Blossom)
|
|
|
|
.map(|lower| (lower, params.activation_height(NetworkUpgrade::Heartwood))),
|
|
|
|
BranchId::Heartwood => params
|
|
|
|
.activation_height(NetworkUpgrade::Heartwood)
|
|
|
|
.map(|lower| (lower, params.activation_height(NetworkUpgrade::Canopy))),
|
|
|
|
BranchId::Canopy => params
|
|
|
|
.activation_height(NetworkUpgrade::Canopy)
|
|
|
|
.map(|lower| (lower, params.activation_height(NetworkUpgrade::Nu5))),
|
|
|
|
BranchId::Nu5 => params.activation_height(NetworkUpgrade::Nu5).map(|lower| {
|
|
|
|
#[cfg(feature = "zfuture")]
|
|
|
|
let upper = params.activation_height(NetworkUpgrade::ZFuture);
|
|
|
|
#[cfg(not(feature = "zfuture"))]
|
|
|
|
let upper = None;
|
|
|
|
(lower, upper)
|
|
|
|
}),
|
|
|
|
#[cfg(feature = "zfuture")]
|
|
|
|
BranchId::ZFuture => params
|
|
|
|
.activation_height(NetworkUpgrade::ZFuture)
|
|
|
|
.map(|lower| (lower, None)),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(any(test, feature = "test-dependencies"))]
|
|
|
|
pub mod testing {
|
|
|
|
use proptest::sample::select;
|
|
|
|
use proptest::strategy::{Just, Strategy};
|
|
|
|
|
|
|
|
use super::{BlockHeight, BranchId, Parameters};
|
|
|
|
|
|
|
|
pub fn arb_branch_id() -> impl Strategy<Value = BranchId> {
|
|
|
|
select(vec![
|
|
|
|
BranchId::Sprout,
|
|
|
|
BranchId::Overwinter,
|
|
|
|
BranchId::Sapling,
|
|
|
|
BranchId::Blossom,
|
|
|
|
BranchId::Heartwood,
|
|
|
|
BranchId::Canopy,
|
|
|
|
BranchId::Nu5,
|
|
|
|
#[cfg(feature = "zfuture")]
|
|
|
|
BranchId::ZFuture,
|
|
|
|
])
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn arb_height<P: Parameters>(
|
|
|
|
branch_id: BranchId,
|
|
|
|
params: &P,
|
|
|
|
) -> impl Strategy<Value = Option<BlockHeight>> {
|
|
|
|
branch_id
|
|
|
|
.height_bounds(params)
|
|
|
|
.map_or(Strategy::boxed(Just(None)), |(lower, upper)| {
|
|
|
|
Strategy::boxed(
|
|
|
|
(lower.0..upper.map_or(std::u32::MAX, |u| u.0))
|
|
|
|
.prop_map(|h| Some(BlockHeight(h))),
|
|
|
|
)
|
|
|
|
})
|
|
|
|
}
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2019-11-27 05:12:28 -08:00
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
2020-09-17 10:55:39 -07:00
|
|
|
use super::{
|
|
|
|
BlockHeight, BranchId, NetworkUpgrade, Parameters, MAIN_NETWORK, UPGRADES_IN_ORDER,
|
|
|
|
};
|
2020-08-05 21:30:48 -07:00
|
|
|
|
2019-11-26 15:44:57 -08:00
|
|
|
#[test]
|
|
|
|
fn nu_ordering() {
|
|
|
|
for i in 1..UPGRADES_IN_ORDER.len() {
|
|
|
|
let nu_a = UPGRADES_IN_ORDER[i - 1];
|
|
|
|
let nu_b = UPGRADES_IN_ORDER[i];
|
|
|
|
match (
|
2020-09-17 10:55:39 -07:00
|
|
|
MAIN_NETWORK.activation_height(nu_a),
|
|
|
|
MAIN_NETWORK.activation_height(nu_b),
|
2019-11-26 15:44:57 -08:00
|
|
|
) {
|
2021-05-11 09:10:21 -07:00
|
|
|
(Some(a), Some(b)) if a < b => (),
|
|
|
|
(Some(_), None) => (),
|
|
|
|
(None, None) => (),
|
2019-11-26 15:44:57 -08:00
|
|
|
_ => panic!(
|
|
|
|
"{} should not be before {} in UPGRADES_IN_ORDER",
|
|
|
|
nu_a, nu_b
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn nu_is_active() {
|
2020-09-17 10:55:39 -07:00
|
|
|
assert!(!MAIN_NETWORK.is_nu_active(NetworkUpgrade::Overwinter, BlockHeight(0)));
|
|
|
|
assert!(!MAIN_NETWORK.is_nu_active(NetworkUpgrade::Overwinter, BlockHeight(347_499)));
|
|
|
|
assert!(MAIN_NETWORK.is_nu_active(NetworkUpgrade::Overwinter, BlockHeight(347_500)));
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
|
2019-11-27 05:12:28 -08:00
|
|
|
#[test]
|
|
|
|
fn branch_id_from_u32() {
|
|
|
|
assert_eq!(BranchId::try_from(0), Ok(BranchId::Sprout));
|
|
|
|
assert!(BranchId::try_from(1).is_err());
|
|
|
|
}
|
|
|
|
|
2019-11-26 15:44:57 -08:00
|
|
|
#[test]
|
|
|
|
fn branch_id_for_height() {
|
|
|
|
assert_eq!(
|
2020-09-17 10:55:39 -07:00
|
|
|
BranchId::for_height(&MAIN_NETWORK, BlockHeight(0)),
|
2020-08-05 13:08:58 -07:00
|
|
|
BranchId::Sprout,
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2020-09-17 10:55:39 -07:00
|
|
|
BranchId::for_height(&MAIN_NETWORK, BlockHeight(419_199)),
|
2019-11-26 15:44:57 -08:00
|
|
|
BranchId::Overwinter,
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2020-09-17 10:55:39 -07:00
|
|
|
BranchId::for_height(&MAIN_NETWORK, BlockHeight(419_200)),
|
2019-11-26 15:44:57 -08:00
|
|
|
BranchId::Sapling,
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2020-09-17 10:55:39 -07:00
|
|
|
BranchId::for_height(&MAIN_NETWORK, BlockHeight(903_000)),
|
2020-06-03 17:24:11 -07:00
|
|
|
BranchId::Heartwood,
|
2019-11-26 15:44:57 -08:00
|
|
|
);
|
2020-07-29 21:50:21 -07:00
|
|
|
assert_eq!(
|
2020-09-17 10:55:39 -07:00
|
|
|
BranchId::for_height(&MAIN_NETWORK, BlockHeight(1_046_400)),
|
2020-07-29 21:50:21 -07:00
|
|
|
BranchId::Canopy,
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2020-09-17 10:55:39 -07:00
|
|
|
BranchId::for_height(&MAIN_NETWORK, BlockHeight(5_000_000)),
|
2020-07-29 21:50:21 -07:00
|
|
|
BranchId::Canopy,
|
|
|
|
);
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
}
|