mithril_cardano_node_chain/entities/
scanned_block.rs

1use pallas_traverse::MultiEraBlock;
2use std::fmt::{Debug, Formatter};
3
4use mithril_common::entities::{
5    BlockHash, BlockNumber, CardanoBlockWithTransactions, CardanoTransaction, ChainPoint,
6    SlotNumber, TransactionHash,
7};
8
9/// A block scanned from a Cardano database
10#[derive(Clone, PartialEq)]
11pub struct ScannedBlock {
12    /// Block hash
13    pub block_hash: Vec<u8>,
14    /// Block number
15    pub block_number: BlockNumber,
16    /// Slot number of the block
17    pub slot_number: SlotNumber,
18    /// Hashes of the transactions in the block
19    pub transactions_hashes: Vec<TransactionHash>,
20}
21
22impl ScannedBlock {
23    /// Scanned block factory
24    pub fn new<B: Into<Vec<u8>>, T: Into<TransactionHash>>(
25        block_hash: B,
26        block_number: BlockNumber,
27        slot_number: SlotNumber,
28        transaction_hashes: Vec<T>,
29    ) -> Self {
30        Self {
31            block_hash: block_hash.into(),
32            block_number,
33            slot_number,
34            transactions_hashes: transaction_hashes.into_iter().map(|h| h.into()).collect(),
35        }
36    }
37
38    pub(crate) fn convert(multi_era_block: MultiEraBlock) -> Self {
39        let mut transactions = Vec::new();
40        for tx in &multi_era_block.txs() {
41            transactions.push(tx.hash().to_string());
42        }
43
44        Self::new(
45            *multi_era_block.hash(),
46            BlockNumber(multi_era_block.number()),
47            SlotNumber(multi_era_block.slot()),
48            transactions,
49        )
50    }
51
52    /// Number of transactions in the block
53    pub fn transactions_len(&self) -> usize {
54        self.transactions_hashes.len()
55    }
56
57    /// Returns the block hash as a hex string.
58    pub fn block_hash_hex(&self) -> BlockHash {
59        hex::encode(&self.block_hash)
60    }
61
62    /// Convert the scanned block into a list of Cardano transactions.
63    ///
64    /// Consume the block.
65    pub fn into_transactions(self) -> Vec<CardanoTransaction> {
66        let block_hash = self.block_hash_hex();
67        self.transactions_hashes
68            .into_iter()
69            .map(|transaction_hash| {
70                CardanoTransaction::new(
71                    transaction_hash,
72                    self.block_number,
73                    self.slot_number,
74                    block_hash.clone(),
75                )
76            })
77            .collect::<Vec<_>>()
78    }
79}
80
81impl Debug for ScannedBlock {
82    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
83        let mut debug = f.debug_struct("ScannedBlock");
84        debug
85            .field("block_hash", &self.block_hash_hex())
86            .field("block_number", &self.block_number)
87            .field("slot_number", &self.slot_number)
88            .field("transactions_hashes", &self.transactions_hashes)
89            .finish()
90    }
91}
92
93impl From<&ScannedBlock> for ChainPoint {
94    fn from(scanned_block: &ScannedBlock) -> Self {
95        ChainPoint::new(
96            scanned_block.slot_number,
97            scanned_block.block_number,
98            scanned_block.block_hash_hex(),
99        )
100    }
101}
102
103impl From<ScannedBlock> for CardanoBlockWithTransactions {
104    fn from(value: ScannedBlock) -> Self {
105        CardanoBlockWithTransactions::new(
106            value.block_hash_hex(),
107            value.block_number,
108            value.slot_number,
109            value.transactions_hashes,
110        )
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn block_hash_hex() {
120        let block = ScannedBlock::new(
121            vec![1, 2, 3],
122            BlockNumber(10),
123            SlotNumber(50),
124            vec!["tx_hash"],
125        );
126        assert_eq!("010203", block.block_hash_hex());
127    }
128}