mithril_common/messages/
snapshot.rs

1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use crate::entities::{CardanoDbBeacon, CompressionAlgorithm};
5
6/// Message structure of a snapshot
7#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
8pub struct SnapshotMessage {
9    /// Digest that is signed by the signer participants
10    pub digest: String,
11
12    /// Cardano network
13    pub network: String,
14
15    /// Mithril beacon on the Cardano chain
16    pub beacon: CardanoDbBeacon,
17
18    /// Hash of the associated certificate
19    pub certificate_hash: String,
20
21    /// Size of the immutables snapshot file in Bytes
22    pub size: u64,
23
24    /// Size of the ancillary files in Bytes
25    #[serde(skip_serializing_if = "Option::is_none")]
26    pub ancillary_size: Option<u64>,
27
28    /// Date and time at which the snapshot was created
29    pub created_at: DateTime<Utc>,
30
31    /// Locations where the snapshot of the immutable files can be retrieved
32    pub locations: Vec<String>,
33
34    /// Locations where the snapshot of the ancillary files can be retrieved
35    #[serde(skip_serializing_if = "Option::is_none")]
36    pub ancillary_locations: Option<Vec<String>>,
37
38    /// Compression algorithm of the snapshot archive
39    pub compression_algorithm: CompressionAlgorithm,
40
41    /// Cardano node version
42    pub cardano_node_version: String,
43}
44
45impl SnapshotMessage {
46    /// Compute the total size of the snapshot including ancillary files
47    pub fn compute_total_size(&self) -> u64 {
48        self.size + self.ancillary_size.unwrap_or(0)
49    }
50}
51
52#[cfg(test)]
53mod tests {
54    use crate::entities::Epoch;
55    use crate::test::double::Dummy;
56
57    use super::*;
58
59    #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
60    pub struct SnapshotMessageUntilV0_1_47 {
61        pub digest: String,
62        pub network: String,
63        pub beacon: CardanoDbBeacon,
64        pub certificate_hash: String,
65        pub size: u64,
66        pub created_at: DateTime<Utc>,
67        pub locations: Vec<String>,
68        pub compression_algorithm: CompressionAlgorithm,
69        pub cardano_node_version: String,
70    }
71
72    const CURRENT_JSON: &str = r#"{
73        "digest": "0b9f5ad7f33cc523775c82249294eb8a1541d54f08eb3107cafc5638403ec7c6",
74        "network": "preview",
75        "beacon": {
76            "epoch": 86,
77            "immutable_file_number": 1728
78        },
79        "certificate_hash": "d5daf6c03ace4a9c074e951844075b9b373bafc4e039160e3e2af01823e9abfb",
80        "size": 807803196,
81        "ancillary_size": 123456789,
82        "created_at": "2023-01-19T13:43:05.618857482Z",
83        "locations": [
84            "https://host/certificate.tar.gz"
85        ],
86        "ancillary_locations": [
87            "https://host/ancillary.tar.gz"
88        ],
89        "compression_algorithm": "gzip",
90        "cardano_node_version": "0.0.1"
91    }"#;
92
93    fn golden_message_until_open_api_0_1_47() -> SnapshotMessageUntilV0_1_47 {
94        SnapshotMessageUntilV0_1_47 {
95            digest: "0b9f5ad7f33cc523775c82249294eb8a1541d54f08eb3107cafc5638403ec7c6".to_string(),
96            network: "preview".to_string(),
97            beacon: CardanoDbBeacon {
98                epoch: Epoch(86),
99                immutable_file_number: 1728,
100            },
101            certificate_hash: "d5daf6c03ace4a9c074e951844075b9b373bafc4e039160e3e2af01823e9abfb"
102                .to_string(),
103            size: 807803196,
104            created_at: DateTime::parse_from_rfc3339("2023-01-19T13:43:05.618857482Z")
105                .unwrap()
106                .with_timezone(&Utc),
107            locations: vec!["https://host/certificate.tar.gz".to_string()],
108            compression_algorithm: CompressionAlgorithm::Gzip,
109            cardano_node_version: "0.0.1".to_string(),
110        }
111    }
112
113    fn golden_message_current() -> SnapshotMessage {
114        SnapshotMessage {
115            digest: "0b9f5ad7f33cc523775c82249294eb8a1541d54f08eb3107cafc5638403ec7c6".to_string(),
116            network: "preview".to_string(),
117            beacon: CardanoDbBeacon {
118                epoch: Epoch(86),
119                immutable_file_number: 1728,
120            },
121            certificate_hash: "d5daf6c03ace4a9c074e951844075b9b373bafc4e039160e3e2af01823e9abfb"
122                .to_string(),
123            size: 807803196,
124            ancillary_size: Some(123456789),
125            created_at: DateTime::parse_from_rfc3339("2023-01-19T13:43:05.618857482Z")
126                .unwrap()
127                .with_timezone(&Utc),
128            locations: vec!["https://host/certificate.tar.gz".to_string()],
129            ancillary_locations: Some(vec!["https://host/ancillary.tar.gz".to_string()]),
130            compression_algorithm: CompressionAlgorithm::Gzip,
131            cardano_node_version: "0.0.1".to_string(),
132        }
133    }
134
135    #[test]
136    fn test_current_json_deserialized_into_message_supported_until_open_api_0_1_47() {
137        let json = CURRENT_JSON;
138        let message: SnapshotMessageUntilV0_1_47 = serde_json::from_str(json).unwrap();
139
140        assert_eq!(golden_message_until_open_api_0_1_47(), message);
141    }
142
143    #[test]
144    fn test_current_json_deserialized_into_current_message() {
145        let json = CURRENT_JSON;
146        let message: SnapshotMessage = serde_json::from_str(json).unwrap();
147
148        assert_eq!(golden_message_current(), message);
149    }
150
151    #[test]
152    fn compute_total_size_with_ancillary_size() {
153        let message = SnapshotMessage {
154            size: 12,
155            ancillary_size: Some(33),
156            ..SnapshotMessage::dummy()
157        };
158
159        assert_eq!(message.compute_total_size(), 45);
160    }
161
162    #[test]
163    fn compute_total_size_without_ancillary_size() {
164        let message = SnapshotMessage {
165            size: 12,
166            ancillary_size: None,
167            ..SnapshotMessage::dummy()
168        };
169
170        assert_eq!(message.compute_total_size(), 12);
171    }
172}