mithril_persistence/database/record/
cardano_block_transactions.rs1use sqlite::Row;
2
3use mithril_common::entities::{
4 BlockHash, BlockNumber, CardanoBlockTransactionMkTreeNode, CardanoBlockWithTransactions,
5 SlotNumber, TransactionHash,
6};
7
8use crate::database::Hydrator;
9use crate::sqlite::{HydrationError, Projection, SqLiteEntity};
10
11#[derive(Debug, PartialEq, Clone)]
13pub struct CardanoBlockTransactionsRecord {
14 pub block_hash: BlockHash,
16
17 pub block_number: BlockNumber,
19
20 pub slot_number: SlotNumber,
22
23 pub transactions_hashes: Vec<TransactionHash>,
25}
26
27impl CardanoBlockTransactionsRecord {
28 pub fn new<U: Into<BlockHash>, T: Into<TransactionHash>>(
30 block_hash: U,
31 block_number: BlockNumber,
32 slot_number: SlotNumber,
33 tx_hashes: Vec<T>,
34 ) -> Self {
35 Self {
36 block_hash: block_hash.into(),
37 block_number,
38 slot_number,
39 transactions_hashes: tx_hashes.into_iter().map(Into::into).collect(),
40 }
41 }
42}
43
44impl SqLiteEntity for CardanoBlockTransactionsRecord {
45 fn hydrate(row: Row) -> Result<Self, HydrationError>
46 where
47 Self: Sized,
48 {
49 let block_hash = row.read::<&str, _>(0);
50 let block_number =
51 Hydrator::try_to_u64("cardano_block.block_number", row.read::<i64, _>(1))?;
52 let slot_number = Hydrator::try_to_u64("cardano_block.slot_number", row.read::<i64, _>(2))?;
53 let transactions_hashes = row
54 .read::<Option<&str>, _>(3)
55 .map(|hashes| hashes.split(',').map(|s| s.to_string()).collect())
56 .unwrap_or_default();
57
58 Ok(Self {
59 block_hash: block_hash.to_string(),
60 block_number: BlockNumber(block_number),
61 slot_number: SlotNumber(slot_number),
62 transactions_hashes,
63 })
64 }
65
66 fn get_projection() -> Projection {
67 Projection::from(&[
68 ("block_hash", "{:cardano_block:}.block_hash", "text"),
69 ("block_number", "{:cardano_block:}.block_number", "int"),
70 ("slot_number", "{:cardano_block:}.slot_number", "int"),
71 (
72 "transactions_hashes",
73 "group_concat({:cardano_tx:}.transaction_hash, ',')",
74 "text",
75 ),
76 ])
77 }
78}
79
80impl From<CardanoBlockWithTransactions> for CardanoBlockTransactionsRecord {
81 fn from(block: CardanoBlockWithTransactions) -> Self {
82 Self::new(
83 block.block_hash,
84 block.block_number,
85 block.slot_number,
86 block.transactions_hashes,
87 )
88 }
89}
90
91impl CardanoBlockTransactionsRecord {
92 pub fn into_mk_tree_nodes(self) -> Vec<CardanoBlockTransactionMkTreeNode> {
94 let mut result = Vec::with_capacity(self.transactions_hashes.len() + 1);
95 result.push(CardanoBlockTransactionMkTreeNode::Block {
96 block_hash: self.block_hash.clone(),
97 block_number: self.block_number,
98 slot_number: self.slot_number,
99 });
100 result.extend(self.transactions_hashes.into_iter().map(|tx_hash| {
101 CardanoBlockTransactionMkTreeNode::Transaction {
102 transaction_hash: tx_hash,
103 block_hash: self.block_hash.clone(),
104 block_number: self.block_number,
105 slot_number: self.slot_number,
106 }
107 }));
108
109 result
110 }
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 #[test]
118 fn convert_blocks_without_transactions_to_mk_tree_node() {
119 assert_eq!(
120 vec![CardanoBlockTransactionMkTreeNode::Block {
121 block_hash: "block_hash-10".to_string(),
122 block_number: BlockNumber(10),
123 slot_number: SlotNumber(50),
124 }],
125 CardanoBlockTransactionsRecord::new(
126 "block_hash-10",
127 BlockNumber(10),
128 SlotNumber(50),
129 Vec::<&str>::new()
130 )
131 .into_mk_tree_nodes()
132 );
133 }
134
135 #[test]
136 fn convert_blocks_with_transactions_to_mk_tree_node() {
137 assert_eq!(
138 vec![
139 CardanoBlockTransactionMkTreeNode::Block {
140 block_hash: "block_hash-10".to_string(),
141 block_number: BlockNumber(10),
142 slot_number: SlotNumber(50),
143 },
144 CardanoBlockTransactionMkTreeNode::Transaction {
145 transaction_hash: "tx-1".to_string(),
146 block_hash: "block_hash-10".to_string(),
147 block_number: BlockNumber(10),
148 slot_number: SlotNumber(50),
149 },
150 CardanoBlockTransactionMkTreeNode::Transaction {
151 transaction_hash: "tx-2".to_string(),
152 block_hash: "block_hash-10".to_string(),
153 block_number: BlockNumber(10),
154 slot_number: SlotNumber(50),
155 },
156 ],
157 CardanoBlockTransactionsRecord::new(
158 "block_hash-10",
159 BlockNumber(10),
160 SlotNumber(50),
161 vec!["tx-1", "tx-2"]
162 )
163 .into_mk_tree_nodes()
164 );
165 }
166}