use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use std::fmt::{Debug, Formatter};
use crate::entities::{
Epoch, ProtocolMessage, ProtocolMessagePartKey, ProtocolParameters, ProtocolVersion,
};
use crate::messages::SignedEntityTypeMessagePart;
pub type CertificateListMessage = Vec<CertificateListItemMessage>;
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct CertificateListItemMessageMetadata {
pub network: String,
#[serde(rename = "version")]
pub protocol_version: ProtocolVersion,
#[serde(rename = "parameters")]
pub protocol_parameters: ProtocolParameters,
pub initiated_at: DateTime<Utc>,
pub sealed_at: DateTime<Utc>,
pub total_signers: usize,
}
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct CertificateListItemMessage {
pub hash: String,
pub previous_hash: String,
pub epoch: Epoch,
pub signed_entity_type: SignedEntityTypeMessagePart,
pub metadata: CertificateListItemMessageMetadata,
pub protocol_message: ProtocolMessage,
pub signed_message: String,
pub aggregate_verification_key: String,
}
impl CertificateListItemMessage {
pub fn dummy() -> Self {
let mut protocol_message = ProtocolMessage::new();
protocol_message.set_message_part(
ProtocolMessagePartKey::SnapshotDigest,
"snapshot-digest-123".to_string(),
);
protocol_message.set_message_part(
ProtocolMessagePartKey::NextAggregateVerificationKey,
"next-avk-123".to_string(),
);
let epoch = Epoch(10);
Self {
hash: "hash".to_string(),
previous_hash: "previous_hash".to_string(),
epoch,
signed_entity_type: SignedEntityTypeMessagePart::MithrilStakeDistribution(epoch),
metadata: CertificateListItemMessageMetadata {
network: "testnet".to_string(),
protocol_version: "0.1.0".to_string(),
protocol_parameters: ProtocolParameters::new(1000, 100, 0.123),
initiated_at: DateTime::parse_from_rfc3339("2024-02-12T13:11:47Z")
.unwrap()
.with_timezone(&Utc),
sealed_at: DateTime::parse_from_rfc3339("2024-02-12T13:12:57Z")
.unwrap()
.with_timezone(&Utc),
total_signers: 2,
},
protocol_message: protocol_message.clone(),
signed_message: "signed_message".to_string(),
aggregate_verification_key: "aggregate_verification_key".to_string(),
}
}
}
impl Debug for CertificateListItemMessage {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let should_be_exhaustive = f.alternate();
let mut debug = f.debug_struct("Certificate");
debug
.field("hash", &self.hash)
.field("previous_hash", &self.previous_hash)
.field("epoch", &format_args!("{:?}", self.epoch))
.field(
"signed_entity_type",
&format_args!("{:?}", self.signed_entity_type),
)
.field("metadata", &format_args!("{:?}", self.metadata))
.field(
"protocol_message",
&format_args!("{:?}", self.protocol_message),
)
.field("signed_message", &self.signed_message);
match should_be_exhaustive {
true => debug
.field(
"aggregate_verification_key",
&self.aggregate_verification_key,
)
.finish(),
false => debug.finish_non_exhaustive(),
}
}
}
#[cfg(test)]
mod tests {
use crate::entities::CardanoDbBeacon;
use crate::messages::CardanoDbBeaconMessagePart;
use super::*;
const ACTUAL_JSON: &str = r#"[{
"hash": "hash",
"previous_hash": "previous_hash",
"epoch": 10,
"signed_entity_type": {
"CardanoImmutableFilesFull": {
"network": "testnet",
"epoch": 10,
"immutable_file_number": 1728
}
},
"metadata": {
"network": "testnet",
"version": "0.1.0",
"parameters": {
"k": 1000,
"m": 100,
"phi_f": 0.123
},
"initiated_at": "2024-02-12T13:11:47Z",
"sealed_at": "2024-02-12T13:12:57Z",
"total_signers": 2
},
"protocol_message": {
"message_parts": {
"snapshot_digest": "snapshot-digest-123",
"next_aggregate_verification_key": "next-avk-123"
}
},
"signed_message": "signed_message",
"aggregate_verification_key": "aggregate_verification_key"
}]"#;
type CertificateListMessageUntilV0_1_32 = Vec<CertificateListItemMessageUntilV0_1_32>;
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct CertificateListItemMessageUntilV0_1_32 {
pub hash: String,
pub previous_hash: String,
pub epoch: Epoch,
pub signed_entity_type: SignedEntityTypeMessagePart,
#[serde(skip_serializing_if = "Option::is_none")]
pub beacon: Option<CardanoDbBeacon>,
pub metadata: CertificateListItemMessageMetadata,
pub protocol_message: ProtocolMessage,
pub signed_message: String,
pub aggregate_verification_key: String,
}
fn golden_message_until_open_api_0_1_32() -> CertificateListItemMessageUntilV0_1_32 {
let mut protocol_message = ProtocolMessage::new();
protocol_message.set_message_part(
ProtocolMessagePartKey::SnapshotDigest,
"snapshot-digest-123".to_string(),
);
protocol_message.set_message_part(
ProtocolMessagePartKey::NextAggregateVerificationKey,
"next-avk-123".to_string(),
);
let epoch = Epoch(10);
CertificateListItemMessageUntilV0_1_32 {
hash: "hash".to_string(),
previous_hash: "previous_hash".to_string(),
epoch,
signed_entity_type: SignedEntityTypeMessagePart::CardanoImmutableFilesFull(
CardanoDbBeaconMessagePart::new("testnet", epoch, 1728),
),
beacon: None,
metadata: CertificateListItemMessageMetadata {
network: "testnet".to_string(),
protocol_version: "0.1.0".to_string(),
protocol_parameters: ProtocolParameters::new(1000, 100, 0.123),
initiated_at: DateTime::parse_from_rfc3339("2024-02-12T13:11:47Z")
.unwrap()
.with_timezone(&Utc),
sealed_at: DateTime::parse_from_rfc3339("2024-02-12T13:12:57Z")
.unwrap()
.with_timezone(&Utc),
total_signers: 2,
},
protocol_message: protocol_message.clone(),
signed_message: "signed_message".to_string(),
aggregate_verification_key: "aggregate_verification_key".to_string(),
}
}
fn golden_actual_message() -> CertificateListItemMessage {
let mut protocol_message = ProtocolMessage::new();
protocol_message.set_message_part(
ProtocolMessagePartKey::SnapshotDigest,
"snapshot-digest-123".to_string(),
);
protocol_message.set_message_part(
ProtocolMessagePartKey::NextAggregateVerificationKey,
"next-avk-123".to_string(),
);
let epoch = Epoch(10);
CertificateListItemMessage {
hash: "hash".to_string(),
previous_hash: "previous_hash".to_string(),
epoch,
signed_entity_type: SignedEntityTypeMessagePart::CardanoImmutableFilesFull(
CardanoDbBeaconMessagePart::new("testnet", epoch, 1728),
),
metadata: CertificateListItemMessageMetadata {
network: "testnet".to_string(),
protocol_version: "0.1.0".to_string(),
protocol_parameters: ProtocolParameters::new(1000, 100, 0.123),
initiated_at: DateTime::parse_from_rfc3339("2024-02-12T13:11:47Z")
.unwrap()
.with_timezone(&Utc),
sealed_at: DateTime::parse_from_rfc3339("2024-02-12T13:12:57Z")
.unwrap()
.with_timezone(&Utc),
total_signers: 2,
},
protocol_message: protocol_message.clone(),
signed_message: "signed_message".to_string(),
aggregate_verification_key: "aggregate_verification_key".to_string(),
}
}
#[test]
fn test_actual_json_deserialized_into_message_supported_until_open_api_0_1_32() {
let json = ACTUAL_JSON;
let message: CertificateListMessageUntilV0_1_32 = serde_json::from_str(json).unwrap();
assert_eq!(vec![golden_message_until_open_api_0_1_32()], message);
}
#[test]
fn test_actual_json_deserialized_into_actual_message() {
let json = ACTUAL_JSON;
let message: CertificateListMessage = serde_json::from_str(json).unwrap();
assert_eq!(vec![golden_actual_message()], message);
}
}