1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3use std::fmt::{Debug, Formatter};
4
5use crate::entities::{
6 Epoch, ProtocolMessage, ProtocolParameters, ProtocolVersion, SignedEntityType,
7};
8
9pub type CertificateListMessage = Vec<CertificateListItemMessage>;
11
12#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
14pub struct CertificateListItemMessageMetadata {
15 pub network: String,
18
19 #[serde(rename = "version")]
23 pub protocol_version: ProtocolVersion,
24
25 #[serde(rename = "parameters")]
28 pub protocol_parameters: ProtocolParameters,
29
30 pub initiated_at: DateTime<Utc>,
34
35 pub sealed_at: DateTime<Utc>,
39
40 pub total_signers: usize,
43}
44
45#[derive(Clone, PartialEq, Serialize, Deserialize)]
47pub struct CertificateListItemMessage {
48 pub hash: String,
52
53 pub previous_hash: String,
58
59 pub epoch: Epoch,
61
62 pub signed_entity_type: SignedEntityType,
65
66 pub metadata: CertificateListItemMessageMetadata,
69
70 pub protocol_message: ProtocolMessage,
73
74 pub signed_message: String,
77
78 pub aggregate_verification_key: String,
82}
83
84impl Debug for CertificateListItemMessage {
85 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
86 let should_be_exhaustive = f.alternate();
87 let mut debug = f.debug_struct("Certificate");
88 debug
89 .field("hash", &self.hash)
90 .field("previous_hash", &self.previous_hash)
91 .field("epoch", &format_args!("{:?}", self.epoch))
92 .field(
93 "signed_entity_type",
94 &format_args!("{:?}", self.signed_entity_type),
95 )
96 .field("metadata", &format_args!("{:?}", self.metadata))
97 .field(
98 "protocol_message",
99 &format_args!("{:?}", self.protocol_message),
100 )
101 .field("signed_message", &self.signed_message);
102
103 match should_be_exhaustive {
104 true => debug
105 .field(
106 "aggregate_verification_key",
107 &self.aggregate_verification_key,
108 )
109 .finish(),
110 false => debug.finish_non_exhaustive(),
111 }
112 }
113}
114
115#[cfg(test)]
116mod tests {
117 use crate::entities::{CardanoDbBeacon, ProtocolMessagePartKey};
118
119 use super::*;
120
121 const CURRENT_JSON: &str = r#"[{
122 "hash": "hash",
123 "previous_hash": "previous_hash",
124 "epoch": 10,
125 "signed_entity_type": {
126 "CardanoImmutableFilesFull": {
127 "epoch": 10,
128 "immutable_file_number": 1728
129 }
130 },
131 "metadata": {
132 "network": "testnet",
133 "version": "0.1.0",
134 "parameters": {
135 "k": 1000,
136 "m": 100,
137 "phi_f": 0.123
138 },
139 "initiated_at": "2024-02-12T13:11:47Z",
140 "sealed_at": "2024-02-12T13:12:57Z",
141 "total_signers": 2
142 },
143 "protocol_message": {
144 "message_parts": {
145 "snapshot_digest": "snapshot-digest-123",
146 "next_aggregate_verification_key": "next-avk-123"
147 }
148 },
149 "signed_message": "signed_message",
150 "aggregate_verification_key": "aggregate_verification_key"
151 }]"#;
152
153 fn golden_current_message() -> CertificateListItemMessage {
154 let mut protocol_message = ProtocolMessage::new();
155 protocol_message.set_message_part(
156 ProtocolMessagePartKey::SnapshotDigest,
157 "snapshot-digest-123".to_string(),
158 );
159 protocol_message.set_message_part(
160 ProtocolMessagePartKey::NextAggregateVerificationKey,
161 "next-avk-123".to_string(),
162 );
163 let epoch = Epoch(10);
164
165 CertificateListItemMessage {
166 hash: "hash".to_string(),
167 previous_hash: "previous_hash".to_string(),
168 epoch,
169 signed_entity_type: SignedEntityType::CardanoImmutableFilesFull(CardanoDbBeacon::new(
170 *epoch, 1728,
171 )),
172 metadata: CertificateListItemMessageMetadata {
173 network: "testnet".to_string(),
174 protocol_version: "0.1.0".to_string(),
175 protocol_parameters: ProtocolParameters::new(1000, 100, 0.123),
176 initiated_at: DateTime::parse_from_rfc3339("2024-02-12T13:11:47Z")
177 .unwrap()
178 .with_timezone(&Utc),
179 sealed_at: DateTime::parse_from_rfc3339("2024-02-12T13:12:57Z")
180 .unwrap()
181 .with_timezone(&Utc),
182 total_signers: 2,
183 },
184 protocol_message: protocol_message.clone(),
185 signed_message: "signed_message".to_string(),
186 aggregate_verification_key: "aggregate_verification_key".to_string(),
187 }
188 }
189
190 #[test]
191 fn test_current_json_deserialized_into_current_message() {
192 let json = CURRENT_JSON;
193 let message: CertificateListMessage = serde_json::from_str(json).unwrap();
194
195 assert_eq!(vec![golden_current_message()], message);
196 }
197}