use std::{iter, sync::Arc};
use chrono::Utc;
use futures::FutureExt;
use zakura_chain::{
block,
chain_tip::{ChainTip, NoChainTip},
parameters::Network::*,
};
use super::super::{ChainTipBlock, ChainTipSender};
fn tip(height: u32, hash_byte: u8, parent_byte: u8) -> ChainTipBlock {
ChainTipBlock {
hash: block::Hash([hash_byte; 32]),
height: block::Height(height),
time: Utc::now(),
transactions: Vec::new(),
transaction_hashes: Arc::from([]),
previous_block_hash: block::Hash([parent_byte; 32]),
}
}
#[test]
fn current_best_tip_is_initially_empty() {
let (_chain_tip_sender, latest_chain_tip, _chain_tip_change) =
ChainTipSender::new(None, &Mainnet);
assert_eq!(latest_chain_tip.best_tip_height(), None);
assert_eq!(latest_chain_tip.best_tip_hash(), None);
assert_eq!(
latest_chain_tip.best_tip_mined_transaction_ids(),
iter::empty().collect()
);
}
#[test]
fn empty_latest_chain_tip_is_empty() {
let latest_chain_tip = NoChainTip;
assert_eq!(latest_chain_tip.best_tip_height(), None);
assert_eq!(latest_chain_tip.best_tip_hash(), None);
assert_eq!(
latest_chain_tip.best_tip_mined_transaction_ids(),
iter::empty().collect()
);
}
#[test]
fn chain_tip_change_is_initially_not_ready() {
let (_chain_tip_sender, _latest_chain_tip, mut chain_tip_change) =
ChainTipSender::new(None, &Mainnet);
let first = chain_tip_change
.wait_for_tip_change()
.now_or_never()
.transpose()
.expect("watch sender is not dropped");
assert_eq!(first, None);
assert_eq!(chain_tip_change.last_tip_change(), None);
let first = chain_tip_change
.wait_for_tip_change()
.now_or_never()
.transpose()
.expect("watch sender is not dropped");
assert_eq!(first, None);
assert_eq!(chain_tip_change.last_tip_change(), None);
#[allow(clippy::redundant_clone)]
let first_clone = chain_tip_change
.clone()
.wait_for_tip_change()
.now_or_never()
.transpose()
.expect("watch sender is not dropped");
assert_eq!(first_clone, None);
assert_eq!(chain_tip_change.last_tip_change(), None);
}
#[test]
fn empty_non_finalized_state_returns_tip_publication_to_finalized() {
let initial = tip(10, 10, 9);
let non_finalized = tip(12, 12, 11);
let finalized = tip(11, 11, 10);
let (mut sender, latest, _) = ChainTipSender::new(initial, &Mainnet);
sender.set_best_non_finalized_tip(non_finalized.clone());
sender.set_finalized_tip(finalized.clone());
assert_eq!(latest.best_tip_hash(), Some(non_finalized.hash));
sender.clear_best_non_finalized_tip(finalized.clone());
assert_eq!(latest.best_tip_height(), Some(finalized.height));
assert_eq!(latest.best_tip_hash(), Some(finalized.hash));
}
#[test]
fn late_broadcast_completion_does_not_rewind_the_tip_cursor() {
let (mut sender, _, mut changes) = ChainTipSender::new(None, &Mainnet);
sender.set_best_non_finalized_tip(Some(tip(2, 2, 1)));
changes.mark_last_change_hash(block::Hash([2; 32]));
changes.mark_last_change_hash(block::Hash([1; 32]));
assert_eq!(changes.last_tip_change(), None);
sender.set_best_non_finalized_tip(Some(tip(3, 3, 2)));
assert_eq!(
changes
.last_tip_change()
.unwrap()
.best_tip_hash_and_height(),
(block::Hash([3; 32]), block::Height(3))
);
}