diff --git a/zebra-state/src/service.rs b/zebra-state/src/service.rs index 5310126aa..387c8723b 100644 --- a/zebra-state/src/service.rs +++ b/zebra-state/src/service.rs @@ -64,7 +64,10 @@ impl StateService { pub fn new(config: Config, network: Network) -> Self { let disk = FinalizedState::new(&config, network); - let mem = NonFinalizedState::default(); + let mem = NonFinalizedState { + network, + ..Default::default() + }; let queued_blocks = QueuedBlocks::default(); let pending_utxos = PendingUtxos::default(); diff --git a/zebra-state/src/service/non_finalized_state.rs b/zebra-state/src/service/non_finalized_state.rs index 9cc16b88f..adbb43485 100644 --- a/zebra-state/src/service/non_finalized_state.rs +++ b/zebra-state/src/service/non_finalized_state.rs @@ -11,6 +11,7 @@ use std::{collections::BTreeSet, mem, ops::Deref, sync::Arc}; use zebra_chain::{ block::{self, Block}, + parameters::{Network, NetworkUpgrade::Canopy}, transaction::{self, Transaction}, transparent, }; @@ -25,7 +26,9 @@ pub struct NonFinalizedState { /// Verified, non-finalized chains, in ascending order. /// /// The best chain is `chain_set.last()` or `chain_set.iter().next_back()`. - chain_set: BTreeSet>, + pub chain_set: BTreeSet>, + /// The configured Zcash network + pub network: Network, } impl NonFinalizedState { @@ -70,6 +73,14 @@ impl NonFinalizedState { /// Commit block to the non-finalized state. pub fn commit_block(&mut self, prepared: PreparedBlock) { 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 { + panic!( + "invalid non-finalized block height: the canopy checkpoint is mandatory, pre-canopy blocks must be committed to the state as finalized blocks" + ); + } let mut parent_chain = self .take_chain_if(|chain| chain.non_finalized_tip_hash() == parent_hash) @@ -81,7 +92,6 @@ impl NonFinalizedState { }) .expect("commit_block is only called with blocks that are ready to be commited"); - let (height, hash) = (prepared.height, prepared.hash); parent_chain.push(prepared); self.chain_set.insert(parent_chain); self.update_metrics_for_committed_block(height, hash); @@ -276,8 +286,22 @@ mod tests { fn best_chain_wins() -> Result<()> { zebra_test::init(); - let block1: Arc = - zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; + best_chain_wins_for_network(Network::Mainnet)?; + best_chain_wins_for_network(Network::Testnet)?; + + Ok(()) + } + + fn best_chain_wins_for_network(network: Network) -> Result<()> { + let block1: Arc = match network { + Network::Mainnet => { + zebra_test::vectors::BLOCK_MAINNET_1180900_BYTES.zcash_deserialize_into()? + } + Network::Testnet => { + zebra_test::vectors::BLOCK_TESTNET_1326100_BYTES.zcash_deserialize_into()? + } + }; + let block2 = block1.make_fake_child().set_work(10); let child = block1.make_fake_child().set_work(1); @@ -297,8 +321,22 @@ mod tests { fn finalize_pops_from_best_chain() -> Result<()> { zebra_test::init(); - let block1: Arc = - zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; + finalize_pops_from_best_chain_for_network(Network::Mainnet)?; + finalize_pops_from_best_chain_for_network(Network::Testnet)?; + + Ok(()) + } + + fn finalize_pops_from_best_chain_for_network(network: Network) -> Result<()> { + let block1: Arc = match network { + Network::Mainnet => { + zebra_test::vectors::BLOCK_MAINNET_1180900_BYTES.zcash_deserialize_into()? + } + Network::Testnet => { + zebra_test::vectors::BLOCK_TESTNET_1326100_BYTES.zcash_deserialize_into()? + } + }; + let block2 = block1.make_fake_child().set_work(10); let child = block1.make_fake_child().set_work(1); @@ -323,8 +361,24 @@ mod tests { fn commit_block_extending_best_chain_doesnt_drop_worst_chains() -> Result<()> { zebra_test::init(); - let block1: Arc = - zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; + commit_block_extending_best_chain_doesnt_drop_worst_chains_for_network(Network::Mainnet)?; + commit_block_extending_best_chain_doesnt_drop_worst_chains_for_network(Network::Testnet)?; + + Ok(()) + } + + fn commit_block_extending_best_chain_doesnt_drop_worst_chains_for_network( + network: Network, + ) -> Result<()> { + let block1: Arc = match network { + Network::Mainnet => { + zebra_test::vectors::BLOCK_MAINNET_1180900_BYTES.zcash_deserialize_into()? + } + Network::Testnet => { + zebra_test::vectors::BLOCK_TESTNET_1326100_BYTES.zcash_deserialize_into()? + } + }; + let block2 = block1.make_fake_child().set_work(10); let child1 = block1.make_fake_child().set_work(1); let child2 = block2.make_fake_child().set_work(1); @@ -347,8 +401,21 @@ mod tests { fn shorter_chain_can_be_best_chain() -> Result<()> { zebra_test::init(); - let block1: Arc = - zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; + shorter_chain_can_be_best_chain_for_network(Network::Mainnet)?; + shorter_chain_can_be_best_chain_for_network(Network::Testnet)?; + + Ok(()) + } + + fn shorter_chain_can_be_best_chain_for_network(network: Network) -> Result<()> { + let block1: Arc = match network { + Network::Mainnet => { + zebra_test::vectors::BLOCK_MAINNET_1180900_BYTES.zcash_deserialize_into()? + } + Network::Testnet => { + zebra_test::vectors::BLOCK_TESTNET_1326100_BYTES.zcash_deserialize_into()? + } + }; let long_chain_block1 = block1.make_fake_child().set_work(1); let long_chain_block2 = long_chain_block1.make_fake_child().set_work(1); @@ -371,8 +438,21 @@ mod tests { fn longer_chain_with_more_work_wins() -> Result<()> { zebra_test::init(); - let block1: Arc = - zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; + longer_chain_with_more_work_wins_for_network(Network::Mainnet)?; + longer_chain_with_more_work_wins_for_network(Network::Testnet)?; + + Ok(()) + } + + fn longer_chain_with_more_work_wins_for_network(network: Network) -> Result<()> { + let block1: Arc = match network { + Network::Mainnet => { + zebra_test::vectors::BLOCK_MAINNET_1180900_BYTES.zcash_deserialize_into()? + } + Network::Testnet => { + zebra_test::vectors::BLOCK_TESTNET_1326100_BYTES.zcash_deserialize_into()? + } + }; let long_chain_block1 = block1.make_fake_child().set_work(1); let long_chain_block2 = long_chain_block1.make_fake_child().set_work(1); @@ -399,8 +479,20 @@ mod tests { fn equal_length_goes_to_more_work() -> Result<()> { zebra_test::init(); - let block1: Arc = - zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; + equal_length_goes_to_more_work_for_network(Network::Mainnet)?; + equal_length_goes_to_more_work_for_network(Network::Testnet)?; + + Ok(()) + } + fn equal_length_goes_to_more_work_for_network(network: Network) -> Result<()> { + let block1: Arc = match network { + Network::Mainnet => { + zebra_test::vectors::BLOCK_MAINNET_1180900_BYTES.zcash_deserialize_into()? + } + Network::Testnet => { + zebra_test::vectors::BLOCK_TESTNET_1326100_BYTES.zcash_deserialize_into()? + } + }; let less_work_child = block1.make_fake_child().set_work(1); let more_work_child = block1.make_fake_child().set_work(3);