Skip to main content

mithril_common/entities/
protocol_message.rs

1use serde::{Deserialize, Serialize};
2use sha2::{Digest, Sha256};
3use std::{collections::BTreeMap, fmt::Display};
4
5/// The key of a ProtocolMessage
6#[derive(Debug, Clone, Copy, Serialize, Deserialize, PartialEq, Eq, PartialOrd, Ord)]
7pub enum ProtocolMessagePartKey {
8    /// The ProtocolMessage part key associated to the Snapshot Digest
9    #[serde(rename = "snapshot_digest")]
10    SnapshotDigest,
11
12    /// The ProtocolMessage part key associated to the Cardano Transactions Merkle Root
13    #[serde(rename = "cardano_transactions_merkle_root")]
14    CardanoTransactionsMerkleRoot,
15
16    /// The ProtocolMessage part key associated to the Cardano Blocks and Transactions Merkle Root
17    #[serde(rename = "cardano_blocks_transactions_merkle_root")]
18    CardanoBlocksTransactionsMerkleRoot,
19
20    /// The ProtocolMessage part key associated to the Next epoch aggregate verification key
21    ///
22    /// The AVK that will be allowed to be used to sign during the next epoch
23    /// aka AVK(n-1)
24    #[serde(rename = "next_aggregate_verification_key")]
25    NextAggregateVerificationKey,
26
27    /// The ProtocolMessage part key associated to the Next epoch protocol parameters
28    ///
29    /// The protocol parameters that will be allowed to be used to sign during the next epoch
30    /// aka PPARAMS(n-1)
31    #[serde(rename = "next_protocol_parameters")]
32    NextProtocolParameters,
33
34    /// The ProtocolMessage part key associated to the current epoch
35    ///
36    /// aka EPOCH(n)
37    #[serde(rename = "current_epoch")]
38    CurrentEpoch,
39
40    /// The ProtocolMessage part key associated to the latest block number signed
41    #[serde(rename = "latest_block_number")]
42    LatestBlockNumber,
43
44    /// The ProtocolMessage part key associated to the security parameter block number offset of the CardanoBlocksTransactions
45    #[serde(rename = "cardano_blocks_transactions_block_number_offset")]
46    CardanoBlocksTransactionsBlockNumberOffset,
47
48    /// The ProtocolMessage part key associated to the epoch for which the Cardano stake distribution is computed
49    #[serde(rename = "cardano_stake_distribution_epoch")]
50    CardanoStakeDistributionEpoch,
51
52    /// The ProtocolMessage part key associated to the Cardano stake distribution Merkle root
53    #[serde(rename = "cardano_stake_distribution_merkle_root")]
54    CardanoStakeDistributionMerkleRoot,
55
56    /// The ProtocolMessage part key associated to the Cardano database Merkle root
57    #[serde(rename = "cardano_database_merkle_root")]
58    CardanoDatabaseMerkleRoot,
59
60    /// The ProtocolMessage part key associated to the Next epoch SNARK aggregate verification key
61    ///
62    /// The SNARK AVK that will be allowed to be used to sign during the next epoch
63    /// aka AVKS(n-1)
64    #[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
95/// The value of a ProtocolMessage
96pub type ProtocolMessagePartValue = String;
97
98/// ProtocolMessage represents a message that is signed (or verified) by the Mithril protocol
99#[derive(Clone, Debug, PartialEq, Eq, Default, Serialize, Deserialize)]
100pub struct ProtocolMessage {
101    /// Map of the messages combined into the digest
102    /// aka MSG(p,n)
103    pub message_parts: BTreeMap<ProtocolMessagePartKey, ProtocolMessagePartValue>,
104}
105
106impl ProtocolMessage {
107    /// ProtocolMessage factory
108    pub fn new() -> ProtocolMessage {
109        ProtocolMessage {
110            message_parts: BTreeMap::new(),
111        }
112    }
113
114    /// Set the message part associated with a key
115    /// Returns previously set value if it exists
116    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    /// Get the message part associated with a key
125    pub fn get_message_part(
126        &self,
127        key: &ProtocolMessagePartKey,
128    ) -> Option<&ProtocolMessagePartValue> {
129        self.message_parts.get(key)
130    }
131
132    /// Computes the hash of the protocol message
133    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}