From 993532b6040a67d2f5d990d1b6964205076e1746 Mon Sep 17 00:00:00 2001 From: teor Date: Mon, 27 Jul 2020 17:54:55 +1000 Subject: [PATCH] feature: Add a "Genesis" network upgrade We can use this network upgrade to implement different consensus rules and chain context handling for genesis blocks. Part of the chain state design in #682. --- .../src/parameters/network_upgrade.rs | 24 +++++++++++------ zebra-consensus/src/parameters/tests.rs | 26 ++++++++++++------- zebra-network/src/protocol/external/types.rs | 2 +- 3 files changed, 34 insertions(+), 18 deletions(-) diff --git a/zebra-consensus/src/parameters/network_upgrade.rs b/zebra-consensus/src/parameters/network_upgrade.rs index 76ea0627d..6c5f9ae59 100644 --- a/zebra-consensus/src/parameters/network_upgrade.rs +++ b/zebra-consensus/src/parameters/network_upgrade.rs @@ -8,12 +8,18 @@ use std::ops::Bound::*; use zebra_chain::types::BlockHeight; use zebra_chain::{Network, Network::*}; -/// A Zcash network protocol upgrade. -// -// TODO: are new network upgrades a breaking change, or should we make this -// enum non-exhaustive? +/// A Zcash network upgrade. +/// +/// Network upgrades can change the Zcash network protocol or consensus rules in +/// incompatible ways. #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] pub enum NetworkUpgrade { + /// The Zcash protocol for a Genesis block. + /// + /// Zcash genesis blocks use a different set of consensus rules from + /// other BeforeOverwinter blocks, so we treat them like a separate network + /// upgrade. + Genesis, /// The Zcash protocol before the Overwinter upgrade. /// /// We avoid using `Sprout`, because the specification says that Sprout @@ -36,7 +42,8 @@ pub enum NetworkUpgrade { /// This is actually a bijective map, but it is const, so we use a vector, and /// do the uniqueness check in the unit tests. pub(crate) const MAINNET_ACTIVATION_HEIGHTS: &[(BlockHeight, NetworkUpgrade)] = &[ - (BlockHeight(0), BeforeOverwinter), + (BlockHeight(0), Genesis), + (BlockHeight(1), BeforeOverwinter), (BlockHeight(347_500), Overwinter), (BlockHeight(419_200), Sapling), (BlockHeight(653_600), Blossom), @@ -49,7 +56,8 @@ pub(crate) const MAINNET_ACTIVATION_HEIGHTS: &[(BlockHeight, NetworkUpgrade)] = /// This is actually a bijective map, but it is const, so we use a vector, and /// do the uniqueness check in the unit tests. pub(crate) const TESTNET_ACTIVATION_HEIGHTS: &[(BlockHeight, NetworkUpgrade)] = &[ - (BlockHeight(0), BeforeOverwinter), + (BlockHeight(0), Genesis), + (BlockHeight(1), BeforeOverwinter), (BlockHeight(207_500), Overwinter), (BlockHeight(280_000), Sapling), (BlockHeight(584_000), Blossom), @@ -68,8 +76,8 @@ pub struct ConsensusBranchId(u32); /// Branch ids are the same for mainnet and testnet. If there is a testnet /// rollback after a bug, the branch id changes. /// -/// Branch ids were introduced in the Overwinter upgrade, so there is no -/// BeforeOverwinter branch id. +/// Branch ids were introduced in the Overwinter upgrade, so there are no +/// Genesis or BeforeOverwinter branch ids. /// /// This is actually a bijective map, but it is const, so we use a vector, and /// do the uniqueness check in the unit tests. diff --git a/zebra-consensus/src/parameters/tests.rs b/zebra-consensus/src/parameters/tests.rs index 06eeb3c95..b2e0b7d47 100644 --- a/zebra-consensus/src/parameters/tests.rs +++ b/zebra-consensus/src/parameters/tests.rs @@ -39,21 +39,32 @@ fn activation_extremes_testnet() { /// Test the activation_list, activation_height, current, and next functions /// for `network` with extreme values. fn activation_extremes(network: Network) { - // The first two upgrades are BeforeOverwinter and Overwinter + // The first three upgrades are Genesis, BeforeOverwinter, and Overwinter assert_eq!( NetworkUpgrade::activation_list(network).get(&BlockHeight(0)), + Some(&Genesis) + ); + assert_eq!(Genesis.activation_height(network), Some(BlockHeight(0))); + assert_eq!(NetworkUpgrade::current(network, BlockHeight(0)), Genesis); + assert_eq!( + NetworkUpgrade::next(network, BlockHeight(0)), + Some(BeforeOverwinter) + ); + + assert_eq!( + NetworkUpgrade::activation_list(network).get(&BlockHeight(1)), Some(&BeforeOverwinter) ); assert_eq!( BeforeOverwinter.activation_height(network), - Some(BlockHeight(0)) + Some(BlockHeight(1)) ); assert_eq!( - NetworkUpgrade::current(network, BlockHeight(0)), + NetworkUpgrade::current(network, BlockHeight(1)), BeforeOverwinter ); assert_eq!( - NetworkUpgrade::next(network, BlockHeight(0)), + NetworkUpgrade::next(network, BlockHeight(1)), Some(Overwinter) ); @@ -61,12 +72,9 @@ fn activation_extremes(network: Network) { // (even if we suspect that won't be true) assert_ne!( NetworkUpgrade::activation_list(network).get(&BlockHeight::MAX), - Some(&BeforeOverwinter) - ); - assert_ne!( - NetworkUpgrade::current(network, BlockHeight::MAX), - BeforeOverwinter + Some(&Genesis) ); + assert_ne!(NetworkUpgrade::current(network, BlockHeight::MAX), Genesis); assert_eq!(NetworkUpgrade::next(network, BlockHeight::MAX), None); } diff --git a/zebra-network/src/protocol/external/types.rs b/zebra-network/src/protocol/external/types.rs index 2cbd28d6f..06b5380c6 100644 --- a/zebra-network/src/protocol/external/types.rs +++ b/zebra-network/src/protocol/external/types.rs @@ -43,7 +43,7 @@ impl Version { // TODO: Should we reject earlier protocol versions during our initial // sync? zcashd accepts 170_002 or later during its initial sync. Version(match (network, network_upgrade) { - (_, BeforeOverwinter) => 170_002, + (_, Genesis) | (_, BeforeOverwinter) => 170_002, (Testnet, Overwinter) => 170_003, (Mainnet, Overwinter) => 170_005, (_, Sapling) => 170_007,