1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
use chrono::{DateTime, Utc};

use mithril_common::entities::{
    Epoch, PartyId, ProtocolMessage, SignedEntityType, SingleSignatures,
};

use crate::database::record::{OpenMessageRecord, OpenMessageWithSingleSignaturesRecord};

/// ## OpenMessage
///
/// An open message is a message open for signatures. Every signer may send a
/// single signature for this message from which a multi signature will be
/// generated if possible.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct OpenMessage {
    /// Epoch
    pub epoch: Epoch,

    /// Type of message
    pub signed_entity_type: SignedEntityType,

    /// Message used by the Mithril Protocol
    pub protocol_message: ProtocolMessage,

    /// Has this message been converted into a Certificate?
    pub is_certified: bool,

    /// Has this open message expired
    pub is_expired: bool,

    /// associated single signatures
    pub single_signatures: Vec<SingleSignatures>,

    /// Message creation datetime
    pub created_at: DateTime<Utc>,

    /// Message expiration datetime, if it exists.
    pub expires_at: Option<DateTime<Utc>>,
}

impl OpenMessage {
    /// Gather all signers party_id for this open message
    pub fn get_signers_id(&self) -> Vec<PartyId> {
        self.single_signatures
            .iter()
            .map(|sig| sig.party_id.to_owned())
            .collect()
    }

    #[cfg(test)]
    /// Create a dumb OpenMessage instance mainly for test purposes
    pub fn dummy() -> Self {
        use mithril_common::test_utils::fake_data;

        let beacon = fake_data::beacon();
        let epoch = beacon.epoch;
        let signed_entity_type = SignedEntityType::CardanoImmutableFilesFull(beacon);

        Self {
            epoch,
            signed_entity_type,
            protocol_message: ProtocolMessage::new(),
            is_certified: false,
            is_expired: false,
            single_signatures: vec![
                fake_data::single_signatures(vec![1, 4, 5]),
                fake_data::single_signatures(vec![2, 3, 8]),
            ],
            created_at: Utc::now(),
            expires_at: None,
        }
    }
}

impl From<OpenMessageRecord> for OpenMessage {
    fn from(record: OpenMessageRecord) -> Self {
        Self {
            epoch: record.epoch,
            signed_entity_type: record.signed_entity_type,
            protocol_message: record.protocol_message,
            is_certified: record.is_certified,
            is_expired: record.is_expired,
            single_signatures: vec![],
            created_at: record.created_at,
            expires_at: record.expires_at,
        }
    }
}

impl From<OpenMessageWithSingleSignaturesRecord> for OpenMessage {
    fn from(record: OpenMessageWithSingleSignaturesRecord) -> Self {
        Self {
            epoch: record.epoch,
            signed_entity_type: record.signed_entity_type,
            protocol_message: record.protocol_message,
            is_certified: record.is_certified,
            is_expired: record.is_expired,
            single_signatures: record.single_signatures,
            created_at: record.created_at,
            expires_at: record.expires_at,
        }
    }
}

#[cfg(test)]
mod test {
    use chrono::Utc;
    use uuid::Uuid;

    use mithril_common::{
        entities::{Epoch, ProtocolMessage, SignedEntityType},
        test_utils::fake_data,
    };

    use crate::database::record::{OpenMessageRecord, OpenMessageWithSingleSignaturesRecord};

    use super::OpenMessage;

    #[test]
    fn test_from_record() {
        let created_at = Utc::now();
        let record = OpenMessageRecord {
            open_message_id: Uuid::new_v4(),
            epoch: Epoch(1),
            signed_entity_type: SignedEntityType::dummy(),
            protocol_message: ProtocolMessage::default(),
            is_certified: false,
            is_expired: false,
            created_at,
            expires_at: None,
        };
        let expected = OpenMessage {
            epoch: Epoch(1),
            signed_entity_type: SignedEntityType::dummy(),
            protocol_message: ProtocolMessage::default(),
            is_certified: false,
            is_expired: false,
            single_signatures: vec![],
            created_at,
            expires_at: None,
        };
        let result: OpenMessage = record.into();

        assert_eq!(expected, result);
    }

    #[test]
    fn test_from_record_with_single_signatures() {
        let created_at = Utc::now();
        let record = OpenMessageWithSingleSignaturesRecord {
            open_message_id: Uuid::new_v4(),
            epoch: Epoch(1),
            signed_entity_type: SignedEntityType::dummy(),
            protocol_message: ProtocolMessage::default(),
            is_certified: false,
            is_expired: false,
            created_at,
            expires_at: None,
            single_signatures: vec![fake_data::single_signatures(vec![1, 4, 5])],
        };
        let expected = OpenMessage {
            epoch: Epoch(1),
            signed_entity_type: SignedEntityType::dummy(),
            protocol_message: ProtocolMessage::default(),
            is_certified: false,
            is_expired: false,
            single_signatures: vec![fake_data::single_signatures(vec![1, 4, 5])],
            created_at,
            expires_at: None,
        };
        let result: OpenMessage = record.into();

        assert_eq!(expected, result);
    }
}