kaspa_consensus/pipeline/virtual_processor/
test_block_builder.rs

1use std::{ops::Deref, sync::Arc};
2
3use crate::model::stores::{
4    pruning::PruningStoreReader, utxo_multisets::UtxoMultisetsStoreReader, virtual_state::VirtualStateStoreReader,
5};
6use kaspa_consensus_core::{
7    block::BlockTemplate, blockhash::ORIGIN, coinbase::MinerData, errors::block::RuleError, tx::Transaction,
8    utxo::utxo_view::UtxoViewComposition,
9};
10use kaspa_hashes::Hash;
11
12use super::VirtualStateProcessor;
13
14/// Wrapper for virtual processor with util methods for building a block with any parent context
15pub struct TestBlockBuilder {
16    processor: Arc<VirtualStateProcessor>,
17}
18
19impl Deref for TestBlockBuilder {
20    type Target = VirtualStateProcessor;
21
22    fn deref(&self) -> &Self::Target {
23        &self.processor
24    }
25}
26
27impl TestBlockBuilder {
28    pub fn new(processor: Arc<VirtualStateProcessor>) -> Self {
29        Self { processor }
30    }
31
32    /// Test-only helper method for building a block template with specific parents
33    pub(crate) fn build_block_template_with_parents(
34        &self,
35        parents: Vec<Hash>,
36        miner_data: MinerData,
37        txs: Vec<Transaction>,
38    ) -> Result<BlockTemplate, RuleError> {
39        //
40        // In the context of this method "pov virtual" is the virtual block which has `parents` as tips and not the actual virtual
41        //
42        let pruning_point = self.pruning_point_store.read().pruning_point().unwrap();
43        let virtual_read = self.virtual_stores.read();
44        let virtual_state = virtual_read.state.get().unwrap();
45        let finality_point = ORIGIN; // No real finality point since we are not actually building virtual here
46        let sink = virtual_state.ghostdag_data.selected_parent;
47        let mut accumulated_diff = virtual_state.utxo_diff.clone().to_reversed();
48        // Search for the sink block from the PoV of this virtual
49        let (pov_sink, virtual_parent_candidates) =
50            self.sink_search_algorithm(&virtual_read, &mut accumulated_diff, sink, parents, finality_point, pruning_point);
51        let (pov_virtual_parents, pov_virtual_ghostdag_data) =
52            self.pick_virtual_parents(pov_sink, virtual_parent_candidates, pruning_point);
53        let pov_sink_multiset = self.utxo_multisets_store.get(pov_sink).unwrap();
54        let pov_virtual_state = self.calculate_virtual_state(
55            &virtual_read,
56            pov_virtual_parents,
57            pov_virtual_ghostdag_data,
58            pov_sink_multiset,
59            &mut accumulated_diff,
60        )?;
61        let pov_virtual_utxo_view = (&virtual_read.utxo_set).compose(accumulated_diff);
62        self.validate_block_template_transactions(&txs, &pov_virtual_state, &pov_virtual_utxo_view)?;
63        drop(virtual_read);
64        self.build_block_template_from_virtual_state(pov_virtual_state, miner_data, txs, vec![])
65    }
66}