From b563b2a1c19dab8ce59699f26b9cc929951500f7 Mon Sep 17 00:00:00 2001 From: Janito Vaqueiro Ferreira Filho Date: Wed, 16 Mar 2022 21:37:50 -0300 Subject: [PATCH] feat(consensus): Validate ZIP-212 grace period blocks using checkpoints (#3889) * Test if mandatory checkpoint is after grace period Check that the mandatory checkpoint height is after the ZIP-212 grace period for both mainnet and testnet, because Zebra is currently unable to fully validate the blocks during that grace period. * Update mandatory checkpoint height Require it to be after the ZIP-212 grace period so that the blocks during the grace period are validated by the checkpoints because Zebra can't currently fully validate blocks during that period. --- zebra-chain/src/parameters/network.rs | 51 +++++++++++++++++-- zebra-chain/src/parameters/network/tests.rs | 1 + .../src/parameters/network/tests/prop.rs | 26 ++++++++++ 3 files changed, 75 insertions(+), 3 deletions(-) create mode 100644 zebra-chain/src/parameters/network/tests.rs create mode 100644 zebra-chain/src/parameters/network/tests/prop.rs diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index ab0048722..4d24ddf07 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -5,6 +5,45 @@ use crate::{block::Height, parameters::NetworkUpgrade::Canopy}; #[cfg(any(test, feature = "proptest-impl"))] use proptest_derive::Arbitrary; +#[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].) +/// +/// https://zips.z.cash/protocol/protocol.pdf#txnencodingandconsensus +/// +/// 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. +/// +/// https://zips.z.cash/zip-0212#changes-to-the-process-of-receiving-sapling-or-orchard-notes +/// +/// 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. +const ZIP_212_GRACE_PERIOD_DURATION: i32 = 32_256; + /// An enum describing the possible network choices. #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] #[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))] @@ -51,10 +90,16 @@ impl Network { /// 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 { - // Currently this is the Canopy activation height for both networks. - Canopy + // Currently this is after the ZIP-212 grace period. + // + // See the `ZIP_212_GRACE_PERIOD_DOCUMENTATION` for more information. + + let canopy_activation = Canopy .activation_height(*self) - .expect("Canopy activation height must be present for both networks") + .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") } } diff --git a/zebra-chain/src/parameters/network/tests.rs b/zebra-chain/src/parameters/network/tests.rs new file mode 100644 index 000000000..2bf82ef4e --- /dev/null +++ b/zebra-chain/src/parameters/network/tests.rs @@ -0,0 +1 @@ +mod prop; diff --git a/zebra-chain/src/parameters/network/tests/prop.rs b/zebra-chain/src/parameters/network/tests/prop.rs new file mode 100644 index 000000000..56c966533 --- /dev/null +++ b/zebra-chain/src/parameters/network/tests/prop.rs @@ -0,0 +1,26 @@ +use proptest::prelude::*; + +use super::super::{Network, ZIP_212_GRACE_PERIOD_DURATION}; +use crate::parameters::NetworkUpgrade; + +proptest! { + /// Check that the mandatory checkpoint is after the ZIP-212 grace period. + /// + /// This is necessary because Zebra can't fully validate the blocks during the grace period due + /// to a limitation of `librustzcash`. + /// + /// See [`ZIP_212_GRACE_PERIOD_DURATION`] for more information. + #[test] + fn mandatory_checkpoint_is_after_zip212_grace_period(network in any::()) { + zebra_test::init(); + + let canopy_activation = NetworkUpgrade::Canopy + .activation_height(network) + .expect("Canopy activation height is set"); + + let grace_period_end_height = (canopy_activation + ZIP_212_GRACE_PERIOD_DURATION) + .expect("ZIP-212 grace period ends in a valid block height"); + + assert!(network.mandatory_checkpoint_height() >= grace_period_end_height); + } +}