zebra_state/
arbitrary.rs

1//! Randomised data generation for state data.
2
3use std::sync::Arc;
4
5use zebra_chain::{
6    amount::Amount,
7    block::{self, Block},
8    transaction::Transaction,
9    transparent,
10    value_balance::ValueBalance,
11};
12
13use crate::{
14    request::ContextuallyVerifiedBlock, service::chain_tip::ChainTipBlock,
15    SemanticallyVerifiedBlock,
16};
17
18/// Mocks computation done during semantic validation
19pub trait Prepare {
20    /// Runs block semantic validation computation, and returns the result.
21    /// Test-only method.
22    fn prepare(self) -> SemanticallyVerifiedBlock;
23}
24
25impl Prepare for Arc<Block> {
26    fn prepare(self) -> SemanticallyVerifiedBlock {
27        let block = self;
28        let hash = block.hash();
29        let height = block.coinbase_height().unwrap();
30        let transaction_hashes: Arc<[_]> = block.transactions.iter().map(|tx| tx.hash()).collect();
31        let new_outputs =
32            transparent::new_ordered_outputs_with_height(&block, height, &transaction_hashes);
33
34        SemanticallyVerifiedBlock {
35            block,
36            hash,
37            height,
38            new_outputs,
39            transaction_hashes,
40            deferred_balance: None,
41        }
42    }
43}
44
45impl<T> From<T> for ChainTipBlock
46where
47    T: Prepare,
48{
49    fn from(block: T) -> Self {
50        block.prepare().into()
51    }
52}
53
54impl SemanticallyVerifiedBlock {
55    /// Returns a [`ContextuallyVerifiedBlock`] created from this block,
56    /// with fake zero-valued spent UTXOs.
57    ///
58    /// Only for use in tests.
59    #[cfg(test)]
60    pub fn test_with_zero_spent_utxos(&self) -> ContextuallyVerifiedBlock {
61        ContextuallyVerifiedBlock::test_with_zero_spent_utxos(self)
62    }
63
64    /// Returns a [`ContextuallyVerifiedBlock`] created from this block,
65    /// with no chain value pool change.
66    ///
67    /// Only for use in tests.
68    #[cfg(test)]
69    pub fn test_with_zero_chain_pool_change(&self) -> ContextuallyVerifiedBlock {
70        ContextuallyVerifiedBlock::test_with_zero_chain_pool_change(self)
71    }
72}
73
74impl ContextuallyVerifiedBlock {
75    /// Create a block that's ready for non-finalized `Chain` contextual
76    /// validation, using a [`SemanticallyVerifiedBlock`] and fake zero-valued spent UTXOs.
77    ///
78    /// Only for use in tests.
79    pub fn test_with_zero_spent_utxos(block: impl Into<SemanticallyVerifiedBlock>) -> Self {
80        let block = block.into();
81
82        let zero_output = transparent::Output {
83            value: Amount::zero(),
84            lock_script: transparent::Script::new(&[]),
85        };
86
87        let zero_utxo = transparent::OrderedUtxo::new(zero_output, block::Height(1), 1);
88
89        let zero_spent_utxos = block
90            .block
91            .transactions
92            .iter()
93            .map(AsRef::as_ref)
94            .flat_map(Transaction::inputs)
95            .flat_map(transparent::Input::outpoint)
96            .map(|outpoint| (outpoint, zero_utxo.clone()))
97            .collect();
98
99        ContextuallyVerifiedBlock::with_block_and_spent_utxos(block, zero_spent_utxos)
100            .expect("all UTXOs are provided with zero values")
101    }
102
103    /// Create a [`ContextuallyVerifiedBlock`] from a [`Block`] or [`SemanticallyVerifiedBlock`],
104    /// with no chain value pool change.
105    ///
106    /// Only for use in tests.
107    pub fn test_with_zero_chain_pool_change(block: impl Into<SemanticallyVerifiedBlock>) -> Self {
108        let SemanticallyVerifiedBlock {
109            block,
110            hash,
111            height,
112            new_outputs,
113            transaction_hashes,
114            deferred_balance: _,
115        } = block.into();
116
117        Self {
118            block,
119            hash,
120            height,
121            new_outputs: new_outputs.clone(),
122            // Just re-use the outputs we created in this block, even though that's incorrect.
123            //
124            // TODO: fix the tests, and stop adding unrelated inputs and outputs.
125            spent_outputs: new_outputs,
126            transaction_hashes,
127            chain_value_pool_change: ValueBalance::zero(),
128        }
129    }
130}