diff --git a/packages/zaino-state/src/chain_index/tests.rs b/packages/zaino-state/src/chain_index/tests.rs index 047091d27..6bce43bae 100644 --- a/packages/zaino-state/src/chain_index/tests.rs +++ b/packages/zaino-state/src/chain_index/tests.rs @@ -1,5 +1,6 @@ //! Zaino-State ChainIndex unit tests. +mod best_chaintip; pub(crate) mod finalised_state; pub(crate) mod mempool; mod mockchain_tests; diff --git a/packages/zaino-state/src/chain_index/tests/best_chaintip.rs b/packages/zaino-state/src/chain_index/tests/best_chaintip.rs new file mode 100644 index 000000000..1abe757f0 --- /dev/null +++ b/packages/zaino-state/src/chain_index/tests/best_chaintip.rs @@ -0,0 +1,39 @@ +//! Regression tests for `best_chaintip`. +//! +//! Tracks : when the snapshot +//! is `StillSyncingFinalizedState` and the source cannot currently produce +//! the block at `validator_finalized_height`, `best_chaintip` surfaces the +//! miss as `database_hole` — the corruption kind — instead of a retryable +//! "not ready" signal. + +use super::load_test_vectors_and_sync_chain_index; +use crate::chain_index::ChainIndex; +use crate::{ChainIndexSnapshot, Height}; + +/// Reaches the `StillSyncingFinalizedState` arm with a +/// `validator_finalized_height` the source cannot serve, mirroring the +/// cold-boot race where zebrad transiently can't produce block `tip - 100`. +/// The error (if any) must not be a `database_hole`: that category means +/// zaino's own on-disk index claims a height whose bytes are unreachable, +/// which is not what happened here. +#[tokio::test(flavor = "multi_thread")] +async fn passthrough_miss_is_not_a_database_hole() { + let (_blocks, _indexer, index_reader, mockchain) = + load_test_vectors_and_sync_chain_index(false).await; + + let above_tip = Height(mockchain.max_chain_height() + 1_000); + let fake_snapshot = ChainIndexSnapshot::StillSyncingFinalizedState { + validator_finalized_height: above_tip, + }; + + match index_reader.best_chaintip(&fake_snapshot).await { + Ok(_tip) => {} + Err(e) => { + let rendered = e.to_string(); + assert!( + !rendered.contains("hole in validator database"), + "best_chaintip misclassified a passthrough miss as a database hole: {rendered}", + ); + } + } +}