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 {
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();

View File

@ -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<Box<Chain>>,
pub chain_set: BTreeSet<Box<Chain>>,
/// 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<Block> =
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<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 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<Block> =
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<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 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<Block> =
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<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 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<Block> =
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<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_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<Block> =
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<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_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<Block> =
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<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 more_work_child = block1.make_fake_child().set_work(3);