2019-11-25 07:41:14 -08:00
|
|
|
//! Consensus parameters.
|
|
|
|
|
2019-11-27 05:12:28 -08:00
|
|
|
use std::convert::TryFrom;
|
2019-11-26 15:44:57 -08:00
|
|
|
use std::fmt;
|
|
|
|
|
|
|
|
/// Zcash consensus parameters.
|
|
|
|
pub trait Parameters {
|
2020-07-29 22:13:59 -07:00
|
|
|
fn activation_height(&self, nu: NetworkUpgrade) -> Option<u32>;
|
2019-11-26 15:44:57 -08:00
|
|
|
|
2020-07-29 22:13:59 -07:00
|
|
|
fn is_nu_active(&self, nu: NetworkUpgrade, height: u32) -> bool {
|
|
|
|
match self.activation_height(nu) {
|
2019-11-26 15:44:57 -08:00
|
|
|
Some(h) if h <= height => true,
|
|
|
|
_ => false,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Marker struct for the production network.
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub struct MainNetwork;
|
|
|
|
|
|
|
|
impl Parameters for MainNetwork {
|
2020-07-29 22:13:59 -07:00
|
|
|
fn activation_height(&self, nu: NetworkUpgrade) -> Option<u32> {
|
2019-11-26 15:44:57 -08:00
|
|
|
match nu {
|
|
|
|
NetworkUpgrade::Overwinter => Some(347_500),
|
|
|
|
NetworkUpgrade::Sapling => Some(419_200),
|
|
|
|
NetworkUpgrade::Blossom => Some(653_600),
|
2020-06-03 17:24:11 -07:00
|
|
|
NetworkUpgrade::Heartwood => Some(903_000),
|
2020-07-29 21:50:21 -07:00
|
|
|
NetworkUpgrade::Canopy => Some(1_046_400),
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// Marker struct for the test network.
|
|
|
|
#[derive(Clone, Copy, Debug)]
|
|
|
|
pub struct TestNetwork;
|
|
|
|
|
|
|
|
impl Parameters for TestNetwork {
|
2020-07-29 22:13:59 -07:00
|
|
|
fn activation_height(&self, nu: NetworkUpgrade) -> Option<u32> {
|
2019-11-26 15:44:57 -08:00
|
|
|
match nu {
|
|
|
|
NetworkUpgrade::Overwinter => Some(207_500),
|
|
|
|
NetworkUpgrade::Sapling => Some(280_000),
|
|
|
|
NetworkUpgrade::Blossom => Some(584_000),
|
2020-06-03 17:24:11 -07:00
|
|
|
NetworkUpgrade::Heartwood => Some(903_800),
|
2020-07-29 21:50:21 -07:00
|
|
|
NetworkUpgrade::Canopy => Some(1_028_500),
|
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,
|
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"),
|
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,
|
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,
|
2019-11-26 15:44:57 -08:00
|
|
|
];
|
|
|
|
|
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.
|
|
|
|
///
|
|
|
|
/// [`signature_hash`]: crate::transaction::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,
|
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),
|
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,
|
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-07-29 22:13:59 -07:00
|
|
|
pub fn for_height<C: Parameters>(parameters: C, height: u32) -> Self {
|
2019-11-26 15:44:57 -08:00
|
|
|
for nu in UPGRADES_IN_ORDER.iter().rev() {
|
2020-07-29 22:13:59 -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
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
2019-11-27 05:12:28 -08:00
|
|
|
use std::convert::TryFrom;
|
|
|
|
|
|
|
|
use super::{BranchId, MainNetwork, NetworkUpgrade, Parameters, UPGRADES_IN_ORDER};
|
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 (
|
|
|
|
MainNetwork::activation_height(nu_a),
|
|
|
|
MainNetwork::activation_height(nu_b),
|
|
|
|
) {
|
|
|
|
(Some(a), Some(b)) if a < b => (),
|
|
|
|
(Some(_), None) => (),
|
|
|
|
(None, None) => (),
|
|
|
|
_ => panic!(
|
|
|
|
"{} should not be before {} in UPGRADES_IN_ORDER",
|
|
|
|
nu_a, nu_b
|
|
|
|
),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn nu_is_active() {
|
|
|
|
assert!(!MainNetwork::is_nu_active(NetworkUpgrade::Overwinter, 0));
|
|
|
|
assert!(!MainNetwork::is_nu_active(
|
|
|
|
NetworkUpgrade::Overwinter,
|
|
|
|
347_499
|
|
|
|
));
|
|
|
|
assert!(MainNetwork::is_nu_active(
|
|
|
|
NetworkUpgrade::Overwinter,
|
|
|
|
347_500
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
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!(BranchId::for_height::<MainNetwork>(0), BranchId::Sprout,);
|
|
|
|
assert_eq!(
|
|
|
|
BranchId::for_height::<MainNetwork>(419_199),
|
|
|
|
BranchId::Overwinter,
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
BranchId::for_height::<MainNetwork>(419_200),
|
|
|
|
BranchId::Sapling,
|
|
|
|
);
|
|
|
|
assert_eq!(
|
2020-07-29 21:50:21 -07:00
|
|
|
BranchId::for_height::<MainNetwork>(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!(
|
|
|
|
BranchId::for_height::<MainNetwork>(1_046_400),
|
|
|
|
BranchId::Canopy,
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
BranchId::for_height::<MainNetwork>(5_000_000),
|
|
|
|
BranchId::Canopy,
|
|
|
|
);
|
2019-11-26 15:44:57 -08:00
|
|
|
}
|
|
|
|
}
|