//! Randomised property tests for the finalized state. use std::env; use zebra_chain::{block::Height, parameters::NetworkUpgrade}; use zebra_test::prelude::*; use crate::{ config::Config, service::{ arbitrary::PreparedChain, finalized_state::{CheckpointVerifiedBlock, FinalizedState}, }, tests::FakeChainHelper, }; const DEFAULT_PARTIAL_CHAIN_PROPTEST_CASES: u32 = 1; #[test] fn blocks_with_v5_transactions() -> Result<()> { let _init_guard = zebra_test::init(); proptest!(ProptestConfig::with_cases(env::var("PROPTEST_CASES") .ok() .and_then(|v| v.parse().ok()) .unwrap_or(DEFAULT_PARTIAL_CHAIN_PROPTEST_CASES)), |((chain, count, network, _history_tree) in PreparedChain::default())| { let mut state = FinalizedState::new(&Config::ephemeral(), network, #[cfg(feature = "elasticsearch")] None); let mut height = Height(0); // use `count` to minimize test failures, so they are easier to diagnose for block in chain.iter().take(count) { let checkpoint_verified = CheckpointVerifiedBlock::from(block.block.clone()); let (hash, _) = state.commit_finalized_direct( checkpoint_verified.into(), None, "blocks_with_v5_transactions test" ).unwrap(); prop_assert_eq!(Some(height), state.finalized_tip_height()); prop_assert_eq!(hash, block.hash); height = Height(height.0 + 1); } }); Ok(()) } /// Test if committing blocks from all upgrades work correctly, to make /// sure the contextual validation done by the finalized state works. /// Also test if a block with the wrong commitment is correctly rejected. /// /// This test requires setting the TEST_FAKE_ACTIVATION_HEIGHTS. #[test] #[allow(clippy::print_stderr)] fn all_upgrades_and_wrong_commitments_with_fake_activation_heights() -> Result<()> { let _init_guard = zebra_test::init(); if std::env::var_os("TEST_FAKE_ACTIVATION_HEIGHTS").is_none() { eprintln!("Skipping all_upgrades_and_wrong_commitments_with_fake_activation_heights() since $TEST_FAKE_ACTIVATION_HEIGHTS is NOT set"); return Ok(()); } // Use no_shrink() because we're ignoring _count and there is nothing to actually shrink. proptest!(ProptestConfig::with_cases(env::var("PROPTEST_CASES") .ok() .and_then(|v| v.parse().ok()) .unwrap_or(DEFAULT_PARTIAL_CHAIN_PROPTEST_CASES)), |((chain, _count, network, _history_tree) in PreparedChain::default().with_valid_commitments().no_shrink())| { let mut state = FinalizedState::new(&Config::ephemeral(), network, #[cfg(feature = "elasticsearch")] None); let mut height = Height(0); let heartwood_height = NetworkUpgrade::Heartwood.activation_height(network).unwrap(); let heartwood_height_plus1 = (heartwood_height + 1).unwrap(); let nu5_height = NetworkUpgrade::Nu5.activation_height(network).unwrap(); let nu5_height_plus1 = (nu5_height + 1).unwrap(); let mut failure_count = 0; for block in chain.iter() { let block_hash = block.hash; let current_height = block.block.coinbase_height().unwrap(); // For some specific heights, try to commit a block with // corrupted commitment. match current_height { h if h == heartwood_height || h == heartwood_height_plus1 || h == nu5_height || h == nu5_height_plus1 => { let block = block.block.clone().set_block_commitment([0x42; 32]); let checkpoint_verified = CheckpointVerifiedBlock::from(block); state.commit_finalized_direct( checkpoint_verified.into(), None, "all_upgrades test" ).expect_err("Must fail commitment check"); failure_count += 1; }, _ => {}, } let checkpoint_verified = CheckpointVerifiedBlock::from(block.block.clone()); let (hash, _) = state.commit_finalized_direct( checkpoint_verified.into(), None, "all_upgrades test" ).unwrap(); prop_assert_eq!(Some(height), state.finalized_tip_height()); prop_assert_eq!(hash, block_hash); height = Height(height.0 + 1); } // Make sure the failure path was triggered prop_assert_eq!(failure_count, 4); }); Ok(()) }