mithril_common/entities/
cardano_blocks_transactions_snapshot.rs

1use serde::{Deserialize, Serialize};
2use sha2::{Digest, Sha256};
3
4use super::BlockNumber;
5
6/// Snapshot of a set of Cardano blocks and transactions
7#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
8pub struct CardanoBlocksTransactionsSnapshot {
9    /// Hash of the Cardano blocks and transactions set
10    pub hash: String,
11
12    /// Merkle root of the Cardano blocks and transactions set
13    pub merkle_root: String,
14
15    /// Block number at which the Cardano blocks and transactions set has been snapshotted
16    pub block_number_signed: BlockNumber,
17
18    /// Block number of the tip of the chain at snapshot time (approximate)
19    pub block_number_tip: BlockNumber,
20}
21
22impl CardanoBlocksTransactionsSnapshot {
23    /// Creates a new [CardanoBlocksTransactionsSnapshot]
24    pub fn new(
25        merkle_root: String,
26        block_number_signed: BlockNumber,
27        offset_security_parameter: BlockNumber,
28    ) -> Self {
29        let mut snapshot = Self {
30            merkle_root,
31            block_number_signed,
32            block_number_tip: block_number_signed + offset_security_parameter,
33            hash: "".to_string(),
34        };
35        snapshot.hash = snapshot.compute_hash();
36        snapshot
37    }
38
39    /// Cardano blocks transactions snapshot hash computation
40    fn compute_hash(&self) -> String {
41        let mut hasher = Sha256::new();
42        hasher.update(self.merkle_root.as_bytes());
43        hasher.update(self.block_number_signed.to_be_bytes());
44        hasher.update(self.block_number_tip.to_be_bytes());
45
46        hex::encode(hasher.finalize())
47    }
48}
49
50#[cfg(test)]
51mod tests {
52    use super::*;
53
54    #[test]
55    fn test_cardano_blocks_transactions_snapshot_compute_hash() {
56        let expected_mk_root_hash =
57            "d99fe4ea053d416de6726deef785766e44970351e63172521f4783f23c8cb66c";
58
59        assert_eq!(
60            expected_mk_root_hash,
61            CardanoBlocksTransactionsSnapshot::new(
62                "mk-root-123".to_string(),
63                BlockNumber(50),
64                BlockNumber(15)
65            )
66            .compute_hash()
67        );
68
69        assert_ne!(
70            expected_mk_root_hash,
71            CardanoBlocksTransactionsSnapshot::new(
72                "mk-root-456".to_string(),
73                BlockNumber(50),
74                BlockNumber(15)
75            )
76            .compute_hash()
77        );
78
79        assert_ne!(
80            expected_mk_root_hash,
81            CardanoBlocksTransactionsSnapshot::new(
82                "mk-root-123".to_string(),
83                BlockNumber(47),
84                BlockNumber(15)
85            )
86            .compute_hash()
87        );
88
89        assert_ne!(
90            expected_mk_root_hash,
91            CardanoBlocksTransactionsSnapshot::new(
92                "mk-root-123".to_string(),
93                BlockNumber(50),
94                BlockNumber(42)
95            )
96            .compute_hash()
97        );
98    }
99
100    #[test]
101    fn test_block_number_tip_is_the_addition_of_block_number_and_offset_security_parameter() {
102        let block_number_signed_value = 100;
103        let offset_security_parameter_value = 20;
104
105        let snapshot = CardanoBlocksTransactionsSnapshot::new(
106            "mk-root-123".to_string(),
107            BlockNumber(block_number_signed_value),
108            BlockNumber(offset_security_parameter_value),
109        );
110
111        assert_eq!(
112            snapshot.block_number_tip,
113            BlockNumber(block_number_signed_value + offset_security_parameter_value),
114            "Block number tip should be the sum of block number signed and offset security parameter"
115        );
116    }
117}