1use serde::{Deserialize, Serialize};
2use sha2::{Digest, Sha256};
3use std::{collections::BTreeMap, fmt::Display};
4
5#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
7pub enum ProtocolMessagePartKey {
8 #[serde(rename = "snapshot_digest")]
10 SnapshotDigest,
11
12 #[serde(rename = "cardano_transactions_merkle_root")]
14 CardanoTransactionsMerkleRoot,
15
16 #[serde(rename = "cardano_blocks_transactions_merkle_root")]
18 CardanoBlocksTransactionsMerkleRoot,
19
20 #[serde(rename = "next_aggregate_verification_key")]
25 NextAggregateVerificationKey,
26
27 #[serde(rename = "next_protocol_parameters")]
32 NextProtocolParameters,
33
34 #[serde(rename = "current_epoch")]
38 CurrentEpoch,
39
40 #[serde(rename = "latest_block_number")]
42 LatestBlockNumber,
43
44 #[serde(rename = "cardano_blocks_transactions_block_number_offset")]
46 CardanoBlocksTransactionsBlockNumberOffset,
47
48 #[serde(rename = "cardano_stake_distribution_epoch")]
50 CardanoStakeDistributionEpoch,
51
52 #[serde(rename = "cardano_stake_distribution_merkle_root")]
54 CardanoStakeDistributionMerkleRoot,
55
56 #[serde(rename = "cardano_database_merkle_root")]
58 CardanoDatabaseMerkleRoot,
59
60 #[serde(rename = "next_aggregate_verification_key_snark")]
65 NextSnarkAggregateVerificationKey,
66}
67
68impl Display for ProtocolMessagePartKey {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 match *self {
71 Self::SnapshotDigest => write!(f, "snapshot_digest"),
72 Self::NextAggregateVerificationKey => write!(f, "next_aggregate_verification_key"),
73 Self::NextProtocolParameters => write!(f, "next_protocol_parameters"),
74 Self::CurrentEpoch => write!(f, "current_epoch"),
75 Self::CardanoTransactionsMerkleRoot => write!(f, "cardano_transactions_merkle_root"),
76 Self::CardanoBlocksTransactionsMerkleRoot => {
77 write!(f, "cardano_blocks_transactions_merkle_root")
78 }
79 Self::LatestBlockNumber => write!(f, "latest_block_number"),
80 Self::CardanoBlocksTransactionsBlockNumberOffset => {
81 write!(f, "cardano_blocks_transactions_block_number_offset")
82 }
83 Self::CardanoStakeDistributionEpoch => write!(f, "cardano_stake_distribution_epoch"),
84 Self::CardanoStakeDistributionMerkleRoot => {
85 write!(f, "cardano_stake_distribution_merkle_root")
86 }
87 Self::CardanoDatabaseMerkleRoot => write!(f, "cardano_database_merkle_root"),
88 Self::NextSnarkAggregateVerificationKey => {
89 write!(f, "next_aggregate_verification_key_snark")
90 }
91 }
92 }
93}
94
95pub type ProtocolMessagePartValue = String;
97
98#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
100pub struct ProtocolMessage {
101 pub message_parts: BTreeMap<ProtocolMessagePartKey, ProtocolMessagePartValue>,
104}
105
106impl ProtocolMessage {
107 pub fn new() -> ProtocolMessage {
109 ProtocolMessage {
110 message_parts: BTreeMap::new(),
111 }
112 }
113
114 pub fn set_message_part(
117 &mut self,
118 key: ProtocolMessagePartKey,
119 value: ProtocolMessagePartValue,
120 ) -> Option<ProtocolMessagePartValue> {
121 self.message_parts.insert(key, value)
122 }
123
124 pub fn get_message_part(
126 &self,
127 key: &ProtocolMessagePartKey,
128 ) -> Option<&ProtocolMessagePartValue> {
129 self.message_parts.get(key)
130 }
131
132 pub fn compute_hash(&self) -> String {
134 let mut hasher = Sha256::new();
135 self.message_parts.iter().for_each(|(k, v)| {
136 hasher.update(k.to_string().as_bytes());
137 hasher.update(v.as_bytes());
138 });
139 hex::encode(hasher.finalize())
140 }
141}
142
143#[cfg(test)]
144mod tests {
145 use super::*;
146
147 #[test]
148 fn test_protocol_message_compute_hash_include_next_aggregate_verification_key() {
149 let protocol_message = ProtocolMessage::new();
150 let hash_before_change = protocol_message.compute_hash();
151
152 let mut protocol_message_modified = protocol_message.clone();
153 protocol_message_modified.set_message_part(
154 ProtocolMessagePartKey::NextAggregateVerificationKey,
155 "next-avk-456".to_string(),
156 );
157
158 assert_ne!(hash_before_change, protocol_message_modified.compute_hash());
159 }
160
161 #[test]
162 fn test_protocol_message_compute_hash_include_snapshot_digest() {
163 let protocol_message = ProtocolMessage::new();
164 let hash_before_change = protocol_message.compute_hash();
165
166 let mut protocol_message_modified = protocol_message.clone();
167 protocol_message_modified.set_message_part(
168 ProtocolMessagePartKey::SnapshotDigest,
169 "snapshot-digest-456".to_string(),
170 );
171
172 assert_ne!(hash_before_change, protocol_message_modified.compute_hash());
173 }
174
175 #[test]
176 fn test_protocol_message_compute_hash_include_cardano_transactions_merkle_root() {
177 let protocol_message = ProtocolMessage::new();
178 let hash_before_change = protocol_message.compute_hash();
179
180 let mut protocol_message_modified = protocol_message.clone();
181 protocol_message_modified.set_message_part(
182 ProtocolMessagePartKey::CardanoTransactionsMerkleRoot,
183 "ctx-merke-root-456".to_string(),
184 );
185
186 assert_ne!(hash_before_change, protocol_message_modified.compute_hash());
187 }
188
189 #[test]
190 fn test_protocol_message_compute_hash_include_cardano_blocks_transactions_merkle_root() {
191 let protocol_message = ProtocolMessage::new();
192 let hash_before_change = protocol_message.compute_hash();
193
194 let mut protocol_message_modified = protocol_message.clone();
195 protocol_message_modified.set_message_part(
196 ProtocolMessagePartKey::CardanoBlocksTransactionsMerkleRoot,
197 "cardano-blocks-tx-merkle-root-456".to_string(),
198 );
199
200 assert_ne!(hash_before_change, protocol_message_modified.compute_hash());
201 }
202
203 #[test]
204 fn test_protocol_message_compute_hash_include_cardano_stake_distribution_epoch() {
205 let protocol_message = ProtocolMessage::new();
206 let hash_before_change = protocol_message.compute_hash();
207
208 let mut protocol_message_modified = protocol_message.clone();
209 protocol_message_modified.set_message_part(
210 ProtocolMessagePartKey::CardanoStakeDistributionEpoch,
211 "cardano-stake-distribution-epoch-456".to_string(),
212 );
213
214 assert_ne!(hash_before_change, protocol_message_modified.compute_hash());
215 }
216
217 #[test]
218 fn test_protocol_message_compute_hash_include_cardano_stake_distribution_merkle_root() {
219 let protocol_message = ProtocolMessage::new();
220 let hash_before_change = protocol_message.compute_hash();
221
222 let mut protocol_message_modified = protocol_message.clone();
223 protocol_message_modified.set_message_part(
224 ProtocolMessagePartKey::CardanoStakeDistributionMerkleRoot,
225 "cardano-stake-distribution-merkle-root-456".to_string(),
226 );
227
228 assert_ne!(hash_before_change, protocol_message_modified.compute_hash());
229 }
230
231 #[test]
232 fn test_protocol_message_compute_hash_include_lastest_immutable_file_number() {
233 let protocol_message = ProtocolMessage::new();
234 let hash_before_change = protocol_message.compute_hash();
235
236 let mut protocol_message_modified = protocol_message.clone();
237 protocol_message_modified.set_message_part(
238 ProtocolMessagePartKey::LatestBlockNumber,
239 "latest-immutable-file-number-456".to_string(),
240 );
241
242 assert_ne!(hash_before_change, protocol_message_modified.compute_hash());
243 }
244
245 #[test]
246 fn test_protocol_message_compute_hash_include_cardano_database_merkle_root() {
247 let protocol_message = ProtocolMessage::new();
248 let hash_before_change = protocol_message.compute_hash();
249
250 let mut protocol_message_modified = protocol_message.clone();
251 protocol_message_modified.set_message_part(
252 ProtocolMessagePartKey::CardanoDatabaseMerkleRoot,
253 "cardano-database-merkle-root-456".to_string(),
254 );
255
256 assert_ne!(hash_before_change, protocol_message_modified.compute_hash());
257 }
258
259 #[test]
260 fn test_protocol_message_compute_hash_include_next_snark_aggregate_verification_key() {
261 let protocol_message = ProtocolMessage::new();
262 let hash_before_change = protocol_message.compute_hash();
263
264 let mut protocol_message_modified = protocol_message.clone();
265 protocol_message_modified.set_message_part(
266 ProtocolMessagePartKey::NextSnarkAggregateVerificationKey,
267 "next-snark-avk-456".to_string(),
268 );
269
270 assert_ne!(hash_before_change, protocol_message_modified.compute_hash());
271 }
272
273 #[test]
274 fn test_protocol_message_compute_hash_include_next_protocol_parameters() {
275 let protocol_message = build_protocol_message_reference();
276 let hash_expected = protocol_message.compute_hash();
277
278 let mut protocol_message_modified = protocol_message.clone();
279 protocol_message_modified.set_message_part(
280 ProtocolMessagePartKey::NextProtocolParameters,
281 "latest-protocol-parameters-456".to_string(),
282 );
283
284 assert_ne!(hash_expected, protocol_message_modified.compute_hash());
285 }
286
287 #[test]
288 fn test_set_message_part_calling_order_have_no_influence_on_hash_computed() {
289 let mut protocol_message_a_b = build_protocol_message_reference();
290 protocol_message_a_b.set_message_part(
291 ProtocolMessagePartKey::CardanoBlocksTransactionsMerkleRoot,
292 "A".to_string(),
293 );
294 protocol_message_a_b.set_message_part(
295 ProtocolMessagePartKey::CardanoDatabaseMerkleRoot,
296 "B".to_string(),
297 );
298
299 let mut protocol_message_b_a = build_protocol_message_reference();
300 protocol_message_b_a.set_message_part(
301 ProtocolMessagePartKey::CardanoDatabaseMerkleRoot,
302 "B".to_string(),
303 );
304 protocol_message_b_a.set_message_part(
305 ProtocolMessagePartKey::CardanoBlocksTransactionsMerkleRoot,
306 "A".to_string(),
307 );
308
309 assert_eq!(
310 protocol_message_a_b.compute_hash(),
311 protocol_message_b_a.compute_hash()
312 );
313 }
314
315 #[test]
316 fn test_protocol_message_compute_hash_the_same_hash_with_same_protocol_message() {
317 assert_eq!(
318 build_protocol_message_reference().compute_hash(),
319 build_protocol_message_reference().compute_hash()
320 );
321 }
322
323 fn build_protocol_message_reference() -> ProtocolMessage {
324 let mut protocol_message = ProtocolMessage::new();
325 protocol_message.set_message_part(
326 ProtocolMessagePartKey::SnapshotDigest,
327 "snapshot-digest-123".to_string(),
328 );
329 protocol_message.set_message_part(
330 ProtocolMessagePartKey::NextAggregateVerificationKey,
331 "next-avk-123".to_string(),
332 );
333 protocol_message.set_message_part(
334 ProtocolMessagePartKey::NextProtocolParameters,
335 "next-protocol-parameters-123".to_string(),
336 );
337 protocol_message.set_message_part(
338 ProtocolMessagePartKey::CardanoTransactionsMerkleRoot,
339 "ctx-merkle-root-123".to_string(),
340 );
341 protocol_message.set_message_part(
342 ProtocolMessagePartKey::CardanoBlocksTransactionsMerkleRoot,
343 "cardano-blocks-tx-merkle-root-123".to_string(),
344 );
345 protocol_message.set_message_part(
346 ProtocolMessagePartKey::LatestBlockNumber,
347 "latest-immutable-file-number-123".to_string(),
348 );
349 protocol_message.set_message_part(
350 ProtocolMessagePartKey::CardanoStakeDistributionEpoch,
351 "cardano-stake-distribution-epoch-123".to_string(),
352 );
353 protocol_message.set_message_part(
354 ProtocolMessagePartKey::CardanoStakeDistributionMerkleRoot,
355 "cardano-stake-distribution-merkle-root-123".to_string(),
356 );
357 protocol_message.set_message_part(
358 ProtocolMessagePartKey::CardanoDatabaseMerkleRoot,
359 "cardano-database-merkle-root-123".to_string(),
360 );
361
362 protocol_message
363 }
364}