mithril_common/entities/
cardano_db_beacon.rs

1use serde::{Deserialize, Serialize};
2use sha2::{Digest, Sha256};
3use std::fmt::{Display, Formatter};
4
5use crate::entities::{Epoch, ImmutableFileNumber};
6
7/// A point in the Cardano chain at which a Mithril certificate of the Cardano Database should be
8/// produced.
9#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Default, Serialize, Deserialize, Hash)]
10pub struct CardanoDbBeacon {
11    /// Cardano chain epoch number
12    pub epoch: Epoch,
13
14    /// Number of the last included immutable files for the digest computation
15    pub immutable_file_number: ImmutableFileNumber,
16}
17
18impl Display for CardanoDbBeacon {
19    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
20        write!(
21            f,
22            "CardanoDbBeacon (epoch: {}, immutable_file_number: {})",
23            self.epoch, self.immutable_file_number
24        )
25    }
26}
27
28impl CardanoDbBeacon {
29    /// CardanoDbBeacon factory
30    pub fn new(epoch: u64, immutable_file_number: ImmutableFileNumber) -> CardanoDbBeacon {
31        CardanoDbBeacon {
32            epoch: Epoch(epoch),
33            immutable_file_number,
34        }
35    }
36
37    /// Computes the hash of a CardanoDbBeacon
38    pub fn compute_hash(&self) -> String {
39        let mut hasher = Sha256::new();
40        hasher.update(self.epoch.to_be_bytes());
41        hasher.update(self.immutable_file_number.to_be_bytes());
42        hex::encode(hasher.finalize())
43    }
44}
45
46#[cfg(test)]
47mod tests {
48    use std::cmp::Ordering;
49
50    use super::*;
51
52    #[test]
53    fn test_order() {
54        let beacon: CardanoDbBeacon = CardanoDbBeacon {
55            epoch: Epoch(10),
56            immutable_file_number: 75,
57        };
58
59        assert_eq!(Ordering::Equal, beacon.cmp(&beacon));
60        assert_eq!(
61            Ordering::Less,
62            beacon.cmp(&CardanoDbBeacon {
63                epoch: beacon.epoch + 1,
64                ..beacon.clone()
65            })
66        );
67        assert_eq!(
68            Ordering::Greater,
69            beacon.cmp(&CardanoDbBeacon {
70                epoch: beacon.epoch - 1,
71                ..beacon.clone()
72            })
73        );
74        assert_eq!(
75            Ordering::Less,
76            beacon.cmp(&CardanoDbBeacon {
77                immutable_file_number: beacon.immutable_file_number + 1,
78                ..beacon.clone()
79            })
80        );
81        assert_eq!(
82            Ordering::Greater,
83            beacon.cmp(&CardanoDbBeacon {
84                immutable_file_number: beacon.immutable_file_number - 1,
85                ..beacon.clone()
86            })
87        );
88
89        // Epoch has higher priority than immutable_file_number
90        assert_eq!(
91            Ordering::Less,
92            beacon.cmp(&CardanoDbBeacon {
93                epoch: beacon.epoch + 1,
94                immutable_file_number: beacon.immutable_file_number - 1,
95            })
96        );
97        assert_eq!(
98            Ordering::Greater,
99            beacon.cmp(&CardanoDbBeacon {
100                epoch: beacon.epoch - 1,
101                immutable_file_number: beacon.immutable_file_number + 1,
102            })
103        )
104    }
105
106    #[test]
107    fn test_beacon_compute_hash() {
108        let hash_expected = "9ab2a51e6dbed250ff6f2a70709834f3fba8197411ce9fb29923b124f3fe8594";
109        let (epoch, immutable_file_number) = (10, 100);
110
111        assert_eq!(
112            hash_expected,
113            CardanoDbBeacon::new(epoch, immutable_file_number).compute_hash()
114        );
115        assert_ne!(
116            hash_expected,
117            CardanoDbBeacon::new(20, immutable_file_number).compute_hash()
118        );
119        assert_ne!(
120            hash_expected,
121            CardanoDbBeacon::new(epoch, 200).compute_hash()
122        );
123    }
124}