From 544d182d259c150050376e080df5b6f03bd829e0 Mon Sep 17 00:00:00 2001 From: Alfredo Garcia Date: Thu, 17 Jun 2021 21:05:28 -0300 Subject: [PATCH] Add and use a function for mandatory checkpoint (#2314) * add `mandatory_checkpoint_height()` function * use mandatory checkpoint instead of canopy in acceptance tests --- .../regenerate-stateful-test-disks.yml | 4 +- .github/workflows/test.yml | 2 +- zebra-chain/src/parameters/network.rs | 14 +++++ zebra-consensus/src/chain.rs | 4 +- zebra-consensus/src/checkpoint/list/tests.rs | 23 ++++----- .../src/service/non_finalized_state.rs | 6 +-- zebrad/Cargo.toml | 8 +-- zebrad/tests/acceptance.rs | 51 +++++++++---------- 8 files changed, 60 insertions(+), 52 deletions(-) diff --git a/.github/workflows/regenerate-stateful-test-disks.yml b/.github/workflows/regenerate-stateful-test-disks.yml index f33b4aec5..e584ed01a 100644 --- a/.github/workflows/regenerate-stateful-test-disks.yml +++ b/.github/workflows/regenerate-stateful-test-disks.yml @@ -65,8 +65,8 @@ jobs: "git clone -b $BRANCH_NAME https://github.com/ZcashFoundation/zebra.git; cd zebra/; docker build --build-arg SHORT_SHA=$SHORT_SHA -f docker/Dockerfile.test -t zebrad-test .; - docker run -i --mount type=bind,source=/mnt/disks/gce-containers-mounts/gce-persistent-disks/zebrad-cache-$SHORT_SHA-mainnet-1046400,target=/zebrad-cache zebrad-test:latest cargo test --verbose --features test_sync_past_canopy_mainnet --manifest-path zebrad/Cargo.toml sync_past_canopy_mainnet; - docker run -i --mount type=bind,source=/mnt/disks/gce-containers-mounts/gce-persistent-disks/zebrad-cache-$SHORT_SHA-testnet-1028500,target=/zebrad-cache zebrad-test:latest cargo test --verbose --features test_sync_past_canopy_testnet --manifest-path zebrad/Cargo.toml sync_past_canopy_testnet; + docker run -i --mount type=bind,source=/mnt/disks/gce-containers-mounts/gce-persistent-disks/zebrad-cache-$SHORT_SHA-mainnet-1046400,target=/zebrad-cache zebrad-test:latest cargo test --verbose --features test_sync_past_mandatory_checkpoint_mainnet --manifest-path zebrad/Cargo.toml sync_past_canopy_mainnet; + docker run -i --mount type=bind,source=/mnt/disks/gce-containers-mounts/gce-persistent-disks/zebrad-cache-$SHORT_SHA-testnet-1028500,target=/zebrad-cache zebrad-test:latest cargo test --verbose --features test_sync_past_mandatory_checkpoint_testnet --manifest-path zebrad/Cargo.toml sync_past_canopy_testnet; " # Clean up - name: Delete test instance diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5e1209f0f..4ab40099e 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -69,7 +69,7 @@ jobs: cd zebra/; docker build --build-arg SHORT_SHA=$SHORT_SHA -f docker/Dockerfile.test -t zebrad-test .; docker run -i zebrad-test cargo test --workspace --no-fail-fast -- -Zunstable-options --include-ignored; - docker run -i --mount type=bind,source=/mnt/disks/gce-containers-mounts/gce-persistent-disks/zebrad-cache-$SHORT_SHA-mainnet-1046400,target=/zebrad-cache zebrad-test:latest cargo test --verbose --features test_sync_past_canopy_mainnet --manifest-path zebrad/Cargo.toml sync_past_canopy_mainnet; + docker run -i --mount type=bind,source=/mnt/disks/gce-containers-mounts/gce-persistent-disks/zebrad-cache-$SHORT_SHA-mainnet-1046400,target=/zebrad-cache zebrad-test:latest cargo test --verbose --features test_sync_past_mandatory_checkpoint_mainnet --manifest-path zebrad/Cargo.toml sync_past_canopy_mainnet; " # Clean up - name: Delete test instance diff --git a/zebra-chain/src/parameters/network.rs b/zebra-chain/src/parameters/network.rs index fcb4be9d6..ab0048722 100644 --- a/zebra-chain/src/parameters/network.rs +++ b/zebra-chain/src/parameters/network.rs @@ -1,5 +1,7 @@ use std::{convert::From, fmt}; +use crate::{block::Height, parameters::NetworkUpgrade::Canopy}; + #[cfg(any(test, feature = "proptest-impl"))] use proptest_derive::Arbitrary; @@ -42,6 +44,18 @@ impl Network { Network::Testnet => 18233, } } + + /// 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 { + // Currently this is the Canopy activation height for both networks. + Canopy + .activation_height(*self) + .expect("Canopy activation height must be present for both networks") + } } impl Default for Network { diff --git a/zebra-consensus/src/chain.rs b/zebra-consensus/src/chain.rs index e212a1ac4..e0b763568 100644 --- a/zebra-consensus/src/chain.rs +++ b/zebra-consensus/src/chain.rs @@ -20,7 +20,7 @@ use tracing::instrument; use zebra_chain::{ block::{self, Block}, - parameters::{Network, NetworkUpgrade::Canopy}, + parameters::Network, }; use zebra_state as zs; @@ -147,7 +147,7 @@ where let max_checkpoint_height = if config.checkpoint_sync { list.max_height() } else { - list.min_height_in_range(Canopy.activation_height(network).unwrap()..) + list.min_height_in_range(network.mandatory_checkpoint_height()..) .expect("hardcoded checkpoint list extends past canopy activation") }; diff --git a/zebra-consensus/src/checkpoint/list/tests.rs b/zebra-consensus/src/checkpoint/list/tests.rs index 8116a3763..52b8c4d5d 100644 --- a/zebra-consensus/src/checkpoint/list/tests.rs +++ b/zebra-consensus/src/checkpoint/list/tests.rs @@ -4,7 +4,7 @@ use super::*; use std::sync::Arc; -use zebra_chain::parameters::{Network, Network::*, NetworkUpgrade::*}; +use zebra_chain::parameters::{Network, Network::*}; use zebra_chain::{ block::{self, Block}, serialization::ZcashDeserialize, @@ -241,29 +241,26 @@ fn checkpoint_list_load_hard_coded() -> Result<(), BoxError> { } #[test] -fn checkpoint_list_hard_coded_canopy_mainnet() -> Result<(), BoxError> { - checkpoint_list_hard_coded_canopy(Mainnet) +fn checkpoint_list_hard_coded_mandatory_mainnet() -> Result<(), BoxError> { + checkpoint_list_hard_coded_mandatory(Mainnet) } #[test] -fn checkpoint_list_hard_coded_canopy_testnet() -> Result<(), BoxError> { - checkpoint_list_hard_coded_canopy(Testnet) +fn checkpoint_list_hard_coded_mandatory_testnet() -> Result<(), BoxError> { + checkpoint_list_hard_coded_mandatory(Testnet) } -/// Check that the hard-coded lists cover the Canopy network upgrade, and the -/// Canopy activation block -fn checkpoint_list_hard_coded_canopy(network: Network) -> Result<(), BoxError> { +/// Check that the hard-coded lists cover the mandatory checkpoint +fn checkpoint_list_hard_coded_mandatory(network: Network) -> Result<(), BoxError> { zebra_test::init(); - let canopy_activation = Canopy - .activation_height(network) - .expect("Unexpected network upgrade info: Canopy must have an activation height"); + let mandatory_checkpoint = network.mandatory_checkpoint_height(); let list = CheckpointList::new(network); assert!( - list.max_height() >= canopy_activation, - "Pre-Canopy blocks and the Canopy activation block must be verified by checkpoints" + list.max_height() >= mandatory_checkpoint, + "Mandatory checkpoint block must be verified by checkpoints" ); Ok(()) diff --git a/zebra-state/src/service/non_finalized_state.rs b/zebra-state/src/service/non_finalized_state.rs index 0de263917..4aa95a8b0 100644 --- a/zebra-state/src/service/non_finalized_state.rs +++ b/zebra-state/src/service/non_finalized_state.rs @@ -16,7 +16,7 @@ use std::{collections::BTreeSet, mem, ops::Deref, sync::Arc}; use zebra_chain::{ block::{self, Block}, - parameters::{Network, NetworkUpgrade::Canopy}, + parameters::Network, transaction::{self, Transaction}, transparent, }; @@ -80,8 +80,8 @@ impl NonFinalizedState { let parent_hash = prepared.block.header.previous_block_hash; let (height, hash) = (prepared.height, prepared.hash); - let canopy_activation_height = Canopy.activation_height(self.network).unwrap(); - if height <= canopy_activation_height { + let mandatory_checkpoint = self.network.mandatory_checkpoint_height(); + if height <= mandatory_checkpoint { panic!( "invalid non-finalized block height: the canopy checkpoint is mandatory, pre-canopy blocks, and the canopy activation block, must be committed to the state as finalized blocks" ); diff --git a/zebrad/Cargo.toml b/zebrad/Cargo.toml index 5e4dd21f3..08320102c 100644 --- a/zebrad/Cargo.toml +++ b/zebrad/Cargo.toml @@ -60,7 +60,7 @@ zebra-test = { path = "../zebra-test" } [features] enable-sentry = [] -test_sync_to_canopy_mainnet = [] -test_sync_to_canopy_testnet = [] -test_sync_past_canopy_mainnet = [] -test_sync_past_canopy_testnet = [] +test_sync_to_mandatory_checkpoint_mainnet = [] +test_sync_to_mandatory_checkpoint_testnet = [] +test_sync_past_mandatory_checkpoint_mainnet = [] +test_sync_past_mandatory_checkpoint_testnet = [] diff --git a/zebrad/tests/acceptance.rs b/zebrad/tests/acceptance.rs index d928be98c..80fc554c8 100644 --- a/zebrad/tests/acceptance.rs +++ b/zebrad/tests/acceptance.rs @@ -28,10 +28,7 @@ use std::{collections::HashSet, convert::TryInto, env, path::Path, path::PathBuf use zebra_chain::{ block::Height, - parameters::{ - Network::{self, *}, - NetworkUpgrade, - }, + parameters::Network::{self, *}, }; use zebra_network::constants::PORT_IN_USE_ERROR; use zebra_state::constants::LOCK_FILE_ERROR; @@ -835,7 +832,7 @@ fn sync_until( Ok(child.dir) } -fn cached_canopy_test_config() -> Result { +fn cached_mandatory_checkpoint_test_config() -> Result { let mut config = persistent_test_config()?; config.consensus.checkpoint_sync = true; config.state.cache_dir = "/zebrad-cache".into(); @@ -848,7 +845,7 @@ fn create_cached_database_height(network: Network, height: Height) -> Result<()> let timeout = Duration::from_secs(60 * 60 * 8); // Use a persistent state, so we can handle large syncs - let mut config = cached_canopy_test_config()?; + let mut config = cached_mandatory_checkpoint_test_config()?; // TODO: add convenience methods? config.network.network = network; config.state.debug_stop_at_height = Some(height.0); @@ -869,12 +866,12 @@ fn create_cached_database_height(network: Network, height: Height) -> Result<()> } fn create_cached_database(network: Network) -> Result<()> { - let height = NetworkUpgrade::Canopy.activation_height(network).unwrap(); + let height = network.mandatory_checkpoint_height(); create_cached_database_height(network, height) } -fn sync_past_canopy(network: Network) -> Result<()> { - let height = NetworkUpgrade::Canopy.activation_height(network).unwrap() + 1200; +fn sync_past_mandatory_checkpoint(network: Network) -> Result<()> { + let height = network.mandatory_checkpoint_height() + 1200; create_cached_database_height(network, height.unwrap()) } @@ -885,48 +882,48 @@ fn sync_past_canopy(network: Network) -> Result<()> { // drives populated by the first two tests, snapshot those drives, and then use // those to more quickly run the second two tests. -/// Sync up to the canopy activation height on mainnet and stop. +/// Sync up to the mandatory checkpoint height on mainnet and stop. #[allow(dead_code)] -#[cfg_attr(feature = "test_sync_to_canopy_mainnet", test)] -fn sync_to_canopy_mainnet() { +#[cfg_attr(feature = "test_sync_to_mandatory_checkpoint_mainnet", test)] +fn sync_to_mandatory_checkpoint_mainnet() { zebra_test::init(); let network = Mainnet; create_cached_database(network).unwrap(); } -/// Sync to the canopy activation height testnet and stop. +/// Sync to the mandatory checkpoint height testnet and stop. #[allow(dead_code)] -#[cfg_attr(feature = "test_sync_to_canopy_testnet", test)] -fn sync_to_canopy_testnet() { +#[cfg_attr(feature = "test_sync_to_mandatory_checkpoint_testnet", test)] +fn sync_to_mandatory_checkpoint_testnet() { zebra_test::init(); let network = Testnet; create_cached_database(network).unwrap(); } -/// Test syncing 1200 blocks (3 checkpoints) past the last checkpoint on mainnet. +/// Test syncing 1200 blocks (3 checkpoints) past the mandatory checkpoint on mainnet. /// -/// This assumes that the config'd state is already synced at or near Canopy -/// activation on mainnet. If the state has already synced past Canopy +/// This assumes that the config'd state is already synced at or near the mandatory checkpoint +/// activation on mainnet. If the state has already synced past the mandatory checkpoint /// activation by 1200 blocks, it will fail. #[allow(dead_code)] -#[cfg_attr(feature = "test_sync_past_canopy_mainnet", test)] -fn sync_past_canopy_mainnet() { +#[cfg_attr(feature = "test_sync_past_mandatory_checkpoint_mainnet", test)] +fn sync_past_mandatory_checkpoint_mainnet() { zebra_test::init(); let network = Mainnet; - sync_past_canopy(network).unwrap(); + sync_past_mandatory_checkpoint(network).unwrap(); } -/// Test syncing 1200 blocks (3 checkpoints) past the last checkpoint on testnet. +/// Test syncing 1200 blocks (3 checkpoints) past the mandatory checkpoint on testnet. /// -/// This assumes that the config'd state is already synced at or near Canopy -/// activation on testnet. If the state has already synced past Canopy +/// This assumes that the config'd state is already synced at or near the mandatory checkpoint +/// activation on testnet. If the state has already synced past the mandatory checkpoint /// activation by 1200 blocks, it will fail. #[allow(dead_code)] -#[cfg_attr(feature = "test_sync_past_canopy_testnet", test)] -fn sync_past_canopy_testnet() { +#[cfg_attr(feature = "test_sync_past_mandatory_checkpoint_testnet", test)] +fn sync_past_mandatory_checkpoint_testnet() { zebra_test::init(); let network = Testnet; - sync_past_canopy(network).unwrap(); + sync_past_mandatory_checkpoint(network).unwrap(); } /// Returns a random port number from the ephemeral port range.