use std::sync::Arc;
use zebra_chain::{
amount::Amount,
block::{self, Block},
transaction::Transaction,
transparent,
value_balance::ValueBalance,
};
use crate::{
request::ContextuallyVerifiedBlock, service::chain_tip::ChainTipBlock,
SemanticallyVerifiedBlock,
};
pub trait Prepare {
fn prepare(self) -> SemanticallyVerifiedBlock;
}
impl Prepare for Arc<Block> {
fn prepare(self) -> SemanticallyVerifiedBlock {
let block = self;
let hash = block.hash();
let height = block.coinbase_height().unwrap();
let transaction_hashes: Arc<[_]> = block.transactions.iter().map(|tx| tx.hash()).collect();
let new_outputs =
transparent::new_ordered_outputs_with_height(&block, height, &transaction_hashes);
SemanticallyVerifiedBlock {
block,
hash,
height,
new_outputs,
transaction_hashes,
deferred_balance: None,
}
}
}
impl<T> From<T> for ChainTipBlock
where
T: Prepare,
{
fn from(block: T) -> Self {
block.prepare().into()
}
}
impl SemanticallyVerifiedBlock {
#[cfg(test)]
pub fn test_with_zero_spent_utxos(&self) -> ContextuallyVerifiedBlock {
ContextuallyVerifiedBlock::test_with_zero_spent_utxos(self)
}
#[cfg(test)]
pub fn test_with_zero_chain_pool_change(&self) -> ContextuallyVerifiedBlock {
ContextuallyVerifiedBlock::test_with_zero_chain_pool_change(self)
}
}
impl ContextuallyVerifiedBlock {
pub fn test_with_zero_spent_utxos(block: impl Into<SemanticallyVerifiedBlock>) -> Self {
let block = block.into();
let zero_output = transparent::Output {
value: Amount::zero(),
lock_script: transparent::Script::new(&[]),
};
let zero_utxo = transparent::OrderedUtxo::new(zero_output, block::Height(1), 1);
let zero_spent_utxos = block
.block
.transactions
.iter()
.map(AsRef::as_ref)
.flat_map(Transaction::inputs)
.flat_map(transparent::Input::outpoint)
.map(|outpoint| (outpoint, zero_utxo.clone()))
.collect();
ContextuallyVerifiedBlock::with_block_and_spent_utxos(block, zero_spent_utxos)
.expect("all UTXOs are provided with zero values")
}
pub fn test_with_zero_chain_pool_change(block: impl Into<SemanticallyVerifiedBlock>) -> Self {
let SemanticallyVerifiedBlock {
block,
hash,
height,
new_outputs,
transaction_hashes,
deferred_balance: _,
} = block.into();
Self {
block,
hash,
height,
new_outputs: new_outputs.clone(),
spent_outputs: new_outputs,
transaction_hashes,
chain_value_pool_change: ValueBalance::zero(),
}
}
}