2020-07-09 23:51:01 -07:00
|
|
|
//! Tests for checkpoint-based block verification
|
|
|
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
use super::types::Progress::*;
|
2020-11-12 16:11:25 -08:00
|
|
|
use super::types::TargetHeight::*;
|
2020-07-09 23:51:01 -07:00
|
|
|
|
|
|
|
use color_eyre::eyre::{eyre, Report};
|
2021-11-02 11:46:57 -07:00
|
|
|
use futures::{
|
|
|
|
future::TryFutureExt,
|
|
|
|
stream::{FuturesUnordered, StreamExt},
|
|
|
|
};
|
2021-03-02 22:01:39 -08:00
|
|
|
use std::{cmp::min, convert::TryInto, mem::drop, time::Duration};
|
2021-11-02 11:46:57 -07:00
|
|
|
use tokio::time::timeout;
|
2021-07-28 16:55:01 -07:00
|
|
|
use tower::{Service, ServiceExt};
|
2020-07-13 09:29:21 -07:00
|
|
|
use tracing_futures::Instrument;
|
2020-07-09 23:51:01 -07:00
|
|
|
|
2020-09-02 21:23:57 -07:00
|
|
|
use zebra_chain::parameters::Network::*;
|
2020-07-09 23:51:01 -07:00
|
|
|
use zebra_chain::serialization::ZcashDeserialize;
|
|
|
|
|
|
|
|
/// The timeout we apply to each verify future during testing.
|
|
|
|
///
|
|
|
|
/// The checkpoint verifier uses `tokio::sync::oneshot` channels as futures.
|
|
|
|
/// If the verifier doesn't send a message on the channel, any tests that
|
|
|
|
/// await the channel future will hang.
|
|
|
|
///
|
|
|
|
/// This value is set to a large value, to avoid spurious failures due to
|
|
|
|
/// high system load.
|
|
|
|
const VERIFY_TIMEOUT_SECONDS: u64 = 10;
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn single_item_checkpoint_list_test() -> Result<(), Report> {
|
|
|
|
single_item_checkpoint_list().await
|
|
|
|
}
|
|
|
|
|
|
|
|
#[spandoc::spandoc]
|
|
|
|
async fn single_item_checkpoint_list() -> Result<(), Report> {
|
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
let block0 =
|
|
|
|
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])?;
|
2020-08-15 23:20:01 -07:00
|
|
|
let hash0 = block0.hash();
|
2020-07-09 23:51:01 -07:00
|
|
|
|
|
|
|
// Make a checkpoint list containing only the genesis block
|
2020-08-16 11:42:02 -07:00
|
|
|
let genesis_checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
2020-07-09 23:51:01 -07:00
|
|
|
[(block0.coinbase_height().unwrap(), hash0)]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect();
|
|
|
|
|
2021-07-28 16:55:01 -07:00
|
|
|
let state_service = zebra_state::init_test(Mainnet);
|
2020-07-09 23:51:01 -07:00
|
|
|
let mut checkpoint_verifier =
|
2021-03-10 18:07:37 -08:00
|
|
|
CheckpointVerifier::from_list(genesis_checkpoint_list, Mainnet, None, state_service)
|
2020-09-02 21:23:57 -07:00
|
|
|
.map_err(|e| eyre!(e))?;
|
2020-07-09 23:51:01 -07:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
BeforeGenesis
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(0)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
/// SPANDOC: Make sure the verifier service is ready
|
2021-11-02 11:46:57 -07:00
|
|
|
let ready_verifier_service = checkpoint_verifier.ready().map_err(|e| eyre!(e)).await?;
|
2020-07-09 23:51:01 -07:00
|
|
|
/// SPANDOC: Set up the future for block 0
|
|
|
|
let verify_future = timeout(
|
|
|
|
Duration::from_secs(VERIFY_TIMEOUT_SECONDS),
|
|
|
|
ready_verifier_service.call(block0.clone()),
|
|
|
|
);
|
|
|
|
/// SPANDOC: Wait for the response for block 0
|
|
|
|
// TODO(teor || jlusby): check error kind
|
|
|
|
let verify_response = verify_future
|
|
|
|
.map_err(|e| eyre!(e))
|
|
|
|
.await
|
|
|
|
.expect("timeout should not happen")
|
|
|
|
.expect("block should verify");
|
|
|
|
|
|
|
|
assert_eq!(verify_response, hash0);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
FinalCheckpoint
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
FinishedVerifying
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(0)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn multi_item_checkpoint_list_test() -> Result<(), Report> {
|
|
|
|
multi_item_checkpoint_list().await
|
|
|
|
}
|
|
|
|
|
|
|
|
#[spandoc::spandoc]
|
|
|
|
async fn multi_item_checkpoint_list() -> Result<(), Report> {
|
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
// Parse all the blocks
|
|
|
|
let mut checkpoint_data = Vec::new();
|
|
|
|
for b in &[
|
2020-07-09 23:33:43 -07:00
|
|
|
// This list is used as a checkpoint list, and as a list of blocks to
|
|
|
|
// verify. So it must be continuous.
|
2020-07-09 23:51:01 -07:00
|
|
|
&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..],
|
|
|
|
&zebra_test::vectors::BLOCK_MAINNET_1_BYTES[..],
|
|
|
|
] {
|
|
|
|
let block = Arc::<Block>::zcash_deserialize(*b)?;
|
2020-08-15 23:20:01 -07:00
|
|
|
let hash = block.hash();
|
2020-07-09 23:51:01 -07:00
|
|
|
checkpoint_data.push((block.clone(), block.coinbase_height().unwrap(), hash));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a checkpoint list containing all the blocks
|
2020-08-16 11:42:02 -07:00
|
|
|
let checkpoint_list: BTreeMap<block::Height, block::Hash> = checkpoint_data
|
2020-07-09 23:51:01 -07:00
|
|
|
.iter()
|
|
|
|
.map(|(_block, height, hash)| (*height, *hash))
|
|
|
|
.collect();
|
|
|
|
|
2021-07-28 16:55:01 -07:00
|
|
|
let state_service = zebra_state::init_test(Mainnet);
|
2020-07-15 02:51:54 -07:00
|
|
|
let mut checkpoint_verifier =
|
2021-03-10 18:07:37 -08:00
|
|
|
CheckpointVerifier::from_list(checkpoint_list, Mainnet, None, state_service)
|
2020-09-02 21:23:57 -07:00
|
|
|
.map_err(|e| eyre!(e))?;
|
2020-07-09 23:51:01 -07:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
BeforeGenesis
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(1)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
// Now verify each block
|
|
|
|
for (block, height, hash) in checkpoint_data {
|
|
|
|
/// SPANDOC: Make sure the verifier service is ready
|
2021-11-02 11:46:57 -07:00
|
|
|
let ready_verifier_service = checkpoint_verifier.ready().map_err(|e| eyre!(e)).await?;
|
2020-07-09 23:51:01 -07:00
|
|
|
|
|
|
|
/// SPANDOC: Set up the future for block {?height}
|
|
|
|
let verify_future = timeout(
|
|
|
|
Duration::from_secs(VERIFY_TIMEOUT_SECONDS),
|
|
|
|
ready_verifier_service.call(block.clone()),
|
|
|
|
);
|
|
|
|
/// SPANDOC: Wait for the response for block {?height}
|
|
|
|
// TODO(teor || jlusby): check error kind
|
|
|
|
let verify_response = verify_future
|
|
|
|
.map_err(|e| eyre!(e))
|
|
|
|
.await
|
|
|
|
.expect("timeout should not happen")
|
|
|
|
.expect("future should succeed");
|
|
|
|
|
|
|
|
assert_eq!(verify_response, hash);
|
|
|
|
|
|
|
|
if height < checkpoint_verifier.checkpoint_list.max_height() {
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
PreviousCheckpoint(height)
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
FinalCheckpoint
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
FinishedVerifying
|
|
|
|
);
|
|
|
|
}
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(1)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
FinalCheckpoint
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
FinishedVerifying
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(1)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2021-03-01 22:22:23 -08:00
|
|
|
#[tokio::test]
|
2021-03-01 22:22:50 -08:00
|
|
|
async fn continuous_blockchain_no_restart() -> Result<(), Report> {
|
2021-03-01 23:11:08 -08:00
|
|
|
continuous_blockchain(None, Mainnet).await?;
|
|
|
|
continuous_blockchain(None, Testnet).await?;
|
2021-03-01 22:22:50 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn continuous_blockchain_restart() -> Result<(), Report> {
|
2021-03-02 22:01:39 -08:00
|
|
|
for height in 0..zebra_test::vectors::CONTINUOUS_MAINNET_BLOCKS.len() {
|
|
|
|
continuous_blockchain(Some(block::Height(height.try_into().unwrap())), Mainnet).await?;
|
2021-03-01 23:11:08 -08:00
|
|
|
}
|
2021-03-02 22:01:39 -08:00
|
|
|
for height in 0..zebra_test::vectors::CONTINUOUS_TESTNET_BLOCKS.len() {
|
|
|
|
continuous_blockchain(Some(block::Height(height.try_into().unwrap())), Testnet).await?;
|
2020-07-23 18:47:48 -07:00
|
|
|
}
|
|
|
|
Ok(())
|
2020-07-13 09:29:21 -07:00
|
|
|
}
|
|
|
|
|
2021-03-01 23:11:08 -08:00
|
|
|
/// Test a continuous blockchain on `network`, restarting verification at `restart_height`.
|
2020-07-13 09:29:21 -07:00
|
|
|
#[spandoc::spandoc]
|
2021-03-01 23:11:08 -08:00
|
|
|
async fn continuous_blockchain(
|
|
|
|
restart_height: Option<block::Height>,
|
|
|
|
network: Network,
|
|
|
|
) -> Result<(), Report> {
|
2020-07-13 09:29:21 -07:00
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
// A continuous blockchain
|
2021-03-01 23:11:08 -08:00
|
|
|
let blockchain = match network {
|
|
|
|
Mainnet => zebra_test::vectors::CONTINUOUS_MAINNET_BLOCKS.iter(),
|
|
|
|
Testnet => zebra_test::vectors::CONTINUOUS_TESTNET_BLOCKS.iter(),
|
|
|
|
};
|
|
|
|
let blockchain: Vec<_> = blockchain
|
|
|
|
.map(|(height, b)| {
|
|
|
|
let block = Arc::<Block>::zcash_deserialize(*b).unwrap();
|
|
|
|
let hash = block.hash();
|
|
|
|
let coinbase_height = block.coinbase_height().unwrap();
|
|
|
|
assert_eq!(*height, coinbase_height.0);
|
|
|
|
(block, coinbase_height, hash)
|
|
|
|
})
|
|
|
|
.collect();
|
2021-03-01 22:22:50 -08:00
|
|
|
let blockchain_len = blockchain.len();
|
2020-07-13 09:29:21 -07:00
|
|
|
|
2021-03-01 23:11:08 -08:00
|
|
|
// Use some of the blocks as checkpoints
|
2021-03-02 22:01:39 -08:00
|
|
|
// We use these indexes so that we test:
|
|
|
|
// - checkpoints don't have to be the same length
|
|
|
|
// - checkpoints start at genesis
|
|
|
|
// - checkpoints end at the end of the range (there's no point in having extra blocks)
|
|
|
|
let expected_max_height = block::Height((blockchain_len - 1).try_into().unwrap());
|
|
|
|
let checkpoint_list = vec![
|
|
|
|
&blockchain[0],
|
|
|
|
&blockchain[blockchain_len / 3],
|
|
|
|
&blockchain[blockchain_len / 2],
|
|
|
|
&blockchain[blockchain_len - 1],
|
|
|
|
];
|
2021-03-01 23:11:08 -08:00
|
|
|
let checkpoint_list: BTreeMap<block::Height, block::Hash> = checkpoint_list
|
2020-07-13 09:29:21 -07:00
|
|
|
.iter()
|
|
|
|
.map(|(_block, height, hash)| (*height, *hash))
|
|
|
|
.collect();
|
|
|
|
|
2021-03-01 23:11:08 -08:00
|
|
|
/// SPANDOC: Verify blocks, restarting at {?restart_height} {?network}
|
2020-07-23 18:47:48 -07:00
|
|
|
{
|
2020-09-10 10:52:51 -07:00
|
|
|
let initial_tip = restart_height.map(|block::Height(height)| {
|
|
|
|
(blockchain[height as usize].1, blockchain[height as usize].2)
|
|
|
|
});
|
2021-07-28 16:55:01 -07:00
|
|
|
let state_service = zebra_state::init_test(Mainnet);
|
2021-03-10 18:07:37 -08:00
|
|
|
let mut checkpoint_verifier = CheckpointVerifier::from_list(
|
|
|
|
checkpoint_list,
|
|
|
|
network,
|
|
|
|
initial_tip,
|
|
|
|
state_service.clone(),
|
|
|
|
)
|
|
|
|
.map_err(|e| eyre!(e))?;
|
2020-07-23 18:47:48 -07:00
|
|
|
|
|
|
|
// Setup checks
|
2021-03-02 22:01:39 -08:00
|
|
|
if restart_height.is_some() {
|
|
|
|
assert!(
|
|
|
|
restart_height <= Some(checkpoint_verifier.checkpoint_list.max_height()),
|
|
|
|
"restart heights after the final checkpoint are not supported by this test"
|
|
|
|
);
|
|
|
|
}
|
2020-07-23 18:47:48 -07:00
|
|
|
if restart_height
|
2021-03-02 22:01:39 -08:00
|
|
|
.map(|h| h == checkpoint_verifier.checkpoint_list.max_height())
|
2020-07-23 18:47:48 -07:00
|
|
|
.unwrap_or(false)
|
|
|
|
{
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
FinalCheckpoint
|
|
|
|
);
|
2020-07-13 09:29:21 -07:00
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
2020-07-23 18:47:48 -07:00
|
|
|
FinishedVerifying
|
2020-07-13 09:29:21 -07:00
|
|
|
);
|
|
|
|
} else {
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
2020-07-23 18:47:48 -07:00
|
|
|
restart_height.map(InitialTip).unwrap_or(BeforeGenesis)
|
2020-07-13 09:29:21 -07:00
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
2020-07-23 18:47:48 -07:00
|
|
|
WaitingForBlocks
|
2020-07-13 09:29:21 -07:00
|
|
|
);
|
|
|
|
}
|
2020-07-23 18:47:48 -07:00
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2021-03-02 22:01:39 -08:00
|
|
|
expected_max_height
|
2020-07-23 18:47:48 -07:00
|
|
|
);
|
2020-07-13 09:29:21 -07:00
|
|
|
|
2020-07-23 18:47:48 -07:00
|
|
|
let mut handles = FuturesUnordered::new();
|
|
|
|
|
|
|
|
// Now verify each block
|
|
|
|
for (block, height, _hash) in blockchain {
|
2021-03-01 22:22:23 -08:00
|
|
|
// Commit directly to the state until after the (fake) restart height
|
2020-07-23 18:47:48 -07:00
|
|
|
if let Some(restart_height) = restart_height {
|
|
|
|
if height <= restart_height {
|
2020-09-04 02:34:40 -07:00
|
|
|
let mut state_service = state_service.clone();
|
|
|
|
/// SPANDOC: Make sure the state service is ready for block {?height}
|
2021-11-02 11:46:57 -07:00
|
|
|
let ready_state_service = state_service.ready().map_err(|e| eyre!(e)).await?;
|
2020-09-04 02:34:40 -07:00
|
|
|
|
2021-03-01 22:22:23 -08:00
|
|
|
/// SPANDOC: Add block directly to the state {?height}
|
2020-09-04 02:34:40 -07:00
|
|
|
ready_state_service
|
state: introduce PreparedBlock, FinalizedBlock
This change introduces two new types:
- `PreparedBlock`, representing a block which has undergone semantic
validation and has been prepared for contextual validation;
- `FinalizedBlock`, representing a block which is ready to be finalized
immediately;
and changes the `Request::CommitBlock`,`Request::CommitFinalizedBlock`
variants to use these types instead of their previous fields.
This change solves the problem of passing data between semantic
validation and contextual validation, and cleans up the state code by
allowing it to pass around a bundle of data. Previously, the state code
just passed around an `Arc<Block>`, which forced it to needlessly
recompute block hashes and other data, and was incompatible with the
already-known but not-yet-implemented data transfer requirements, namely
passing in the Sprout and Sapling anchors computed during contextual
validation.
This commit propagates the `PreparedBlock` and `FinalizedBlock` types
through the state code but only uses their data opportunistically, e.g.,
changing .hash() computations to use the precomputed hash. In the
future, these structures can be extended to pass data through the
verification pipeline for reuse as appropriate. For instance, these
changes allow the sprout and sapling anchors to be propagated through
the state.
2020-11-21 01:16:14 -08:00
|
|
|
.call(zebra_state::Request::CommitFinalizedBlock(
|
|
|
|
block.clone().into(),
|
|
|
|
))
|
2020-09-04 02:34:40 -07:00
|
|
|
.await
|
|
|
|
.map_err(|e| eyre!(e))?;
|
2021-03-01 22:22:23 -08:00
|
|
|
|
|
|
|
// Skip verification for (fake) previous blocks
|
|
|
|
continue;
|
2020-07-23 18:47:48 -07:00
|
|
|
}
|
|
|
|
}
|
2021-03-01 22:22:23 -08:00
|
|
|
|
2020-07-23 20:17:39 -07:00
|
|
|
/// SPANDOC: Make sure the verifier service is ready for block {?height}
|
2021-11-02 11:46:57 -07:00
|
|
|
let ready_verifier_service = checkpoint_verifier.ready().map_err(|e| eyre!(e)).await?;
|
2020-07-23 18:47:48 -07:00
|
|
|
|
|
|
|
/// SPANDOC: Set up the future for block {?height}
|
|
|
|
let verify_future = timeout(
|
|
|
|
Duration::from_secs(VERIFY_TIMEOUT_SECONDS),
|
|
|
|
ready_verifier_service.call(block.clone()),
|
|
|
|
);
|
2020-07-13 09:29:21 -07:00
|
|
|
|
2020-07-23 20:17:39 -07:00
|
|
|
/// SPANDOC: spawn verification future in the background for block {?height}
|
2020-07-23 18:47:48 -07:00
|
|
|
let handle = tokio::spawn(verify_future.in_current_span());
|
|
|
|
handles.push(handle);
|
|
|
|
|
|
|
|
// Execution checks
|
|
|
|
if height < checkpoint_verifier.checkpoint_list.max_height() {
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
FinalCheckpoint
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
FinishedVerifying
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-01 22:22:50 -08:00
|
|
|
// Check that we have the correct number of verify tasks
|
|
|
|
if let Some(block::Height(restart_height)) = restart_height {
|
|
|
|
let restart_height = restart_height as usize;
|
2021-03-02 22:01:39 -08:00
|
|
|
if restart_height == blockchain_len - 1 {
|
2021-03-01 22:22:50 -08:00
|
|
|
assert_eq!(
|
|
|
|
handles.len(),
|
|
|
|
0,
|
|
|
|
"unexpected number of verify tasks for restart height: {:?}",
|
|
|
|
restart_height,
|
|
|
|
);
|
|
|
|
} else {
|
|
|
|
assert_eq!(
|
|
|
|
handles.len(),
|
2021-03-02 22:01:39 -08:00
|
|
|
blockchain_len - restart_height - 1,
|
2021-03-01 22:22:50 -08:00
|
|
|
"unexpected number of verify tasks for restart height: {:?}",
|
|
|
|
restart_height,
|
|
|
|
);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
assert_eq!(
|
|
|
|
handles.len(),
|
2021-03-02 22:01:39 -08:00
|
|
|
blockchain_len,
|
2021-03-01 22:22:50 -08:00
|
|
|
"unexpected number of verify tasks with no restart height",
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-03-01 23:11:08 -08:00
|
|
|
/// SPANDOC: wait on spawned verification tasks for restart height {?restart_height} {?network}
|
2020-07-23 18:47:48 -07:00
|
|
|
while let Some(result) = handles.next().await {
|
|
|
|
result??.map_err(|e| eyre!(e))?;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Final checks
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
2021-03-01 22:22:50 -08:00
|
|
|
FinalCheckpoint,
|
|
|
|
"unexpected previous checkpoint for restart height: {:?}",
|
|
|
|
restart_height,
|
2020-07-23 18:47:48 -07:00
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
2021-03-01 22:22:50 -08:00
|
|
|
FinishedVerifying,
|
|
|
|
"unexpected target checkpoint for restart height: {:?}",
|
|
|
|
restart_height,
|
2020-07-23 18:47:48 -07:00
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2021-03-02 22:01:39 -08:00
|
|
|
expected_max_height,
|
2021-03-01 22:22:50 -08:00
|
|
|
"unexpected max checkpoint height for restart height: {:?}",
|
|
|
|
restart_height,
|
2020-07-23 18:47:48 -07:00
|
|
|
);
|
|
|
|
}
|
2020-07-13 09:29:21 -07:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2020-07-09 23:51:01 -07:00
|
|
|
#[tokio::test]
|
|
|
|
async fn block_higher_than_max_checkpoint_fail_test() -> Result<(), Report> {
|
|
|
|
block_higher_than_max_checkpoint_fail().await
|
|
|
|
}
|
|
|
|
|
|
|
|
#[spandoc::spandoc]
|
|
|
|
async fn block_higher_than_max_checkpoint_fail() -> Result<(), Report> {
|
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
let block0 =
|
|
|
|
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])?;
|
|
|
|
let block415000 =
|
|
|
|
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..])?;
|
|
|
|
|
|
|
|
// Make a checkpoint list containing only the genesis block
|
2020-08-16 11:42:02 -07:00
|
|
|
let genesis_checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
2020-07-09 23:51:01 -07:00
|
|
|
[(block0.coinbase_height().unwrap(), block0.as_ref().into())]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect();
|
|
|
|
|
2021-07-28 16:55:01 -07:00
|
|
|
let state_service = zebra_state::init_test(Mainnet);
|
2020-07-09 23:51:01 -07:00
|
|
|
let mut checkpoint_verifier =
|
2021-03-10 18:07:37 -08:00
|
|
|
CheckpointVerifier::from_list(genesis_checkpoint_list, Mainnet, None, state_service)
|
2020-09-02 21:23:57 -07:00
|
|
|
.map_err(|e| eyre!(e))?;
|
2020-07-09 23:51:01 -07:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
BeforeGenesis
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(0)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
/// SPANDOC: Make sure the verifier service is ready
|
2021-11-02 11:46:57 -07:00
|
|
|
let ready_verifier_service = checkpoint_verifier.ready().map_err(|e| eyre!(e)).await?;
|
2020-07-09 23:51:01 -07:00
|
|
|
/// SPANDOC: Set up the future for block 415000
|
|
|
|
let verify_future = timeout(
|
|
|
|
Duration::from_secs(VERIFY_TIMEOUT_SECONDS),
|
|
|
|
ready_verifier_service.call(block415000.clone()),
|
|
|
|
);
|
|
|
|
/// SPANDOC: Wait for the response for block 415000, and expect failure
|
|
|
|
// TODO(teor || jlusby): check error kind
|
|
|
|
let _ = verify_future
|
|
|
|
.map_err(|e| eyre!(e))
|
|
|
|
.await
|
|
|
|
.expect("timeout should not happen")
|
|
|
|
.expect_err("bad block hash should fail");
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
BeforeGenesis
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(0)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn wrong_checkpoint_hash_fail_test() -> Result<(), Report> {
|
|
|
|
wrong_checkpoint_hash_fail().await
|
|
|
|
}
|
|
|
|
|
|
|
|
#[spandoc::spandoc]
|
|
|
|
async fn wrong_checkpoint_hash_fail() -> Result<(), Report> {
|
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
let good_block0 =
|
|
|
|
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])?;
|
2020-08-15 23:20:01 -07:00
|
|
|
let good_block0_hash = good_block0.hash();
|
2020-07-09 23:51:01 -07:00
|
|
|
// Change the header hash
|
|
|
|
let mut bad_block0 = good_block0.clone();
|
|
|
|
let mut bad_block0 = Arc::make_mut(&mut bad_block0);
|
|
|
|
bad_block0.header.version = 0;
|
|
|
|
let bad_block0: Arc<Block> = bad_block0.clone().into();
|
|
|
|
|
|
|
|
// Make a checkpoint list containing the genesis block checkpoint
|
2020-08-16 11:42:02 -07:00
|
|
|
let genesis_checkpoint_list: BTreeMap<block::Height, block::Hash> =
|
2020-07-09 23:51:01 -07:00
|
|
|
[(good_block0.coinbase_height().unwrap(), good_block0_hash)]
|
|
|
|
.iter()
|
|
|
|
.cloned()
|
|
|
|
.collect();
|
|
|
|
|
2021-07-28 16:55:01 -07:00
|
|
|
let state_service = zebra_state::init_test(Mainnet);
|
2020-07-09 23:51:01 -07:00
|
|
|
let mut checkpoint_verifier =
|
2021-03-10 18:07:37 -08:00
|
|
|
CheckpointVerifier::from_list(genesis_checkpoint_list, Mainnet, None, state_service)
|
2020-09-02 21:23:57 -07:00
|
|
|
.map_err(|e| eyre!(e))?;
|
2020-07-09 23:51:01 -07:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
BeforeGenesis
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(0)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
/// SPANDOC: Make sure the verifier service is ready (1/3)
|
2021-11-02 11:46:57 -07:00
|
|
|
let ready_verifier_service = checkpoint_verifier.ready().map_err(|e| eyre!(e)).await?;
|
2020-07-09 23:51:01 -07:00
|
|
|
/// SPANDOC: Set up the future for bad block 0 (1/3)
|
|
|
|
// TODO(teor || jlusby): check error kind
|
|
|
|
let bad_verify_future_1 = timeout(
|
|
|
|
Duration::from_secs(VERIFY_TIMEOUT_SECONDS),
|
|
|
|
ready_verifier_service.call(bad_block0.clone()),
|
|
|
|
);
|
|
|
|
// We can't await the future yet, because bad blocks aren't cleared
|
|
|
|
// until the chain is verified
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
BeforeGenesis
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(0)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
/// SPANDOC: Make sure the verifier service is ready (2/3)
|
2021-11-02 11:46:57 -07:00
|
|
|
let ready_verifier_service = checkpoint_verifier.ready().map_err(|e| eyre!(e)).await?;
|
2020-07-09 23:51:01 -07:00
|
|
|
/// SPANDOC: Set up the future for bad block 0 again (2/3)
|
|
|
|
// TODO(teor || jlusby): check error kind
|
|
|
|
let bad_verify_future_2 = timeout(
|
|
|
|
Duration::from_secs(VERIFY_TIMEOUT_SECONDS),
|
|
|
|
ready_verifier_service.call(bad_block0.clone()),
|
|
|
|
);
|
|
|
|
// We can't await the future yet, because bad blocks aren't cleared
|
|
|
|
// until the chain is verified
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
BeforeGenesis
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(0)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
/// SPANDOC: Make sure the verifier service is ready (3/3)
|
2021-11-02 11:46:57 -07:00
|
|
|
let ready_verifier_service = checkpoint_verifier.ready().map_err(|e| eyre!(e)).await?;
|
2020-07-09 23:51:01 -07:00
|
|
|
/// SPANDOC: Set up the future for good block 0 (3/3)
|
|
|
|
let good_verify_future = timeout(
|
|
|
|
Duration::from_secs(VERIFY_TIMEOUT_SECONDS),
|
|
|
|
ready_verifier_service.call(good_block0.clone()),
|
|
|
|
);
|
|
|
|
/// SPANDOC: Wait for the response for good block 0, and expect success (3/3)
|
|
|
|
// TODO(teor || jlusby): check error kind
|
|
|
|
let verify_response = good_verify_future
|
|
|
|
.map_err(|e| eyre!(e))
|
|
|
|
.await
|
|
|
|
.expect("timeout should not happen")
|
|
|
|
.expect("future should succeed");
|
|
|
|
|
|
|
|
assert_eq!(verify_response, good_block0_hash);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
FinalCheckpoint
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
FinishedVerifying
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(0)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
// Now, await the bad futures, which should have completed
|
|
|
|
|
|
|
|
/// SPANDOC: Wait for the response for block 0, and expect failure (1/3)
|
|
|
|
// TODO(teor || jlusby): check error kind
|
|
|
|
let _ = bad_verify_future_1
|
|
|
|
.map_err(|e| eyre!(e))
|
|
|
|
.await
|
|
|
|
.expect("timeout should not happen")
|
|
|
|
.expect_err("bad block hash should fail");
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
FinalCheckpoint
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
FinishedVerifying
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(0)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
/// SPANDOC: Wait for the response for block 0, and expect failure again (2/3)
|
|
|
|
// TODO(teor || jlusby): check error kind
|
|
|
|
let _ = bad_verify_future_2
|
|
|
|
.map_err(|e| eyre!(e))
|
|
|
|
.await
|
|
|
|
.expect("timeout should not happen")
|
|
|
|
.expect_err("bad block hash should fail");
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
FinalCheckpoint
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
FinishedVerifying
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(0)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn checkpoint_drop_cancel_test() -> Result<(), Report> {
|
|
|
|
checkpoint_drop_cancel().await
|
|
|
|
}
|
|
|
|
|
|
|
|
#[spandoc::spandoc]
|
|
|
|
async fn checkpoint_drop_cancel() -> Result<(), Report> {
|
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
// Parse all the blocks
|
|
|
|
let mut checkpoint_data = Vec::new();
|
|
|
|
for b in &[
|
2020-07-09 23:33:43 -07:00
|
|
|
// Continous blocks are verified
|
2020-07-09 23:51:01 -07:00
|
|
|
&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..],
|
|
|
|
&zebra_test::vectors::BLOCK_MAINNET_1_BYTES[..],
|
2020-07-09 23:33:43 -07:00
|
|
|
// Other blocks can't verify, so they are rejected on drop
|
2020-07-09 23:51:01 -07:00
|
|
|
&zebra_test::vectors::BLOCK_MAINNET_415000_BYTES[..],
|
|
|
|
&zebra_test::vectors::BLOCK_MAINNET_434873_BYTES[..],
|
|
|
|
] {
|
|
|
|
let block = Arc::<Block>::zcash_deserialize(*b)?;
|
2020-08-15 23:20:01 -07:00
|
|
|
let hash = block.hash();
|
2020-07-09 23:51:01 -07:00
|
|
|
checkpoint_data.push((block.clone(), block.coinbase_height().unwrap(), hash));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Make a checkpoint list containing all the blocks
|
2020-08-16 11:42:02 -07:00
|
|
|
let checkpoint_list: BTreeMap<block::Height, block::Hash> = checkpoint_data
|
2020-07-09 23:51:01 -07:00
|
|
|
.iter()
|
|
|
|
.map(|(_block, height, hash)| (*height, *hash))
|
|
|
|
.collect();
|
|
|
|
|
2021-07-28 16:55:01 -07:00
|
|
|
let state_service = zebra_state::init_test(Mainnet);
|
2020-07-15 02:51:54 -07:00
|
|
|
let mut checkpoint_verifier =
|
2021-03-10 18:07:37 -08:00
|
|
|
CheckpointVerifier::from_list(checkpoint_list, Mainnet, None, state_service)
|
2020-09-02 21:23:57 -07:00
|
|
|
.map_err(|e| eyre!(e))?;
|
2020-07-09 23:51:01 -07:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
BeforeGenesis
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(434873)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
|
|
|
|
let mut futures = Vec::new();
|
|
|
|
// Now collect verify futures for each block
|
|
|
|
for (block, height, hash) in checkpoint_data {
|
|
|
|
/// SPANDOC: Make sure the verifier service is ready
|
2021-11-02 11:46:57 -07:00
|
|
|
let ready_verifier_service = checkpoint_verifier.ready().map_err(|e| eyre!(e)).await?;
|
2020-07-09 23:51:01 -07:00
|
|
|
|
|
|
|
/// SPANDOC: Set up the future for block {?height}
|
|
|
|
let verify_future = timeout(
|
|
|
|
Duration::from_secs(VERIFY_TIMEOUT_SECONDS),
|
|
|
|
ready_verifier_service.call(block.clone()),
|
|
|
|
);
|
|
|
|
|
|
|
|
futures.push((verify_future, height, hash));
|
|
|
|
|
|
|
|
// Only continuous checkpoints verify
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
PreviousCheckpoint(block::Height(min(height.0, 1)))
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.checkpoint_list.max_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
block::Height(434873)
|
2020-07-09 23:51:01 -07:00
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now drop the verifier, to cancel the futures
|
|
|
|
drop(checkpoint_verifier);
|
|
|
|
|
|
|
|
for (verify_future, height, hash) in futures {
|
|
|
|
/// SPANDOC: Check the response for block {?height}
|
|
|
|
let verify_response = verify_future
|
|
|
|
.map_err(|e| eyre!(e))
|
|
|
|
.await
|
|
|
|
.expect("timeout should not happen");
|
|
|
|
|
2020-08-16 11:42:02 -07:00
|
|
|
if height <= block::Height(1) {
|
2020-07-09 23:51:01 -07:00
|
|
|
let verify_hash =
|
|
|
|
verify_response.expect("Continuous checkpoints should have succeeded before drop");
|
|
|
|
assert_eq!(verify_hash, hash);
|
|
|
|
} else {
|
|
|
|
// TODO(teor || jlusby): check error kind
|
|
|
|
verify_response.expect_err("Pending futures should fail on drop");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-07-21 06:11:51 -07:00
|
|
|
|
|
|
|
#[tokio::test]
|
|
|
|
async fn hard_coded_mainnet_test() -> Result<(), Report> {
|
|
|
|
hard_coded_mainnet().await
|
|
|
|
}
|
|
|
|
|
|
|
|
#[spandoc::spandoc]
|
|
|
|
async fn hard_coded_mainnet() -> Result<(), Report> {
|
|
|
|
zebra_test::init();
|
|
|
|
|
|
|
|
let block0 =
|
|
|
|
Arc::<Block>::zcash_deserialize(&zebra_test::vectors::BLOCK_MAINNET_GENESIS_BYTES[..])?;
|
2020-08-15 23:20:01 -07:00
|
|
|
let hash0 = block0.hash();
|
2020-07-21 06:11:51 -07:00
|
|
|
|
2021-07-28 16:55:01 -07:00
|
|
|
let state_service = zebra_state::init_test(Mainnet);
|
2020-07-21 06:11:51 -07:00
|
|
|
// Use the hard-coded checkpoint list
|
2020-09-02 21:23:57 -07:00
|
|
|
let mut checkpoint_verifier = CheckpointVerifier::new(Network::Mainnet, None, state_service);
|
2020-07-21 06:11:51 -07:00
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
|
|
|
BeforeGenesis
|
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
2020-08-16 11:42:02 -07:00
|
|
|
assert!(checkpoint_verifier.checkpoint_list.max_height() > block::Height(0));
|
2020-07-21 06:11:51 -07:00
|
|
|
|
|
|
|
/// SPANDOC: Make sure the verifier service is ready
|
2021-11-02 11:46:57 -07:00
|
|
|
let ready_verifier_service = checkpoint_verifier.ready().map_err(|e| eyre!(e)).await?;
|
2020-07-21 06:11:51 -07:00
|
|
|
/// SPANDOC: Set up the future for block 0
|
|
|
|
let verify_future = timeout(
|
|
|
|
Duration::from_secs(VERIFY_TIMEOUT_SECONDS),
|
|
|
|
ready_verifier_service.call(block0.clone()),
|
|
|
|
);
|
|
|
|
/// SPANDOC: Wait for the response for block 0
|
|
|
|
// TODO(teor || jlusby): check error kind
|
|
|
|
let verify_response = verify_future
|
|
|
|
.map_err(|e| eyre!(e))
|
|
|
|
.await
|
|
|
|
.expect("timeout should not happen")
|
|
|
|
.expect("block should verify");
|
|
|
|
|
|
|
|
assert_eq!(verify_response, hash0);
|
|
|
|
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.previous_checkpoint_height(),
|
2020-08-16 11:42:02 -07:00
|
|
|
PreviousCheckpoint(block::Height(0))
|
2020-07-21 06:11:51 -07:00
|
|
|
);
|
|
|
|
assert_eq!(
|
|
|
|
checkpoint_verifier.target_checkpoint_height(),
|
|
|
|
WaitingForBlocks
|
|
|
|
);
|
|
|
|
// The lists will get bigger over time, so we just pick a recent height
|
2020-08-16 11:42:02 -07:00
|
|
|
assert!(checkpoint_verifier.checkpoint_list.max_height() > block::Height(900_000));
|
2020-07-21 06:11:51 -07:00
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|