304 lines
8.8 KiB
Rust
304 lines
8.8 KiB
Rust
use std::sync::Arc;
|
|
|
|
use zebra_chain::{block::Block, parameters::Network, serialization::ZcashDeserializeInto};
|
|
use zebra_test::prelude::*;
|
|
|
|
use crate::{
|
|
service::non_finalized_state::{Chain, NonFinalizedState},
|
|
tests::{FakeChainHelper, Prepare},
|
|
};
|
|
|
|
use self::assert_eq;
|
|
|
|
#[test]
|
|
fn construct_empty() {
|
|
zebra_test::init();
|
|
let _chain = Chain::default();
|
|
}
|
|
|
|
#[test]
|
|
fn construct_single() -> Result<()> {
|
|
zebra_test::init();
|
|
let block: Arc<Block> =
|
|
zebra_test::vectors::BLOCK_MAINNET_434873_BYTES.zcash_deserialize_into()?;
|
|
|
|
let mut chain = Chain::default();
|
|
chain.push(block.prepare())?;
|
|
|
|
assert_eq!(1, chain.blocks.len());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn construct_many() -> Result<()> {
|
|
zebra_test::init();
|
|
|
|
let mut block: Arc<Block> =
|
|
zebra_test::vectors::BLOCK_MAINNET_434873_BYTES.zcash_deserialize_into()?;
|
|
let mut blocks = vec![];
|
|
|
|
while blocks.len() < 100 {
|
|
let next_block = block.make_fake_child();
|
|
blocks.push(block);
|
|
block = next_block;
|
|
}
|
|
|
|
let mut chain = Chain::default();
|
|
|
|
for block in blocks {
|
|
chain.push(block.prepare())?;
|
|
}
|
|
|
|
assert_eq!(100, chain.blocks.len());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn ord_matches_work() -> Result<()> {
|
|
zebra_test::init();
|
|
let less_block = zebra_test::vectors::BLOCK_MAINNET_434873_BYTES
|
|
.zcash_deserialize_into::<Arc<Block>>()?
|
|
.set_work(1);
|
|
let more_block = less_block.clone().set_work(10);
|
|
|
|
let mut lesser_chain = Chain::default();
|
|
lesser_chain.push(less_block.prepare())?;
|
|
|
|
let mut bigger_chain = Chain::default();
|
|
bigger_chain.push(more_block.prepare())?;
|
|
|
|
assert!(bigger_chain > lesser_chain);
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn best_chain_wins() -> Result<()> {
|
|
zebra_test::init();
|
|
|
|
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);
|
|
|
|
let expected_hash = block2.hash();
|
|
|
|
let mut state = NonFinalizedState::default();
|
|
state.commit_new_chain(block2.prepare())?;
|
|
state.commit_new_chain(child.prepare())?;
|
|
|
|
let best_chain = state.best_chain().unwrap();
|
|
assert!(best_chain.height_by_hash.contains_key(&expected_hash));
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn finalize_pops_from_best_chain() -> Result<()> {
|
|
zebra_test::init();
|
|
|
|
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);
|
|
|
|
let mut state = NonFinalizedState::default();
|
|
state.commit_new_chain(block1.clone().prepare())?;
|
|
state.commit_block(block2.clone().prepare())?;
|
|
state.commit_block(child.prepare())?;
|
|
|
|
let finalized = state.finalize();
|
|
assert_eq!(block1, finalized.block);
|
|
|
|
let finalized = state.finalize();
|
|
assert_eq!(block2, finalized.block);
|
|
|
|
assert!(state.best_chain().is_none());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
// This test gives full coverage for `take_chain_if`
|
|
fn commit_block_extending_best_chain_doesnt_drop_worst_chains() -> Result<()> {
|
|
zebra_test::init();
|
|
|
|
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);
|
|
|
|
let mut state = NonFinalizedState::default();
|
|
assert_eq!(0, state.chain_set.len());
|
|
state.commit_new_chain(block1.prepare())?;
|
|
assert_eq!(1, state.chain_set.len());
|
|
state.commit_block(block2.prepare())?;
|
|
assert_eq!(1, state.chain_set.len());
|
|
state.commit_block(child1.prepare())?;
|
|
assert_eq!(2, state.chain_set.len());
|
|
state.commit_block(child2.prepare())?;
|
|
assert_eq!(2, state.chain_set.len());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn shorter_chain_can_be_best_chain() -> Result<()> {
|
|
zebra_test::init();
|
|
|
|
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);
|
|
|
|
let short_chain_block = block1.make_fake_child().set_work(3);
|
|
|
|
let mut state = NonFinalizedState::default();
|
|
state.commit_new_chain(block1.prepare())?;
|
|
state.commit_block(long_chain_block1.prepare())?;
|
|
state.commit_block(long_chain_block2.prepare())?;
|
|
state.commit_block(short_chain_block.prepare())?;
|
|
assert_eq!(2, state.chain_set.len());
|
|
|
|
assert_eq!(2, state.best_chain_len());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn longer_chain_with_more_work_wins() -> Result<()> {
|
|
zebra_test::init();
|
|
|
|
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);
|
|
let long_chain_block3 = long_chain_block2.make_fake_child().set_work(1);
|
|
let long_chain_block4 = long_chain_block3.make_fake_child().set_work(1);
|
|
|
|
let short_chain_block = block1.make_fake_child().set_work(3);
|
|
|
|
let mut state = NonFinalizedState::default();
|
|
state.commit_new_chain(block1.prepare())?;
|
|
state.commit_block(long_chain_block1.prepare())?;
|
|
state.commit_block(long_chain_block2.prepare())?;
|
|
state.commit_block(long_chain_block3.prepare())?;
|
|
state.commit_block(long_chain_block4.prepare())?;
|
|
state.commit_block(short_chain_block.prepare())?;
|
|
assert_eq!(2, state.chain_set.len());
|
|
|
|
assert_eq!(5, state.best_chain_len());
|
|
|
|
Ok(())
|
|
}
|
|
|
|
#[test]
|
|
fn equal_length_goes_to_more_work() -> Result<()> {
|
|
zebra_test::init();
|
|
|
|
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);
|
|
let expected_hash = more_work_child.hash();
|
|
|
|
let mut state = NonFinalizedState::default();
|
|
state.commit_new_chain(block1.prepare())?;
|
|
state.commit_block(less_work_child.prepare())?;
|
|
state.commit_block(more_work_child.prepare())?;
|
|
assert_eq!(2, state.chain_set.len());
|
|
|
|
let tip_hash = state.best_tip().unwrap().1;
|
|
assert_eq!(expected_hash, tip_hash);
|
|
|
|
Ok(())
|
|
}
|