From 4d3cfd626dad9a341b11e1de503b1a08ef2110f4 Mon Sep 17 00:00:00 2001 From: teor Date: Tue, 13 Sep 2022 13:32:53 +1000 Subject: [PATCH] Move the queued_blocks tests into their own module --- zebra-state/src/service/queued_blocks.rs | 142 +----------------- .../src/service/queued_blocks/tests.rs | 3 + .../service/queued_blocks/tests/vectors.rs | 139 +++++++++++++++++ 3 files changed, 145 insertions(+), 139 deletions(-) create mode 100644 zebra-state/src/service/queued_blocks/tests.rs create mode 100644 zebra-state/src/service/queued_blocks/tests/vectors.rs diff --git a/zebra-state/src/service/queued_blocks.rs b/zebra-state/src/service/queued_blocks.rs index 1f20fb4a959..ac0270c9276 100644 --- a/zebra-state/src/service/queued_blocks.rs +++ b/zebra-state/src/service/queued_blocks.rs @@ -12,6 +12,9 @@ use zebra_chain::{block, transparent}; use crate::{BoxError, FinalizedBlock, PreparedBlock}; +#[cfg(test)] +mod tests; + /// A queued finalized block, and its corresponding [`Result`] channel. pub type QueuedFinalized = ( FinalizedBlock, @@ -188,142 +191,3 @@ impl QueuedBlocks { self.known_utxos.get(outpoint).cloned() } } - -// TODO: move these tests into their own `tests/vectors.rs` module -#[cfg(test)] -mod tests { - use std::sync::Arc; - - use tokio::sync::oneshot; - use zebra_chain::{block::Block, serialization::ZcashDeserializeInto}; - use zebra_test::prelude::*; - - use crate::{arbitrary::Prepare, tests::FakeChainHelper}; - - use super::*; - - // Quick helper trait for making queued blocks with throw away channels - trait IntoQueued { - fn into_queued(self) -> QueuedNonFinalized; - } - - impl IntoQueued for Arc { - fn into_queued(self) -> QueuedNonFinalized { - let (rsp_tx, _) = oneshot::channel(); - (self.prepare(), rsp_tx) - } - } - - #[test] - fn dequeue_gives_right_children() -> Result<()> { - let _init_guard = zebra_test::init(); - - let block1: Arc = - zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; - let child1: Arc = - zebra_test::vectors::BLOCK_MAINNET_419201_BYTES.zcash_deserialize_into()?; - let child2 = block1.make_fake_child(); - - let parent = block1.header.previous_block_hash; - - let mut queue = QueuedBlocks::default(); - // Empty to start - assert_eq!(0, queue.blocks.len()); - assert_eq!(0, queue.by_parent.len()); - assert_eq!(0, queue.by_height.len()); - assert_eq!(0, queue.known_utxos.len()); - - // Inserting the first block gives us 1 in each table, and some UTXOs - queue.queue(block1.clone().into_queued()); - assert_eq!(1, queue.blocks.len()); - assert_eq!(1, queue.by_parent.len()); - assert_eq!(1, queue.by_height.len()); - assert_eq!(2, queue.known_utxos.len()); - - // The second gives us another in each table because its a child of the first, - // and a lot of UTXOs - queue.queue(child1.clone().into_queued()); - assert_eq!(2, queue.blocks.len()); - assert_eq!(2, queue.by_parent.len()); - assert_eq!(2, queue.by_height.len()); - assert_eq!(632, queue.known_utxos.len()); - - // The 3rd only increments blocks, because it is also a child of the - // first block, so for the second and third tables it gets added to the - // existing HashSet value - queue.queue(child2.clone().into_queued()); - assert_eq!(3, queue.blocks.len()); - assert_eq!(2, queue.by_parent.len()); - assert_eq!(2, queue.by_height.len()); - assert_eq!(634, queue.known_utxos.len()); - - // Dequeueing the first block removes 1 block from each list - let children = queue.dequeue_children(parent); - assert_eq!(1, children.len()); - assert_eq!(block1, children[0].0.block); - assert_eq!(2, queue.blocks.len()); - assert_eq!(1, queue.by_parent.len()); - assert_eq!(1, queue.by_height.len()); - assert_eq!(632, queue.known_utxos.len()); - - // Dequeueing the children of the first block removes both of the other - // blocks, and empties all lists - let parent = children[0].0.block.hash(); - let children = queue.dequeue_children(parent); - assert_eq!(2, children.len()); - assert!(children - .iter() - .any(|(block, _)| block.hash == child1.hash())); - assert!(children - .iter() - .any(|(block, _)| block.hash == child2.hash())); - assert_eq!(0, queue.blocks.len()); - assert_eq!(0, queue.by_parent.len()); - assert_eq!(0, queue.by_height.len()); - assert_eq!(0, queue.known_utxos.len()); - - Ok(()) - } - - #[test] - fn prune_removes_right_children() -> Result<()> { - let _init_guard = zebra_test::init(); - - let block1: Arc = - zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; - let child1: Arc = - zebra_test::vectors::BLOCK_MAINNET_419201_BYTES.zcash_deserialize_into()?; - let child2 = block1.make_fake_child(); - - let mut queue = QueuedBlocks::default(); - queue.queue(block1.clone().into_queued()); - queue.queue(child1.clone().into_queued()); - queue.queue(child2.clone().into_queued()); - assert_eq!(3, queue.blocks.len()); - assert_eq!(2, queue.by_parent.len()); - assert_eq!(2, queue.by_height.len()); - assert_eq!(634, queue.known_utxos.len()); - - // Pruning the first height removes only block1 - queue.prune_by_height(block1.coinbase_height().unwrap()); - assert_eq!(2, queue.blocks.len()); - assert_eq!(1, queue.by_parent.len()); - assert_eq!(1, queue.by_height.len()); - assert!(queue.get_mut(&block1.hash()).is_none()); - assert!(queue.get_mut(&child1.hash()).is_some()); - assert!(queue.get_mut(&child2.hash()).is_some()); - assert_eq!(632, queue.known_utxos.len()); - - // Pruning the children of the first block removes both of the other - // blocks, and empties all lists - queue.prune_by_height(child1.coinbase_height().unwrap()); - assert_eq!(0, queue.blocks.len()); - assert_eq!(0, queue.by_parent.len()); - assert_eq!(0, queue.by_height.len()); - assert!(queue.get_mut(&child1.hash()).is_none()); - assert!(queue.get_mut(&child2.hash()).is_none()); - assert_eq!(0, queue.known_utxos.len()); - - Ok(()) - } -} diff --git a/zebra-state/src/service/queued_blocks/tests.rs b/zebra-state/src/service/queued_blocks/tests.rs new file mode 100644 index 00000000000..823e8b6d7c5 --- /dev/null +++ b/zebra-state/src/service/queued_blocks/tests.rs @@ -0,0 +1,3 @@ +//! Tests for block queues. + +mod vectors; diff --git a/zebra-state/src/service/queued_blocks/tests/vectors.rs b/zebra-state/src/service/queued_blocks/tests/vectors.rs new file mode 100644 index 00000000000..bd8dcbeb8e2 --- /dev/null +++ b/zebra-state/src/service/queued_blocks/tests/vectors.rs @@ -0,0 +1,139 @@ +//! Fixed test vectors for block queues. + +use std::sync::Arc; + +use tokio::sync::oneshot; + +use zebra_chain::{block::Block, serialization::ZcashDeserializeInto}; +use zebra_test::prelude::*; + +use crate::{ + arbitrary::Prepare, + service::queued_blocks::{QueuedBlocks, QueuedNonFinalized}, + tests::FakeChainHelper, +}; + +// Quick helper trait for making queued blocks with throw away channels +trait IntoQueued { + fn into_queued(self) -> QueuedNonFinalized; +} + +impl IntoQueued for Arc { + fn into_queued(self) -> QueuedNonFinalized { + let (rsp_tx, _) = oneshot::channel(); + (self.prepare(), rsp_tx) + } +} + +#[test] +fn dequeue_gives_right_children() -> Result<()> { + let _init_guard = zebra_test::init(); + + let block1: Arc = + zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; + let child1: Arc = + zebra_test::vectors::BLOCK_MAINNET_419201_BYTES.zcash_deserialize_into()?; + let child2 = block1.make_fake_child(); + + let parent = block1.header.previous_block_hash; + + let mut queue = QueuedBlocks::default(); + // Empty to start + assert_eq!(0, queue.blocks.len()); + assert_eq!(0, queue.by_parent.len()); + assert_eq!(0, queue.by_height.len()); + assert_eq!(0, queue.known_utxos.len()); + + // Inserting the first block gives us 1 in each table, and some UTXOs + queue.queue(block1.clone().into_queued()); + assert_eq!(1, queue.blocks.len()); + assert_eq!(1, queue.by_parent.len()); + assert_eq!(1, queue.by_height.len()); + assert_eq!(2, queue.known_utxos.len()); + + // The second gives us another in each table because its a child of the first, + // and a lot of UTXOs + queue.queue(child1.clone().into_queued()); + assert_eq!(2, queue.blocks.len()); + assert_eq!(2, queue.by_parent.len()); + assert_eq!(2, queue.by_height.len()); + assert_eq!(632, queue.known_utxos.len()); + + // The 3rd only increments blocks, because it is also a child of the + // first block, so for the second and third tables it gets added to the + // existing HashSet value + queue.queue(child2.clone().into_queued()); + assert_eq!(3, queue.blocks.len()); + assert_eq!(2, queue.by_parent.len()); + assert_eq!(2, queue.by_height.len()); + assert_eq!(634, queue.known_utxos.len()); + + // Dequeueing the first block removes 1 block from each list + let children = queue.dequeue_children(parent); + assert_eq!(1, children.len()); + assert_eq!(block1, children[0].0.block); + assert_eq!(2, queue.blocks.len()); + assert_eq!(1, queue.by_parent.len()); + assert_eq!(1, queue.by_height.len()); + assert_eq!(632, queue.known_utxos.len()); + + // Dequeueing the children of the first block removes both of the other + // blocks, and empties all lists + let parent = children[0].0.block.hash(); + let children = queue.dequeue_children(parent); + assert_eq!(2, children.len()); + assert!(children + .iter() + .any(|(block, _)| block.hash == child1.hash())); + assert!(children + .iter() + .any(|(block, _)| block.hash == child2.hash())); + assert_eq!(0, queue.blocks.len()); + assert_eq!(0, queue.by_parent.len()); + assert_eq!(0, queue.by_height.len()); + assert_eq!(0, queue.known_utxos.len()); + + Ok(()) +} + +#[test] +fn prune_removes_right_children() -> Result<()> { + let _init_guard = zebra_test::init(); + + let block1: Arc = + zebra_test::vectors::BLOCK_MAINNET_419200_BYTES.zcash_deserialize_into()?; + let child1: Arc = + zebra_test::vectors::BLOCK_MAINNET_419201_BYTES.zcash_deserialize_into()?; + let child2 = block1.make_fake_child(); + + let mut queue = QueuedBlocks::default(); + queue.queue(block1.clone().into_queued()); + queue.queue(child1.clone().into_queued()); + queue.queue(child2.clone().into_queued()); + assert_eq!(3, queue.blocks.len()); + assert_eq!(2, queue.by_parent.len()); + assert_eq!(2, queue.by_height.len()); + assert_eq!(634, queue.known_utxos.len()); + + // Pruning the first height removes only block1 + queue.prune_by_height(block1.coinbase_height().unwrap()); + assert_eq!(2, queue.blocks.len()); + assert_eq!(1, queue.by_parent.len()); + assert_eq!(1, queue.by_height.len()); + assert!(queue.get_mut(&block1.hash()).is_none()); + assert!(queue.get_mut(&child1.hash()).is_some()); + assert!(queue.get_mut(&child2.hash()).is_some()); + assert_eq!(632, queue.known_utxos.len()); + + // Pruning the children of the first block removes both of the other + // blocks, and empties all lists + queue.prune_by_height(child1.coinbase_height().unwrap()); + assert_eq!(0, queue.blocks.len()); + assert_eq!(0, queue.by_parent.len()); + assert_eq!(0, queue.by_height.len()); + assert!(queue.get_mut(&child1.hash()).is_none()); + assert!(queue.get_mut(&child2.hash()).is_none()); + assert_eq!(0, queue.known_utxos.len()); + + Ok(()) +}