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        self.into()
28    }
29}
30
31impl<T> From<T> for ChainTipBlock
32where
33    T: Prepare,
34{
35    fn from(block: T) -> Self {
36        block.prepare().into()
37    }
38}
39
40impl SemanticallyVerifiedBlock {
41    /// Returns a [`ContextuallyVerifiedBlock`] created from this block,
42    /// with fake zero-valued spent UTXOs.
43    ///
44    /// Only for use in tests.
45    #[cfg(test)]
46    pub fn test_with_zero_spent_utxos(&self) -> ContextuallyVerifiedBlock {
47        ContextuallyVerifiedBlock::test_with_zero_spent_utxos(self)
48    }
49
50    /// Returns a [`ContextuallyVerifiedBlock`] created from this block,
51    /// with no chain value pool change.
52    ///
53    /// Only for use in tests.
54    #[cfg(test)]
55    pub fn test_with_zero_chain_pool_change(&self) -> ContextuallyVerifiedBlock {
56        ContextuallyVerifiedBlock::test_with_zero_chain_pool_change(self)
57    }
58}
59
60impl ContextuallyVerifiedBlock {
61    /// Create a block that's ready for non-finalized `Chain` contextual
62    /// validation, using a [`SemanticallyVerifiedBlock`] and fake zero-valued spent UTXOs.
63    ///
64    /// Only for use in tests.
65    pub fn test_with_zero_spent_utxos(block: impl Into<SemanticallyVerifiedBlock>) -> Self {
66        let block = block.into();
67
68        let zero_output = transparent::Output {
69            value: Amount::zero(),
70            lock_script: transparent::Script::new(&[]),
71        };
72
73        let zero_utxo = transparent::OrderedUtxo::new(zero_output, block::Height(1), 1);
74
75        let zero_spent_utxos = block
76            .block
77            .transactions
78            .iter()
79            .map(AsRef::as_ref)
80            .flat_map(Transaction::inputs)
81            .flat_map(transparent::Input::outpoint)
82            .map(|outpoint| (outpoint, zero_utxo.clone()))
83            .collect();
84
85        ContextuallyVerifiedBlock::with_block_and_spent_utxos(block, zero_spent_utxos)
86            .expect("all UTXOs are provided with zero values")
87    }
88
89    /// Create a [`ContextuallyVerifiedBlock`] from a [`Block`] or [`SemanticallyVerifiedBlock`],
90    /// with no chain value pool change.
91    ///
92    /// Only for use in tests.
93    pub fn test_with_zero_chain_pool_change(block: impl Into<SemanticallyVerifiedBlock>) -> Self {
94        let SemanticallyVerifiedBlock {
95            block,
96            hash,
97            height,
98            new_outputs,
99            transaction_hashes,
100            deferred_pool_balance_change: _,
101        } = block.into();
102
103        Self {
104            block,
105            hash,
106            height,
107            new_outputs: new_outputs.clone(),
108            // Just re-use the outputs we created in this block, even though that's incorrect.
109            //
110            // TODO: fix the tests, and stop adding unrelated inputs and outputs.
111            spent_outputs: new_outputs,
112            transaction_hashes,
113            chain_value_pool_change: ValueBalance::zero(),
114        }
115    }
116}