1use std::cmp::Ordering;
2
3use crate::crypto_helper::MKTreeNode;
4use crate::entities::{
5 BlockHash, BlockNumber, CardanoBlock, CardanoTransaction, SlotNumber, TransactionHash,
6};
7
8#[derive(Debug, Clone, PartialEq, Eq)]
15pub enum CardanoBlockTransactionMkTreeNode {
16 Block {
18 block_hash: BlockHash,
20 block_number: BlockNumber,
22 slot_number: SlotNumber,
24 },
25 Transaction {
27 transaction_hash: TransactionHash,
29 block_number: BlockNumber,
31 slot_number: SlotNumber,
33 block_hash: BlockHash,
35 },
36}
37
38impl CardanoBlockTransactionMkTreeNode {
39 pub fn block_number(&self) -> BlockNumber {
41 match self {
42 Self::Block { block_number, .. } => *block_number,
43 Self::Transaction { block_number, .. } => *block_number,
44 }
45 }
46
47 fn leaf_identifier(&self) -> Vec<u8> {
48 match self {
49 Self::Block {
50 block_hash,
51 block_number,
52 slot_number,
53 } => format!("Block/{block_hash}/{block_number}/{slot_number}").into_bytes(),
54 Self::Transaction {
55 transaction_hash,
56 block_hash,
57 block_number,
58 slot_number,
59 } => format!("Tx/{transaction_hash}/{block_hash}/{block_number}/{slot_number}",)
60 .into_bytes(),
61 }
62 }
63}
64
65impl From<CardanoBlock> for CardanoBlockTransactionMkTreeNode {
66 fn from(value: CardanoBlock) -> Self {
67 Self::Block {
68 block_hash: value.block_hash,
69 block_number: value.block_number,
70 slot_number: value.slot_number,
71 }
72 }
73}
74
75impl From<CardanoTransaction> for CardanoBlockTransactionMkTreeNode {
76 fn from(value: CardanoTransaction) -> Self {
77 Self::Transaction {
78 transaction_hash: value.transaction_hash,
79 block_hash: value.block_hash,
80 block_number: value.block_number,
81 slot_number: value.slot_number,
82 }
83 }
84}
85
86impl From<CardanoBlockTransactionMkTreeNode> for MKTreeNode {
87 fn from(value: CardanoBlockTransactionMkTreeNode) -> Self {
88 MKTreeNode::new(value.leaf_identifier())
89 }
90}
91
92impl PartialOrd for CardanoBlockTransactionMkTreeNode {
93 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
94 Some(Ord::cmp(self, other))
95 }
96}
97
98impl Ord for CardanoBlockTransactionMkTreeNode {
99 fn cmp(&self, other: &Self) -> Ordering {
100 use CardanoBlockTransactionMkTreeNode::{Block, Transaction};
101
102 match (self, other) {
103 (Block { .. }, Transaction { .. }) => Ordering::Less,
104 (Transaction { .. }, Block { .. }) => Ordering::Greater,
105 (
106 Block {
107 block_number,
108 block_hash,
109 slot_number,
110 },
111 Block {
112 block_number: other_block_number,
113 block_hash: other_block_hash,
114 slot_number: other_slot_number,
115 },
116 ) => block_number
117 .cmp(other_block_number)
118 .then(slot_number.cmp(other_slot_number))
119 .then(block_hash.cmp(other_block_hash)),
120 (
121 Transaction {
122 block_number,
123 slot_number,
124 block_hash,
125 transaction_hash,
126 },
127 Transaction {
128 block_number: other_block_number,
129 slot_number: other_slot_number,
130 block_hash: other_block_hash,
131 transaction_hash: other_transaction_hash,
132 },
133 ) => block_number
134 .cmp(other_block_number)
135 .then(slot_number.cmp(other_slot_number))
136 .then(block_hash.cmp(other_block_hash))
137 .then(transaction_hash.cmp(other_transaction_hash)),
138 }
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 macro_rules! block_node {
147 (num: $block_number:expr, slot: $slot_number:expr) => {
148 block_node!(hash:format!("block_hash-{}", $block_number), num: $block_number, slot: $slot_number)
149 };
150 (hash: $block_hash:expr, num: $block_number:expr, slot: $slot_number:expr) => {
151 CardanoBlockTransactionMkTreeNode::Block {
152 block_hash: $block_hash.to_string(),
153 block_number: BlockNumber($block_number),
154 slot_number: SlotNumber($slot_number),
155 }
156 };
157 }
158
159 macro_rules! tx_node {
160 (hash: $tx_hash:expr, block: $block_number:expr, slot: $slot_number:expr) => {
161 tx_node!(hash: $tx_hash, block_hash: format!("block_hash-{}", $tx_hash), block: $block_number, slot: $slot_number)
162 };
163 (hash: $tx_hash:expr, block_hash: $block_hash:expr, block: $block_number:expr, slot: $slot_number:expr) => {
164 CardanoBlockTransactionMkTreeNode::Transaction {
165 transaction_hash: $tx_hash.to_string(),
166 block_hash: $block_hash.to_string(),
167 block_number: BlockNumber($block_number),
168 slot_number: SlotNumber($slot_number),
169 }
170 };
171 }
172
173 #[test]
174 fn block_node_leaf_identifier() {
175 assert_eq!(
177 "Block/block_hash-5/5/6".to_string().into_bytes(),
178 block_node!(hash: "block_hash-5", num: 5, slot: 6).leaf_identifier()
179 );
180 assert_eq!(
181 "Block/block_hash-10/9/13".to_string().into_bytes(),
182 block_node!(hash: "block_hash-10", num: 9, slot: 13).leaf_identifier()
183 );
184 }
185
186 #[test]
187 fn transaction_node_leaf_identifier() {
188 assert_eq!(
190 "Tx/tx_hash-5/block_hash-5/5/6".to_string().into_bytes(),
191 tx_node!(hash: "tx_hash-5", block_hash: "block_hash-5", block: 5, slot: 6)
192 .leaf_identifier()
193 );
194 assert_eq!(
195 "Tx/tx_hash-10/block_hash-10/9/13".to_string().into_bytes(),
196 tx_node!(hash: "tx_hash-10", block_hash: "block_hash-10", block: 9, slot: 13)
197 .leaf_identifier()
198 );
199 }
200
201 #[test]
202 fn convert_cardano_block_to_cardano_blocks_transactions_mktree_node() {
203 let block = CardanoBlock::new("block_hash-5", BlockNumber(4), SlotNumber(6));
204
205 assert_eq!(
206 CardanoBlockTransactionMkTreeNode::Block {
207 block_hash: "block_hash-5".to_string(),
208 block_number: BlockNumber(4),
209 slot_number: SlotNumber(6)
210 },
211 block.into()
212 )
213 }
214
215 #[test]
216 fn convert_cardano_transaction_to_cardano_blocks_transactions_mktree_node() {
217 let transaction =
218 CardanoTransaction::new("tx_hash-5", BlockNumber(4), SlotNumber(6), "block_hash-5");
219
220 assert_eq!(
221 CardanoBlockTransactionMkTreeNode::Transaction {
222 transaction_hash: "tx_hash-5".to_string(),
223 block_number: BlockNumber(4),
224 slot_number: SlotNumber(6),
225 block_hash: "block_hash-5".to_string(),
226 },
227 transaction.into()
228 )
229 }
230
231 #[test]
232 fn convert_block_node_into_mktree_nodes() {
233 let block = block_node!(hash: "block_hash-5", num: 5, slot: 6);
234 let expected: MKTreeNode = MKTreeNode::new(block.leaf_identifier());
235
236 let computed_node: MKTreeNode = block.into();
237 assert_eq!(expected, computed_node);
238 assert_ne!(
239 computed_node,
240 block_node!(hash: "other", num: 5, slot: 6).into()
241 );
242 assert_ne!(
243 computed_node,
244 block_node!(hash: "block_hash-10", num: 1000, slot: 6).into()
245 );
246 assert_ne!(
247 computed_node,
248 block_node!(hash: "block_hash-10", num: 5, slot: 1000).into()
249 );
250 }
251
252 #[test]
253 fn convert_tx_node_into_mktree_nodes() {
254 let transaction =
255 tx_node!(hash: "tx_hash-5", block_hash: "block_hash-5", block: 5, slot: 6);
256 let expected: MKTreeNode = MKTreeNode::new(transaction.leaf_identifier());
257
258 let computed_node: MKTreeNode = transaction.into();
259 assert_eq!(expected, computed_node);
260 assert_ne!(
261 computed_node,
262 tx_node!(hash: "other", block_hash: "block_hash-5", block: 5, slot: 6).into(),
263 );
264 assert_ne!(
265 computed_node,
266 tx_node!(hash: "tx_hash-5", block_hash: "other", block: 5, slot: 6).into(),
267 );
268 assert_ne!(
269 computed_node,
270 tx_node!(hash: "tx_hash-5", block_hash: "block_hash-5", block: 1000, slot: 6).into(),
271 );
272 assert_ne!(
273 computed_node,
274 tx_node!(hash: "tx_hash-5", block_hash: "block_hash-5", block: 5, slot: 1000).into(),
275 );
276 }
277
278 mod mk_tree_node_ordering {
279 use super::*;
280
281 #[test]
282 fn same_value_yield_equal_order() {
283 let block = block_node!(num: 5, slot: 6);
284 let tx = tx_node!(hash: "tx_hash-1", block: 5, slot: 6);
285
286 assert_eq!(Ordering::Equal, block.cmp(&block));
287 assert_eq!(Ordering::Equal, tx.cmp(&tx));
288 }
289
290 #[test]
291 fn order_block_nodes_first_then_transaction_nodes() {
292 let block = block_node!(num: 5, slot: 6);
293 let tx = tx_node!(hash: "tx_hash-1", block: 5, slot: 6);
294
295 assert_eq!(Ordering::Less, block.cmp(&tx));
296 assert_eq!(Ordering::Greater, tx.cmp(&block));
297 }
298
299 #[test]
300 fn order_blocks_by_block_number_first() {
301 let block = block_node!(hash: "block_hash-5", num: 5, slot: 6);
302
303 assert_eq!(
304 Ordering::Less,
305 block.cmp(&block_node!(hash: "block_hash-1", num: 10, slot: 1))
306 );
307 assert_eq!(
308 Ordering::Greater,
309 block.cmp(&block_node!(hash: "block_hash-9", num: 1, slot: 9))
310 );
311 }
312
313 #[test]
314 fn order_blocks_by_slot_number_second() {
315 let block = block_node!(hash: "block_hash-5", num: 5, slot: 6);
316
317 assert_eq!(
318 Ordering::Less,
319 block.cmp(&block_node!(hash: "block_hash-1", num: 5, slot: 9))
320 );
321 assert_eq!(
322 Ordering::Greater,
323 block.cmp(&block_node!(hash: "block_hash-9", num: 5, slot: 1))
324 );
325 }
326
327 #[test]
328 fn order_blocks_by_block_hash_third() {
329 let block = block_node!(hash: "block_hash-5", num: 5, slot: 6);
330
331 assert_eq!(
332 Ordering::Less,
333 block.cmp(&block_node!(hash: "block_hash-9", num: 5, slot: 6))
334 );
335 assert_eq!(
336 Ordering::Greater,
337 block.cmp(&block_node!(hash: "block_hash-1", num: 5, slot: 6))
338 );
339 }
340
341 #[test]
342 fn order_transactions_by_block_number_first() {
343 let tx = tx_node!(hash: "tx_hash-5", block_hash: "block_hash-5", block: 5, slot: 6);
344
345 assert_eq!(
346 Ordering::Less,
347 tx.cmp(
348 &tx_node!(hash: "tx_hash-1", block_hash: "block_hash-1", block: 10, slot: 1)
349 )
350 );
351 assert_eq!(
352 Ordering::Greater,
353 tx.cmp(&tx_node!(hash: "tx_hash-9", block_hash: "block_hash-9", block: 1, slot: 9))
354 );
355 }
356
357 #[test]
358 fn order_transactions_by_slot_number_second() {
359 let tx = tx_node!(hash: "tx_hash-5", block_hash: "block_hash-5", block: 5, slot: 6);
360
361 assert_eq!(
362 Ordering::Less,
363 tx.cmp(&tx_node!(hash: "tx_hash-1", block_hash: "block_hash-1", block: 5, slot: 9))
364 );
365 assert_eq!(
366 Ordering::Greater,
367 tx.cmp(&tx_node!(hash: "tx_hash-9", block_hash: "block_hash-9", block: 5, slot: 1))
368 );
369 }
370
371 #[test]
372 fn order_transactions_by_block_hash_third() {
373 let tx = tx_node!(hash: "tx_hash-5", block_hash: "block_hash-5", block: 5, slot: 6);
374
375 assert_eq!(
376 Ordering::Less,
377 tx.cmp(&tx_node!(hash: "tx_hash-1", block_hash: "block_hash-9", block: 5, slot: 6))
378 );
379 assert_eq!(
380 Ordering::Greater,
381 tx.cmp(&tx_node!(hash: "tx_hash-9", block_hash: "block_hash-1", block: 5, slot: 6))
382 );
383 }
384
385 #[test]
386 fn order_transactions_by_transaction_hash_fourth() {
387 let tx = tx_node!(hash: "tx_hash-5", block_hash: "block_hash-5", block: 5, slot: 6);
388
389 assert_eq!(
390 Ordering::Less,
391 tx.cmp(&tx_node!(hash: "tx_hash-9", block_hash: "block_hash-5", block: 5, slot: 6))
392 );
393 assert_eq!(
394 Ordering::Greater,
395 tx.cmp(&tx_node!(hash: "tx_hash-1", block_hash: "block_hash-5", block: 5, slot: 6))
396 );
397 }
398
399 #[test]
400 fn sorting_a_vec() {
401 let mut list = vec![
402 tx_node!(hash: "tx_hash-70", block: 300, slot: 35),
403 tx_node!(hash: "tx_hash-200", block: 100, slot: 100),
404 tx_node!(hash: "tx_hash-50", block: 200, slot: 25),
405 block_node!(num: 100, slot: 100),
406 tx_node!(hash: "tx_hash-100", block: 100, slot: 100),
407 block_node!(num: 200, slot: 35),
408 block_node!(num: 200, slot: 25),
409 ];
410 list.sort();
411
412 assert_eq!(
413 list,
414 vec![
415 block_node!(num: 100, slot: 100),
416 block_node!(num: 200, slot: 25),
417 block_node!(num: 200, slot: 35),
418 tx_node!(hash: "tx_hash-100", block: 100, slot: 100),
419 tx_node!(hash: "tx_hash-200", block: 100, slot: 100),
420 tx_node!(hash: "tx_hash-50", block: 200, slot: 25),
421 tx_node!(hash: "tx_hash-70", block: 300, slot: 35),
422 ]
423 );
424 }
425 }
426}