dpp/voting/contender_structs/
mod.rs1mod contender;
2
3use crate::data_contract::document_type::DocumentTypeRef;
4use crate::document::serialization_traits::DocumentPlatformConversionMethodsV0;
5use crate::document::Document;
6use crate::voting::vote_choices::resource_vote_choice::ResourceVoteChoice;
7use crate::ProtocolError;
8use bincode::{Decode, Encode};
9use platform_value::Identifier;
10use platform_version::version::PlatformVersion;
11use std::fmt;
12
13pub use contender::v0::{ContenderV0, ContenderWithSerializedDocumentV0};
14pub use contender::{Contender, ContenderWithSerializedDocument};
15
16#[derive(Debug, PartialEq, Eq, Clone, Default)]
22pub struct FinalizedContenderWithSerializedDocument {
23 pub identity_id: Identifier,
25 pub serialized_document: Vec<u8>,
27 pub final_vote_tally: u32,
29}
30
31#[derive(Debug, PartialEq, Eq, Clone, Default, Encode, Decode)]
37pub struct FinalizedResourceVoteChoicesWithVoterInfo {
38 pub resource_vote_choice: ResourceVoteChoice,
40 pub voters: Vec<(Identifier, u8)>,
42}
43impl fmt::Display for FinalizedResourceVoteChoicesWithVoterInfo {
44 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
45 let voters_str: Vec<String> = self
46 .voters
47 .iter()
48 .map(|(id, strength)| format!("{}:{}", id, strength))
49 .collect();
50 write!(
51 f,
52 "FinalizedResourceVoteChoicesWithVoterInfo {{ resource_vote_choice: {}, voters: [{}] }}",
53 self.resource_vote_choice,
54 voters_str.join(", ")
55 )
56 }
57}
58
59#[derive(Debug, PartialEq, Clone)]
65pub struct FinalizedContender {
66 pub identity_id: Identifier,
68 pub document: Document,
70 pub serialized_document: Vec<u8>,
72 pub final_vote_tally: u32,
74}
75
76impl FinalizedContender {
77 pub fn try_from_contender_with_serialized_document(
79 value: FinalizedContenderWithSerializedDocument,
80 document_type: DocumentTypeRef,
81 platform_version: &PlatformVersion,
82 ) -> Result<Self, ProtocolError> {
83 let FinalizedContenderWithSerializedDocument {
84 identity_id,
85 serialized_document,
86 final_vote_tally,
87 } = value;
88
89 Ok(FinalizedContender {
90 identity_id,
91 document: Document::from_bytes(&serialized_document, document_type, platform_version)?,
92 serialized_document,
93 final_vote_tally,
94 })
95 }
96}
97
98impl TryFrom<ContenderWithSerializedDocument> for FinalizedContenderWithSerializedDocument {
99 type Error = ProtocolError;
100
101 fn try_from(value: ContenderWithSerializedDocument) -> Result<Self, Self::Error> {
102 let (identity_id, serialized_document, vote_tally) = match value {
103 ContenderWithSerializedDocument::V0(v0) => {
104 let ContenderWithSerializedDocumentV0 {
105 identity_id,
106 serialized_document,
107 vote_tally,
108 } = v0;
109 (identity_id, serialized_document, vote_tally)
110 }
111 };
112
113 Ok(FinalizedContenderWithSerializedDocument {
114 identity_id,
115 serialized_document: serialized_document.ok_or(
116 ProtocolError::CorruptedCodeExecution("expected serialized document".to_string()),
117 )?,
118 final_vote_tally: vote_tally.ok_or(ProtocolError::CorruptedCodeExecution(
119 "expected vote tally".to_string(),
120 ))?,
121 })
122 }
123}
124
125#[cfg(test)]
126mod tests {
127 use super::*;
128 use crate::voting::contender_structs::contender::v0::ContenderWithSerializedDocumentV0;
129 use platform_value::Identifier;
130
131 mod finalized_resource_vote_choices_display {
132 use super::*;
133
134 #[test]
135 fn display_with_no_voters() {
136 let item = FinalizedResourceVoteChoicesWithVoterInfo {
137 resource_vote_choice: ResourceVoteChoice::Abstain,
138 voters: vec![],
139 };
140 let s = item.to_string();
141 assert!(s.contains("resource_vote_choice"));
142 assert!(s.contains("voters: []"));
143 }
144
145 #[test]
146 fn display_with_multiple_voters() {
147 let id1 = Identifier::new([1u8; 32]);
148 let id2 = Identifier::new([2u8; 32]);
149 let item = FinalizedResourceVoteChoicesWithVoterInfo {
150 resource_vote_choice: ResourceVoteChoice::Lock,
151 voters: vec![(id1, 1), (id2, 4)],
152 };
153 let s = item.to_string();
154 assert!(s.contains(&format!("{}:1", id1)));
156 assert!(s.contains(&format!("{}:4", id2)));
157 assert!(s.contains(", "));
158 }
159 }
160
161 mod finalized_resource_vote_choices_encoding {
162 use super::*;
163 use bincode::config;
164
165 #[test]
166 fn roundtrip_preserves_data() {
167 let id = Identifier::new([7u8; 32]);
168 let original = FinalizedResourceVoteChoicesWithVoterInfo {
169 resource_vote_choice: ResourceVoteChoice::TowardsIdentity(id),
170 voters: vec![(id, 3)],
171 };
172 let cfg = config::standard();
173 let bytes = bincode::encode_to_vec(&original, cfg).expect("encode");
174 let (decoded, _): (FinalizedResourceVoteChoicesWithVoterInfo, _) =
175 bincode::decode_from_slice(&bytes, cfg).expect("decode");
176 assert_eq!(decoded, original);
177 }
178 }
179
180 mod finalized_contender_with_serialized_document_default {
181 use super::*;
182
183 #[test]
184 fn default_has_zero_fields() {
185 let fc = FinalizedContenderWithSerializedDocument::default();
186 assert_eq!(fc.identity_id, Identifier::default());
187 assert!(fc.serialized_document.is_empty());
188 assert_eq!(fc.final_vote_tally, 0);
189 }
190 }
191
192 mod try_from_contender_with_serialized_document {
193 use super::*;
194
195 #[test]
196 fn err_when_serialized_document_missing() {
197 let csd = ContenderWithSerializedDocument::V0(ContenderWithSerializedDocumentV0 {
198 identity_id: Identifier::new([1u8; 32]),
199 serialized_document: None,
200 vote_tally: Some(10),
201 });
202 let result = FinalizedContenderWithSerializedDocument::try_from(csd);
203 match result {
204 Err(ProtocolError::CorruptedCodeExecution(msg)) => {
205 assert!(msg.contains("expected serialized document"));
206 }
207 _ => panic!("expected CorruptedCodeExecution error for missing document"),
208 }
209 }
210
211 #[test]
212 fn err_when_vote_tally_missing() {
213 let csd = ContenderWithSerializedDocument::V0(ContenderWithSerializedDocumentV0 {
214 identity_id: Identifier::new([1u8; 32]),
215 serialized_document: Some(vec![1, 2, 3]),
216 vote_tally: None,
217 });
218 let result = FinalizedContenderWithSerializedDocument::try_from(csd);
219 match result {
220 Err(ProtocolError::CorruptedCodeExecution(msg)) => {
221 assert!(msg.contains("expected vote tally"));
222 }
223 _ => panic!("expected CorruptedCodeExecution error for missing vote tally"),
224 }
225 }
226
227 #[test]
228 fn ok_when_all_fields_present() {
229 let id = Identifier::new([9u8; 32]);
230 let doc = vec![0xAA, 0xBB, 0xCC];
231 let csd = ContenderWithSerializedDocument::V0(ContenderWithSerializedDocumentV0 {
232 identity_id: id,
233 serialized_document: Some(doc.clone()),
234 vote_tally: Some(42),
235 });
236 let finalized =
237 FinalizedContenderWithSerializedDocument::try_from(csd).expect("should succeed");
238 assert_eq!(finalized.identity_id, id);
239 assert_eq!(finalized.serialized_document, doc);
240 assert_eq!(finalized.final_vote_tally, 42);
241 }
242 }
243
244 mod finalized_contender_with_serialized_document_equality {
245 use super::*;
246
247 #[test]
248 fn equal_structs_compare_equal() {
249 let id = Identifier::new([3u8; 32]);
250 let a = FinalizedContenderWithSerializedDocument {
251 identity_id: id,
252 serialized_document: vec![1, 2, 3],
253 final_vote_tally: 100,
254 };
255 let b = FinalizedContenderWithSerializedDocument {
256 identity_id: id,
257 serialized_document: vec![1, 2, 3],
258 final_vote_tally: 100,
259 };
260 assert_eq!(a, b);
261 let c = a.clone();
263 assert_eq!(a, c);
264 }
265
266 #[test]
267 fn different_tally_not_equal() {
268 let id = Identifier::new([3u8; 32]);
269 let a = FinalizedContenderWithSerializedDocument {
270 identity_id: id,
271 serialized_document: vec![1, 2, 3],
272 final_vote_tally: 100,
273 };
274 let b = FinalizedContenderWithSerializedDocument {
275 identity_id: id,
276 serialized_document: vec![1, 2, 3],
277 final_vote_tally: 101,
278 };
279 assert_ne!(a, b);
280 }
281 }
282}