Skip to main content

zebra_state/
arbitrary.rs

1//! Randomised data generation for state data.
2
3use std::sync::Arc;
4
5use zebra_chain::{
6    amount::{Amount, DeferredPoolBalanceChange},
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(
86            block,
87            zero_spent_utxos,
88            DeferredPoolBalanceChange::zero(),
89        )
90        .expect("all UTXOs are provided with zero values")
91    }
92
93    /// Create a [`ContextuallyVerifiedBlock`] from a [`Block`] or [`SemanticallyVerifiedBlock`],
94    /// with no chain value pool change.
95    ///
96    /// Only for use in tests.
97    pub fn test_with_zero_chain_pool_change(block: impl Into<SemanticallyVerifiedBlock>) -> Self {
98        let SemanticallyVerifiedBlock {
99            block,
100            hash,
101            height,
102            new_outputs,
103            transaction_hashes,
104        } = block.into();
105
106        Self {
107            block,
108            hash,
109            height,
110            new_outputs: new_outputs.clone(),
111            // Just re-use the outputs we created in this block, even though that's incorrect.
112            //
113            // TODO: fix the tests, and stop adding unrelated inputs and outputs.
114            spent_outputs: new_outputs,
115            transaction_hashes,
116            chain_value_pool_change: ValueBalance::zero(),
117        }
118    }
119}