kaspa_consensus_core/
block.rs

1use crate::{
2    coinbase::MinerData,
3    header::Header,
4    tx::{Transaction, TransactionId},
5    BlueWorkType,
6};
7use kaspa_hashes::Hash;
8use kaspa_utils::mem_size::MemSizeEstimator;
9use std::sync::Arc;
10
11/// A mutable block structure where header and transactions within can still be mutated.
12#[derive(Debug, Clone)]
13pub struct MutableBlock {
14    pub header: Header,
15    pub transactions: Vec<Transaction>,
16}
17
18impl MutableBlock {
19    pub fn new(header: Header, txs: Vec<Transaction>) -> Self {
20        Self { header, transactions: txs }
21    }
22
23    pub fn from_header(header: Header) -> Self {
24        Self::new(header, vec![])
25    }
26
27    pub fn to_immutable(self) -> Block {
28        Block::new(self.header, self.transactions)
29    }
30}
31
32/// A block structure where the inner header and transactions are wrapped by Arcs for
33/// cheap cloning and for cross-thread safety and immutability. Note: no need to wrap
34/// this struct with an additional Arc.
35#[derive(Debug, Clone)]
36pub struct Block {
37    pub header: Arc<Header>,
38    pub transactions: Arc<Vec<Transaction>>,
39}
40
41impl Block {
42    pub fn new(header: Header, txs: Vec<Transaction>) -> Self {
43        Self { header: Arc::new(header), transactions: Arc::new(txs) }
44    }
45
46    pub fn from_arcs(header: Arc<Header>, transactions: Arc<Vec<Transaction>>) -> Self {
47        Self { header, transactions }
48    }
49
50    pub fn from_header_arc(header: Arc<Header>) -> Self {
51        Self { header, transactions: Arc::new(Vec::new()) }
52    }
53
54    pub fn from_header(header: Header) -> Self {
55        Self { header: Arc::new(header), transactions: Arc::new(Vec::new()) }
56    }
57
58    pub fn is_header_only(&self) -> bool {
59        self.transactions.is_empty()
60    }
61
62    pub fn hash(&self) -> Hash {
63        self.header.hash
64    }
65
66    /// WARNING: To be used for test purposes only
67    pub fn from_precomputed_hash(hash: Hash, parents: Vec<Hash>) -> Block {
68        Block::from_header(Header::from_precomputed_hash(hash, parents))
69    }
70
71    pub fn asses_for_cache(&self) -> Option<()> {
72        (self.estimate_mem_bytes() < 1_000_000).then_some(())
73    }
74}
75
76impl MemSizeEstimator for Block {
77    fn estimate_mem_bytes(&self) -> usize {
78        // Calculates mem bytes of the block (for cache tracking purposes)
79        size_of::<Self>()
80            + self.header.estimate_mem_bytes()
81            + size_of::<Vec<Transaction>>()
82            + self.transactions.iter().map(Transaction::estimate_mem_bytes).sum::<usize>()
83    }
84}
85
86/// An abstraction for a recallable transaction selector with persistent state
87pub trait TemplateTransactionSelector {
88    /// Expected to return a batch of transactions which were not previously selected.
89    /// The batch will typically contain sufficient transactions to fill the block
90    /// mass (along with the previously unrejected txs), or will drain the selector    
91    fn select_transactions(&mut self) -> Vec<Transaction>;
92
93    /// Should be used to report invalid transactions obtained from the *most recent*
94    /// `select_transactions` call. Implementors should use this call to internally
95    /// track the selection state and discard the rejected tx from internal occupation calculations
96    fn reject_selection(&mut self, tx_id: TransactionId);
97
98    /// Determine whether this was an overall successful selection episode
99    fn is_successful(&self) -> bool;
100}
101
102/// Block template build mode
103#[derive(Clone, Copy, Debug)]
104pub enum TemplateBuildMode {
105    /// Block template build can possibly fail if `TemplateTransactionSelector::is_successful` deems the operation unsuccessful.
106    ///
107    /// In such a case, the build fails with `BlockRuleError::InvalidTransactionsInNewBlock`.
108    Standard,
109
110    /// Block template build always succeeds. The built block contains only the validated transactions.
111    Infallible,
112}
113
114/// A block template for miners.
115#[derive(Debug, Clone)]
116pub struct BlockTemplate {
117    pub block: MutableBlock,
118    pub miner_data: MinerData,
119    pub coinbase_has_red_reward: bool,
120    pub selected_parent_timestamp: u64,
121    pub selected_parent_daa_score: u64,
122    pub selected_parent_hash: Hash,
123    /// Expected length is one less than txs length due to lack of coinbase transaction
124    pub calculated_fees: Vec<u64>,
125}
126
127impl BlockTemplate {
128    pub fn new(
129        block: MutableBlock,
130        miner_data: MinerData,
131        coinbase_has_red_reward: bool,
132        selected_parent_timestamp: u64,
133        selected_parent_daa_score: u64,
134        selected_parent_hash: Hash,
135        calculated_fees: Vec<u64>,
136    ) -> Self {
137        Self {
138            block,
139            miner_data,
140            coinbase_has_red_reward,
141            selected_parent_timestamp,
142            selected_parent_daa_score,
143            selected_parent_hash,
144            calculated_fees,
145        }
146    }
147
148    pub fn to_virtual_state_approx_id(&self) -> VirtualStateApproxId {
149        VirtualStateApproxId::new(self.block.header.daa_score, self.block.header.blue_work, self.selected_parent_hash)
150    }
151}
152
153/// An opaque data structure representing a unique approximate identifier for virtual state. Note that it is
154/// approximate in the sense that in rare cases a slightly different virtual state might produce the same identifier,
155/// hence it should be used for cache-like heuristics only
156#[derive(PartialEq)]
157pub struct VirtualStateApproxId {
158    daa_score: u64,
159    blue_work: BlueWorkType,
160    sink: Hash,
161}
162
163impl VirtualStateApproxId {
164    pub fn new(daa_score: u64, blue_work: BlueWorkType, sink: Hash) -> Self {
165        Self { daa_score, blue_work, sink }
166    }
167}