dpp/voting/contender_structs/contender/
mod.rs

1pub mod v0;
2
3use crate::data_contract::document_type::DocumentTypeRef;
4use crate::data_contract::DataContract;
5use crate::document::Document;
6#[cfg(feature = "json-conversion")]
7use crate::serialization::JsonConvertible;
8#[cfg(feature = "value-conversion")]
9use crate::serialization::ValueConvertible;
10use crate::serialization::{PlatformDeserializable, PlatformSerializable};
11use crate::voting::contender_structs::contender::v0::ContenderV0;
12use crate::voting::contender_structs::ContenderWithSerializedDocumentV0;
13use crate::ProtocolError;
14use bincode::{Decode, Encode};
15use derive_more::From;
16use platform_serialization_derive::{PlatformDeserialize, PlatformSerialize};
17use platform_value::Identifier;
18use platform_version::version::PlatformVersion;
19
20/// Represents a contender in the contested document vote poll.
21///
22/// This struct holds the identity ID of the contender, the serialized document,
23/// and the vote tally.
24#[derive(Debug, PartialEq, Clone, From)]
25pub enum Contender {
26    /// V0
27    V0(ContenderV0),
28}
29
30/// Represents a contender in the contested document vote poll.
31/// This is for internal use where the document is in serialized form
32///
33/// This struct holds the identity ID of the contender, the serialized document,
34/// and the vote tally.
35#[cfg_attr(
36    all(feature = "json-conversion", feature = "serde-conversion"),
37    derive(JsonConvertible)
38)]
39#[derive(
40    Debug, PartialEq, Eq, Clone, From, Encode, Decode, PlatformSerialize, PlatformDeserialize,
41)]
42#[cfg_attr(
43    feature = "serde-conversion",
44    derive(serde::Serialize, serde::Deserialize),
45    serde(tag = "$formatVersion")
46)]
47#[cfg_attr(feature = "value-conversion", derive(ValueConvertible))]
48#[platform_serialize(unversioned)]
49pub enum ContenderWithSerializedDocument {
50    /// V0
51    #[cfg_attr(feature = "serde-conversion", serde(rename = "0"))]
52    V0(ContenderWithSerializedDocumentV0),
53}
54
55impl Contender {
56    pub fn identity_id(&self) -> Identifier {
57        match self {
58            Contender::V0(v0) => v0.identity_id,
59        }
60    }
61
62    pub fn identity_id_ref(&self) -> &Identifier {
63        match self {
64            Contender::V0(v0) => &v0.identity_id,
65        }
66    }
67
68    pub fn document(&self) -> &Option<Document> {
69        match self {
70            Contender::V0(v0) => &v0.document,
71        }
72    }
73
74    pub fn take_document(&mut self) -> Option<Document> {
75        match self {
76            Contender::V0(v0) => v0.document.take(),
77        }
78    }
79
80    pub fn vote_tally(&self) -> Option<u32> {
81        match self {
82            Contender::V0(v0) => v0.vote_tally,
83        }
84    }
85}
86
87impl ContenderWithSerializedDocument {
88    pub fn identity_id(&self) -> Identifier {
89        match self {
90            ContenderWithSerializedDocument::V0(v0) => v0.identity_id,
91        }
92    }
93
94    pub fn identity_id_ref(&self) -> &Identifier {
95        match self {
96            ContenderWithSerializedDocument::V0(v0) => &v0.identity_id,
97        }
98    }
99
100    pub fn serialized_document(&self) -> &Option<Vec<u8>> {
101        match self {
102            ContenderWithSerializedDocument::V0(v0) => &v0.serialized_document,
103        }
104    }
105
106    pub fn take_serialized_document(&mut self) -> Option<Vec<u8>> {
107        match self {
108            ContenderWithSerializedDocument::V0(v0) => v0.serialized_document.take(),
109        }
110    }
111
112    pub fn vote_tally(&self) -> Option<u32> {
113        match self {
114            ContenderWithSerializedDocument::V0(v0) => v0.vote_tally,
115        }
116    }
117}
118
119impl ContenderWithSerializedDocument {
120    pub fn try_into_contender(
121        self,
122        document_type_ref: DocumentTypeRef,
123        platform_version: &PlatformVersion,
124    ) -> Result<Contender, ProtocolError> {
125        match self {
126            ContenderWithSerializedDocument::V0(v0) => Ok(v0
127                .try_into_contender(document_type_ref, platform_version)?
128                .into()),
129        }
130    }
131
132    pub fn try_to_contender(
133        &self,
134        document_type_ref: DocumentTypeRef,
135        platform_version: &PlatformVersion,
136    ) -> Result<Contender, ProtocolError> {
137        match self {
138            ContenderWithSerializedDocument::V0(v0) => Ok(v0
139                .try_to_contender(document_type_ref, platform_version)?
140                .into()),
141        }
142    }
143}
144
145impl Contender {
146    pub fn try_into_contender_with_serialized_document(
147        self,
148        document_type_ref: DocumentTypeRef,
149        data_contract: &DataContract,
150        platform_version: &PlatformVersion,
151    ) -> Result<ContenderWithSerializedDocument, ProtocolError> {
152        match self {
153            Contender::V0(v0) => Ok(v0
154                .try_into_contender_with_serialized_document(
155                    document_type_ref,
156                    data_contract,
157                    platform_version,
158                )?
159                .into()),
160        }
161    }
162
163    pub fn try_to_contender_with_serialized_document(
164        &self,
165        document_type_ref: DocumentTypeRef,
166        data_contract: &DataContract,
167        platform_version: &PlatformVersion,
168    ) -> Result<ContenderWithSerializedDocument, ProtocolError> {
169        match self {
170            Contender::V0(v0) => Ok(v0
171                .try_to_contender_with_serialized_document(
172                    document_type_ref,
173                    data_contract,
174                    platform_version,
175                )?
176                .into()),
177        }
178    }
179
180    pub fn serialize(
181        &self,
182        document_type: DocumentTypeRef,
183        data_contract: &DataContract,
184        platform_version: &PlatformVersion,
185    ) -> Result<Vec<u8>, ProtocolError> {
186        self.try_to_contender_with_serialized_document(
187            document_type,
188            data_contract,
189            platform_version,
190        )?
191        .serialize_to_bytes()
192    }
193
194    pub fn serialize_consume(
195        self,
196        document_type: DocumentTypeRef,
197        data_contract: &DataContract,
198        platform_version: &PlatformVersion,
199    ) -> Result<Vec<u8>, ProtocolError> {
200        self.try_into_contender_with_serialized_document(
201            document_type,
202            data_contract,
203            platform_version,
204        )?
205        .serialize_to_bytes()
206    }
207
208    pub fn from_bytes(
209        serialized_contender: &[u8],
210        document_type: DocumentTypeRef,
211        platform_version: &PlatformVersion,
212    ) -> Result<Self, ProtocolError>
213    where
214        Self: Sized,
215    {
216        let serialized_contender =
217            ContenderWithSerializedDocument::deserialize_from_bytes(serialized_contender)?;
218        serialized_contender.try_into_contender(document_type, platform_version)
219    }
220}
221
222#[cfg(test)]
223mod tests {
224    use super::*;
225    use crate::voting::contender_structs::contender::v0::{
226        ContenderV0, ContenderWithSerializedDocumentV0,
227    };
228    use platform_value::Identifier;
229
230    mod contender_construction {
231        use super::*;
232
233        #[test]
234        fn contender_v0_default() {
235            let contender = ContenderV0::default();
236            assert_eq!(contender.identity_id, Identifier::default());
237            assert!(contender.document.is_none());
238            assert!(contender.vote_tally.is_none());
239        }
240
241        #[test]
242        fn contender_v0_with_fields() {
243            let id = Identifier::new([1u8; 32]);
244            let contender = ContenderV0 {
245                identity_id: id,
246                document: None,
247                vote_tally: Some(42),
248            };
249            assert_eq!(contender.identity_id, id);
250            assert!(contender.document.is_none());
251            assert_eq!(contender.vote_tally, Some(42));
252        }
253
254        #[test]
255        fn contender_from_v0() {
256            let id = Identifier::new([2u8; 32]);
257            let v0 = ContenderV0 {
258                identity_id: id,
259                document: None,
260                vote_tally: Some(100),
261            };
262            let contender: Contender = v0.into();
263            assert_eq!(contender.identity_id(), id);
264            assert_eq!(contender.vote_tally(), Some(100));
265        }
266    }
267
268    mod contender_accessors {
269        use super::*;
270
271        #[test]
272        fn identity_id_returns_correct_value() {
273            let id = Identifier::new([3u8; 32]);
274            let contender = Contender::V0(ContenderV0 {
275                identity_id: id,
276                document: None,
277                vote_tally: None,
278            });
279            assert_eq!(contender.identity_id(), id);
280        }
281
282        #[test]
283        fn identity_id_ref_returns_reference() {
284            let id = Identifier::new([4u8; 32]);
285            let contender = Contender::V0(ContenderV0 {
286                identity_id: id,
287                document: None,
288                vote_tally: None,
289            });
290            assert_eq!(*contender.identity_id_ref(), id);
291        }
292
293        #[test]
294        fn document_returns_none_when_empty() {
295            let contender = Contender::V0(ContenderV0::default());
296            assert!(contender.document().is_none());
297        }
298
299        #[test]
300        fn vote_tally_returns_none_when_not_set() {
301            let contender = Contender::V0(ContenderV0::default());
302            assert!(contender.vote_tally().is_none());
303        }
304
305        #[test]
306        fn vote_tally_returns_value_when_set() {
307            let contender = Contender::V0(ContenderV0 {
308                identity_id: Identifier::default(),
309                document: None,
310                vote_tally: Some(999),
311            });
312            assert_eq!(contender.vote_tally(), Some(999));
313        }
314
315        #[test]
316        fn take_document_returns_none_and_leaves_none() {
317            let mut contender = Contender::V0(ContenderV0::default());
318            let doc = contender.take_document();
319            assert!(doc.is_none());
320            assert!(contender.document().is_none());
321        }
322    }
323
324    mod contender_with_serialized_document {
325        use super::*;
326
327        #[test]
328        fn default_values() {
329            let csd = ContenderWithSerializedDocumentV0::default();
330            assert_eq!(csd.identity_id, Identifier::default());
331            assert!(csd.serialized_document.is_none());
332            assert!(csd.vote_tally.is_none());
333        }
334
335        #[test]
336        fn construction_with_data() {
337            let id = Identifier::new([5u8; 32]);
338            let doc_bytes = vec![1, 2, 3, 4, 5];
339            let csd = ContenderWithSerializedDocumentV0 {
340                identity_id: id,
341                serialized_document: Some(doc_bytes.clone()),
342                vote_tally: Some(50),
343            };
344            let wrapped = ContenderWithSerializedDocument::V0(csd);
345            assert_eq!(wrapped.identity_id(), id);
346            assert_eq!(*wrapped.identity_id_ref(), id);
347            assert_eq!(wrapped.serialized_document(), &Some(doc_bytes));
348            assert_eq!(wrapped.vote_tally(), Some(50));
349        }
350
351        #[test]
352        fn take_serialized_document() {
353            let doc_bytes = vec![10, 20, 30];
354            let csd = ContenderWithSerializedDocumentV0 {
355                identity_id: Identifier::default(),
356                serialized_document: Some(doc_bytes.clone()),
357                vote_tally: None,
358            };
359            let mut wrapped = ContenderWithSerializedDocument::V0(csd);
360            let taken = wrapped.take_serialized_document();
361            assert_eq!(taken, Some(doc_bytes));
362            assert!(wrapped.serialized_document().is_none());
363        }
364
365        #[test]
366        fn serialization_round_trip() {
367            let id = Identifier::new([6u8; 32]);
368            let csd = ContenderWithSerializedDocumentV0 {
369                identity_id: id,
370                serialized_document: Some(vec![0xAA, 0xBB, 0xCC]),
371                vote_tally: Some(77),
372            };
373            let wrapped = ContenderWithSerializedDocument::V0(csd);
374
375            // Serialize to bytes using PlatformSerializable
376            let bytes = wrapped
377                .serialize_to_bytes()
378                .expect("should serialize to bytes");
379            assert!(!bytes.is_empty());
380
381            // Deserialize back
382            let restored = ContenderWithSerializedDocument::deserialize_from_bytes(&bytes)
383                .expect("should deserialize from bytes");
384
385            assert_eq!(wrapped, restored);
386        }
387
388        #[test]
389        fn serialization_round_trip_with_no_document() {
390            let id = Identifier::new([7u8; 32]);
391            let csd = ContenderWithSerializedDocumentV0 {
392                identity_id: id,
393                serialized_document: None,
394                vote_tally: None,
395            };
396            let wrapped = ContenderWithSerializedDocument::V0(csd);
397
398            let bytes = wrapped
399                .serialize_to_bytes()
400                .expect("should serialize to bytes");
401            let restored = ContenderWithSerializedDocument::deserialize_from_bytes(&bytes)
402                .expect("should deserialize from bytes");
403
404            assert_eq!(wrapped, restored);
405        }
406    }
407
408    mod equality {
409        use super::*;
410
411        #[test]
412        fn equal_contenders() {
413            let id = Identifier::new([8u8; 32]);
414            let a = Contender::V0(ContenderV0 {
415                identity_id: id,
416                document: None,
417                vote_tally: Some(10),
418            });
419            let b = Contender::V0(ContenderV0 {
420                identity_id: id,
421                document: None,
422                vote_tally: Some(10),
423            });
424            assert_eq!(a, b);
425        }
426
427        #[test]
428        fn different_vote_tallies_not_equal() {
429            let id = Identifier::new([9u8; 32]);
430            let a = Contender::V0(ContenderV0 {
431                identity_id: id,
432                document: None,
433                vote_tally: Some(10),
434            });
435            let b = Contender::V0(ContenderV0 {
436                identity_id: id,
437                document: None,
438                vote_tally: Some(20),
439            });
440            assert_ne!(a, b);
441        }
442
443        #[test]
444        fn different_identity_ids_not_equal() {
445            let a = Contender::V0(ContenderV0 {
446                identity_id: Identifier::new([1u8; 32]),
447                document: None,
448                vote_tally: None,
449            });
450            let b = Contender::V0(ContenderV0 {
451                identity_id: Identifier::new([2u8; 32]),
452                document: None,
453                vote_tally: None,
454            });
455            assert_ne!(a, b);
456        }
457    }
458}