zebra/zebra-consensus/src/checkpoint/list/tests.rs

267 lines
8.7 KiB
Rust
Raw Normal View History

//! Tests for CheckpointList
use super::*;
use std::sync::Arc;
use zebra_chain::parameters::{Network, NetworkUpgrade::Sapling};
use zebra_chain::{block::Block, serialization::ZcashDeserialize};
/// Make a checkpoint list containing only the genesis block
#[test]
fn checkpoint_list_genesis() -> Result<(), Error> {
zebra_test::init();
// Parse the genesis block
let mut checkpoint_data = Vec::new();
let block =
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])?;
let hash: BlockHeaderHash = block.as_ref().into();
checkpoint_data.push((
block.coinbase_height().expect("test block has height"),
hash,
));
// Make a checkpoint list containing the genesis block
let checkpoint_list: BTreeMap<BlockHeight, BlockHeaderHash> =
checkpoint_data.iter().cloned().collect();
let _ = CheckpointList::from_list(checkpoint_list)?;
Ok(())
}
/// Make a checkpoint list containing multiple blocks
#[test]
fn checkpoint_list_multiple() -> Result<(), Error> {
zebra_test::init();
// Parse all the blocks
let mut checkpoint_data = Vec::new();
for b in &[
&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..],
&zebra_test::vectors::BLOCK_MAINNET_1_BYTES[..],
&zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..],
&zebra_test::vectors::BLOCK_MAINNET_434873_BYTES[..],
] {
let block = Arc::<Block>::zcash_deserialize(*b)?;
let hash: BlockHeaderHash = block.as_ref().into();
checkpoint_data.push((
block.coinbase_height().expect("test block has height"),
hash,
));
}
// Make a checkpoint list containing all the blocks
let checkpoint_list: BTreeMap<BlockHeight, BlockHeaderHash> =
checkpoint_data.iter().cloned().collect();
let _ = CheckpointList::from_list(checkpoint_list)?;
Ok(())
}
/// Make sure that an empty checkpoint list fails
#[test]
fn checkpoint_list_empty_fail() -> Result<(), Error> {
zebra_test::init();
let _ = CheckpointList::from_list(Vec::new()).expect_err("empty checkpoint lists should fail");
Ok(())
}
/// Make sure a checkpoint list that doesn't contain the genesis block fails
#[test]
fn checkpoint_list_no_genesis_fail() -> Result<(), Error> {
zebra_test::init();
// Parse a non-genesis block
let mut checkpoint_data = Vec::new();
let block = Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_1_BYTES[..])?;
let hash: BlockHeaderHash = block.as_ref().into();
checkpoint_data.push((
block.coinbase_height().expect("test block has height"),
hash,
));
// Make a checkpoint list containing the non-genesis block
let checkpoint_list: BTreeMap<BlockHeight, BlockHeaderHash> =
checkpoint_data.iter().cloned().collect();
let _ = CheckpointList::from_list(checkpoint_list)
.expect_err("a checkpoint list with no genesis block should fail");
Ok(())
}
/// Make sure a checkpoint list that contains a null hash fails
#[test]
fn checkpoint_list_null_hash_fail() -> Result<(), Error> {
zebra_test::init();
let checkpoint_data = vec![(BlockHeight(0), BlockHeaderHash([0; 32]))];
// Make a checkpoint list containing the non-genesis block
let checkpoint_list: BTreeMap<BlockHeight, BlockHeaderHash> =
checkpoint_data.iter().cloned().collect();
let _ = CheckpointList::from_list(checkpoint_list)
.expect_err("a checkpoint list with a null block hash should fail");
Ok(())
}
/// Make sure a checkpoint list that contains an invalid block height fails
#[test]
fn checkpoint_list_bad_height_fail() -> Result<(), Error> {
zebra_test::init();
let checkpoint_data = vec![(
BlockHeight(BlockHeight::MAX.0 + 1),
BlockHeaderHash([1; 32]),
)];
// Make a checkpoint list containing the non-genesis block
let checkpoint_list: BTreeMap<BlockHeight, BlockHeaderHash> =
checkpoint_data.iter().cloned().collect();
let _ = CheckpointList::from_list(checkpoint_list).expect_err(
"a checkpoint list with an invalid block height (BlockHeight::MAX + 1) should fail",
);
let checkpoint_data = vec![(BlockHeight(u32::MAX), BlockHeaderHash([1; 32]))];
// Make a checkpoint list containing the non-genesis block
let checkpoint_list: BTreeMap<BlockHeight, BlockHeaderHash> =
checkpoint_data.iter().cloned().collect();
let _ = CheckpointList::from_list(checkpoint_list)
.expect_err("a checkpoint list with an invalid block height (u32::MAX) should fail");
Ok(())
}
/// Make sure that a checkpoint list containing duplicate blocks fails
#[test]
fn checkpoint_list_duplicate_blocks_fail() -> Result<(), Error> {
zebra_test::init();
// Parse some blocks twice
let mut checkpoint_data = Vec::new();
for b in &[
&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..],
&zebra_test::vectors::BLOCK_MAINNET_1_BYTES[..],
&zebra_test::vectors::BLOCK_MAINNET_1_BYTES[..],
] {
let block = Arc::<Block>::zcash_deserialize(*b)?;
let hash: BlockHeaderHash = block.as_ref().into();
checkpoint_data.push((
block.coinbase_height().expect("test block has height"),
hash,
));
}
// Make a checkpoint list containing some duplicate blocks
let _ = CheckpointList::from_list(checkpoint_data)
.expect_err("checkpoint lists with duplicate blocks should fail");
Ok(())
}
/// Make sure that a checkpoint list containing duplicate heights
/// (with different hashes) fails
#[test]
fn checkpoint_list_duplicate_heights_fail() -> Result<(), Error> {
zebra_test::init();
// Parse the genesis block
let mut checkpoint_data = Vec::new();
for b in &[&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..]] {
let block = Arc::<Block>::zcash_deserialize(*b)?;
let hash: BlockHeaderHash = block.as_ref().into();
checkpoint_data.push((
block.coinbase_height().expect("test block has height"),
hash,
));
}
// Then add some fake entries with duplicate heights
checkpoint_data.push((BlockHeight(1), BlockHeaderHash([0xaa; 32])));
checkpoint_data.push((BlockHeight(1), BlockHeaderHash([0xbb; 32])));
// Make a checkpoint list containing some duplicate blocks
let _ = CheckpointList::from_list(checkpoint_data)
.expect_err("checkpoint lists with duplicate heights should fail");
Ok(())
}
/// Make sure that a checkpoint list containing duplicate hashes
/// (at different heights) fails
#[test]
fn checkpoint_list_duplicate_hashes_fail() -> Result<(), Error> {
zebra_test::init();
// Parse the genesis block
let mut checkpoint_data = Vec::new();
for b in &[&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..]] {
let block = Arc::<Block>::zcash_deserialize(*b)?;
let hash: BlockHeaderHash = block.as_ref().into();
checkpoint_data.push((
block.coinbase_height().expect("test block has height"),
hash,
));
}
// Then add some fake entries with duplicate hashes
checkpoint_data.push((BlockHeight(1), BlockHeaderHash([0xcc; 32])));
checkpoint_data.push((BlockHeight(2), BlockHeaderHash([0xcc; 32])));
// Make a checkpoint list containing some duplicate blocks
let _ = CheckpointList::from_list(checkpoint_data)
.expect_err("checkpoint lists with duplicate hashes should fail");
Ok(())
}
/// Parse and check the hard-coded Mainnet and Testnet lists
#[test]
fn checkpoint_list_load_hard_coded() -> Result<(), Error> {
zebra_test::init();
let _: CheckpointList = MAINNET_CHECKPOINTS
.parse()
.expect("hard-coded Mainnet checkpoint list should parse");
let _: CheckpointList = TESTNET_CHECKPOINTS
.parse()
.expect("hard-coded Testnet checkpoint list should parse");
let _ = CheckpointList::new(Network::Mainnet);
let _ = CheckpointList::new(Network::Testnet);
Ok(())
}
#[test]
fn checkpoint_list_hard_coded_sapling_mainnet() -> Result<(), Error> {
checkpoint_list_hard_coded_sapling(Network::Mainnet)
}
#[test]
fn checkpoint_list_hard_coded_sapling_testnet() -> Result<(), Error> {
checkpoint_list_hard_coded_sapling(Network::Testnet)
}
/// Check that the hard-coded lists cover the Sapling network upgrade
fn checkpoint_list_hard_coded_sapling(network: Network) -> Result<(), Error> {
zebra_test::init();
let sapling_activation = Sapling
.activation_height(network)
.expect("Unexpected network upgrade info: Sapling must have an activation height");
let list = CheckpointList::new(network);
assert!(
list.max_height() >= sapling_activation,
"Pre-Sapling blocks must be verified by checkpoints"
);
Ok(())
}