panic in `NonFinalizedState::commit_block` before Canopy (#1909)

* add a panic in commit_block() for blocks before canopy
* update tests to use a post canopy block and network

Co-authored-by: teor <teor@riseup.net>
This commit is contained in:
Alfredo Garcia 2021-03-16 21:41:28 -03:00 committed by GitHub
parent d49eaab68e
commit 9e1662d2d7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 110 additions and 15 deletions

View File

@ -64,7 +64,10 @@ impl StateService {
pub fn new(config: Config, network: Network) -> Self { pub fn new(config: Config, network: Network) -> Self {
let disk = FinalizedState::new(&config, network); let disk = FinalizedState::new(&config, network);
let mem = NonFinalizedState::default(); let mem = NonFinalizedState {
network,
..Default::default()
};
let queued_blocks = QueuedBlocks::default(); let queued_blocks = QueuedBlocks::default();
let pending_utxos = PendingUtxos::default(); let pending_utxos = PendingUtxos::default();

View File

@ -11,6 +11,7 @@ use std::{collections::BTreeSet, mem, ops::Deref, sync::Arc};
use zebra_chain::{ use zebra_chain::{
block::{self, Block}, block::{self, Block},
parameters::{Network, NetworkUpgrade::Canopy},
transaction::{self, Transaction}, transaction::{self, Transaction},
transparent, transparent,
}; };
@ -25,7 +26,9 @@ pub struct NonFinalizedState {
/// Verified, non-finalized chains, in ascending order. /// Verified, non-finalized chains, in ascending order.
/// ///
/// The best chain is `chain_set.last()` or `chain_set.iter().next_back()`. /// The best chain is `chain_set.last()` or `chain_set.iter().next_back()`.
chain_set: BTreeSet<Box<Chain>>, pub chain_set: BTreeSet<Box<Chain>>,
/// The configured Zcash network
pub network: Network,
} }
impl NonFinalizedState { impl NonFinalizedState {
@ -70,6 +73,14 @@ impl NonFinalizedState {
/// Commit block to the non-finalized state. /// Commit block to the non-finalized state.
pub fn commit_block(&mut self, prepared: PreparedBlock) { pub fn commit_block(&mut self, prepared: PreparedBlock) {
let parent_hash = prepared.block.header.previous_block_hash; 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 let mut parent_chain = self
.take_chain_if(|chain| chain.non_finalized_tip_hash() == parent_hash) .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"); .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); parent_chain.push(prepared);
self.chain_set.insert(parent_chain); self.chain_set.insert(parent_chain);
self.update_metrics_for_committed_block(height, hash); self.update_metrics_for_committed_block(height, hash);
@ -276,8 +286,22 @@ mod tests {
fn best_chain_wins() -> Result<()> { fn best_chain_wins() -> Result<()> {
zebra_test::init(); zebra_test::init();
let block1: Arc<Block> = best_chain_wins_for_network(Network::Mainnet)?;
zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; best_chain_wins_for_network(Network::Testnet)?;
Ok(())
}
fn best_chain_wins_for_network(network: Network) -> Result<()> {
let block1: Arc<Block> = 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 block2 = block1.make_fake_child().set_work(10);
let child = block1.make_fake_child().set_work(1); let child = block1.make_fake_child().set_work(1);
@ -297,8 +321,22 @@ mod tests {
fn finalize_pops_from_best_chain() -> Result<()> { fn finalize_pops_from_best_chain() -> Result<()> {
zebra_test::init(); zebra_test::init();
let block1: Arc<Block> = finalize_pops_from_best_chain_for_network(Network::Mainnet)?;
zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; finalize_pops_from_best_chain_for_network(Network::Testnet)?;
Ok(())
}
fn finalize_pops_from_best_chain_for_network(network: Network) -> Result<()> {
let block1: Arc<Block> = 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 block2 = block1.make_fake_child().set_work(10);
let child = block1.make_fake_child().set_work(1); 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<()> { fn commit_block_extending_best_chain_doesnt_drop_worst_chains() -> Result<()> {
zebra_test::init(); zebra_test::init();
let block1: Arc<Block> = commit_block_extending_best_chain_doesnt_drop_worst_chains_for_network(Network::Mainnet)?;
zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; 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<Block> = 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 block2 = block1.make_fake_child().set_work(10);
let child1 = block1.make_fake_child().set_work(1); let child1 = block1.make_fake_child().set_work(1);
let child2 = block2.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<()> { fn shorter_chain_can_be_best_chain() -> Result<()> {
zebra_test::init(); zebra_test::init();
let block1: Arc<Block> = shorter_chain_can_be_best_chain_for_network(Network::Mainnet)?;
zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; 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<Block> = 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_block1 = block1.make_fake_child().set_work(1);
let long_chain_block2 = long_chain_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<()> { fn longer_chain_with_more_work_wins() -> Result<()> {
zebra_test::init(); zebra_test::init();
let block1: Arc<Block> = longer_chain_with_more_work_wins_for_network(Network::Mainnet)?;
zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; 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<Block> = 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_block1 = block1.make_fake_child().set_work(1);
let long_chain_block2 = long_chain_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<()> { fn equal_length_goes_to_more_work() -> Result<()> {
zebra_test::init(); zebra_test::init();
let block1: Arc<Block> = equal_length_goes_to_more_work_for_network(Network::Mainnet)?;
zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; 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<Block> = 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 less_work_child = block1.make_fake_child().set_work(1);
let more_work_child = block1.make_fake_child().set_work(3); let more_work_child = block1.make_fake_child().set_work(3);