1use crate::drive::votes::paths::{
2 VotePollPaths, RESOURCE_ABSTAIN_VOTE_TREE_KEY_U8_32, RESOURCE_LOCK_VOTE_TREE_KEY_U8_32,
3 RESOURCE_STORED_INFO_KEY_U8_32,
4};
5use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::resolve::ContestedDocumentResourceVotePollResolver;
6use crate::drive::votes::resolved::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed;
7#[cfg(feature = "server")]
8use crate::drive::Drive;
9use crate::error::drive::DriveError;
10use crate::error::query::QuerySyntaxError;
11use crate::error::Error;
12#[cfg(feature = "server")]
13use crate::fees::op::LowLevelDriveOperation;
14#[cfg(feature = "server")]
15use crate::query::GroveError;
16use bincode::{Decode, Encode};
17use dpp::block::block_info::BlockInfo;
18use dpp::data_contract::DataContract;
19use dpp::identifier::Identifier;
20#[cfg(feature = "server")]
21use dpp::serialization::PlatformDeserializable;
22#[cfg(feature = "server")]
23use dpp::voting::contender_structs::ContenderWithSerializedDocumentV0;
24use dpp::voting::contender_structs::{
25 ContenderWithSerializedDocument, FinalizedContenderWithSerializedDocument,
26};
27#[cfg(feature = "server")]
28use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::ContestedDocumentVotePollStoredInfo;
29#[cfg(feature = "server")]
30use dpp::voting::vote_info_storage::contested_document_vote_poll_stored_info::ContestedDocumentVotePollStoredInfoV0Getters;
31use dpp::voting::vote_info_storage::contested_document_vote_poll_winner_info::ContestedDocumentVotePollWinnerInfo;
32use dpp::voting::vote_polls::contested_document_resource_vote_poll::ContestedDocumentResourceVotePoll;
33#[cfg(feature = "server")]
34use grovedb::query_result_type::QueryResultType;
35#[cfg(feature = "server")]
36use grovedb::{Element, TransactionArg};
37use grovedb::{PathQuery, Query, QueryItem, SizedQuery};
38use platform_version::version::PlatformVersion;
39
40#[derive(Debug, PartialEq, Clone, Copy, Encode, Decode)]
45pub enum ContestedDocumentVotePollDriveQueryResultType {
46 Documents,
48 VoteTally,
50 DocumentsAndVoteTally,
52 SingleDocumentByContender(Identifier),
54}
55
56impl ContestedDocumentVotePollDriveQueryResultType {
57 pub fn has_vote_tally(&self) -> bool {
59 match self {
60 ContestedDocumentVotePollDriveQueryResultType::Documents => false,
61 ContestedDocumentVotePollDriveQueryResultType::SingleDocumentByContender(_) => false,
62 ContestedDocumentVotePollDriveQueryResultType::VoteTally => true,
63 ContestedDocumentVotePollDriveQueryResultType::DocumentsAndVoteTally => true,
64 }
65 }
66
67 pub fn has_documents(&self) -> bool {
69 match self {
70 ContestedDocumentVotePollDriveQueryResultType::Documents => true,
71 ContestedDocumentVotePollDriveQueryResultType::SingleDocumentByContender(_) => true,
72 ContestedDocumentVotePollDriveQueryResultType::VoteTally => false,
73 ContestedDocumentVotePollDriveQueryResultType::DocumentsAndVoteTally => true,
74 }
75 }
76}
77
78impl TryFrom<i32> for ContestedDocumentVotePollDriveQueryResultType {
79 type Error = Error;
80
81 fn try_from(value: i32) -> Result<Self, Self::Error> {
82 match value {
83 0 => Ok(ContestedDocumentVotePollDriveQueryResultType::Documents),
84 1 => Ok(ContestedDocumentVotePollDriveQueryResultType::VoteTally),
85 2 => Ok(ContestedDocumentVotePollDriveQueryResultType::DocumentsAndVoteTally),
86 3 => Err(Error::Query(QuerySyntaxError::Unsupported(
87 "unsupported to get SingleDocumentByContender query result type".to_string()
88 ))),
89 n => Err(Error::Query(QuerySyntaxError::Unsupported(format!(
90 "unsupported contested document vote poll drive query result type {}, only 0, 1, 2 and 3 are supported",
91 n
92 )))),
93 }
94 }
95}
96
97#[derive(Debug, PartialEq, Clone, Encode, Decode)]
99pub struct ContestedDocumentVotePollDriveQuery {
100 pub vote_poll: ContestedDocumentResourceVotePoll,
102 pub result_type: ContestedDocumentVotePollDriveQueryResultType,
104 pub offset: Option<u16>,
106 pub limit: Option<u16>,
108 pub start_at: Option<([u8; 32], bool)>,
110 pub allow_include_locked_and_abstaining_vote_tally: bool,
114}
115
116#[derive(Debug, PartialEq, Eq, Clone, Default)]
121pub struct ContestedDocumentVotePollDriveQueryExecutionResult {
122 pub contenders: Vec<ContenderWithSerializedDocument>,
124 pub locked_vote_tally: Option<u32>,
126 pub abstaining_vote_tally: Option<u32>,
128 pub winner: Option<(ContestedDocumentVotePollWinnerInfo, BlockInfo)>,
130 pub skipped: u16,
132}
133
134#[derive(Debug, PartialEq, Eq, Clone, Default)]
139pub struct FinalizedContestedDocumentVotePollDriveQueryExecutionResult {
140 pub contenders: Vec<FinalizedContenderWithSerializedDocument>,
142 pub locked_vote_tally: u32,
144 pub abstaining_vote_tally: u32,
146}
147
148impl TryFrom<ContestedDocumentVotePollDriveQueryExecutionResult>
149 for FinalizedContestedDocumentVotePollDriveQueryExecutionResult
150{
151 type Error = Error;
152
153 fn try_from(
154 value: ContestedDocumentVotePollDriveQueryExecutionResult,
155 ) -> Result<Self, Self::Error> {
156 let ContestedDocumentVotePollDriveQueryExecutionResult {
157 contenders,
158 locked_vote_tally,
159 abstaining_vote_tally,
160 ..
161 } = value;
162
163 let finalized_contenders = contenders
164 .into_iter()
165 .map(|contender| {
166 let finalized: FinalizedContenderWithSerializedDocument = contender.try_into()?;
167 Ok(finalized)
168 })
169 .collect::<Result<Vec<_>, Error>>()?;
170
171 Ok(
172 FinalizedContestedDocumentVotePollDriveQueryExecutionResult {
173 contenders: finalized_contenders,
174 locked_vote_tally: locked_vote_tally.ok_or(Error::Drive(
175 DriveError::CorruptedCodeExecution("expected a locked tally"),
176 ))?,
177 abstaining_vote_tally: abstaining_vote_tally.ok_or(Error::Drive(
178 DriveError::CorruptedCodeExecution("expected an abstaining tally"),
179 ))?,
180 },
181 )
182 }
183}
184
185impl ContestedDocumentVotePollDriveQuery {
186 #[cfg(feature = "server")]
187 pub fn resolve(
208 &self,
209 drive: &Drive,
210 transaction: TransactionArg,
211 platform_version: &PlatformVersion,
212 ) -> Result<ResolvedContestedDocumentVotePollDriveQuery<'_>, Error> {
213 let ContestedDocumentVotePollDriveQuery {
214 vote_poll,
215 result_type,
216 offset,
217 limit,
218 start_at,
219 allow_include_locked_and_abstaining_vote_tally,
220 } = self;
221 Ok(ResolvedContestedDocumentVotePollDriveQuery {
222 vote_poll: vote_poll.resolve_allow_borrowed(drive, transaction, platform_version)?,
223 result_type: *result_type,
224 offset: *offset,
225 limit: *limit,
226 start_at: *start_at,
227 allow_include_locked_and_abstaining_vote_tally:
228 *allow_include_locked_and_abstaining_vote_tally,
229 })
230 }
231
232 #[cfg(feature = "verify")]
233 pub fn resolve_with_known_contracts_provider<'a>(
235 &self,
236 known_contracts_provider_fn: &super::ContractLookupFn,
237 ) -> Result<ResolvedContestedDocumentVotePollDriveQuery<'a>, Error> {
238 let ContestedDocumentVotePollDriveQuery {
239 vote_poll,
240 result_type,
241 offset,
242 limit,
243 start_at,
244 allow_include_locked_and_abstaining_vote_tally,
245 } = self;
246 Ok(ResolvedContestedDocumentVotePollDriveQuery {
247 vote_poll: vote_poll
248 .resolve_with_known_contracts_provider(known_contracts_provider_fn)?,
249 result_type: *result_type,
250 offset: *offset,
251 limit: *limit,
252 start_at: *start_at,
253 allow_include_locked_and_abstaining_vote_tally:
254 *allow_include_locked_and_abstaining_vote_tally,
255 })
256 }
257
258 #[cfg(any(feature = "verify", feature = "server"))]
259 pub fn resolve_with_provided_borrowed_contract<'a>(
261 &self,
262 data_contract: &'a DataContract,
263 ) -> Result<ResolvedContestedDocumentVotePollDriveQuery<'a>, Error> {
264 let ContestedDocumentVotePollDriveQuery {
265 vote_poll,
266 result_type,
267 offset,
268 limit,
269 start_at,
270 allow_include_locked_and_abstaining_vote_tally,
271 } = self;
272 Ok(ResolvedContestedDocumentVotePollDriveQuery {
273 vote_poll: vote_poll.resolve_with_provided_borrowed_contract(data_contract)?,
274 result_type: *result_type,
275 offset: *offset,
276 limit: *limit,
277 start_at: *start_at,
278 allow_include_locked_and_abstaining_vote_tally:
279 *allow_include_locked_and_abstaining_vote_tally,
280 })
281 }
282
283 #[cfg(feature = "server")]
284 pub fn execute_with_proof(
286 self,
287 drive: &Drive,
288 block_info: Option<BlockInfo>,
289 transaction: TransactionArg,
290 platform_version: &PlatformVersion,
291 ) -> Result<(Vec<u8>, u64), Error> {
292 let mut drive_operations = vec![];
293 let items = self.execute_with_proof_internal(
294 drive,
295 transaction,
296 &mut drive_operations,
297 platform_version,
298 )?;
299 let cost = if let Some(block_info) = block_info {
300 let fee_result = Drive::calculate_fee(
301 None,
302 Some(drive_operations),
303 &block_info.epoch,
304 drive.config.epochs_per_era,
305 platform_version,
306 None,
307 )?;
308 fee_result.processing_fee
309 } else {
310 0
311 };
312 Ok((items, cost))
313 }
314
315 #[cfg(feature = "server")]
316 pub(crate) fn execute_with_proof_internal(
318 self,
319 drive: &Drive,
320 transaction: TransactionArg,
321 drive_operations: &mut Vec<LowLevelDriveOperation>,
322 platform_version: &PlatformVersion,
323 ) -> Result<Vec<u8>, Error> {
324 let resolved = self.resolve(drive, transaction, platform_version)?;
325 let path_query = resolved.construct_path_query(platform_version)?;
326 drive.grove_get_proved_path_query(
328 &path_query,
329 transaction,
330 drive_operations,
331 &platform_version.drive,
332 )
333 }
334
335 #[cfg(feature = "server")]
336 pub fn execute_no_proof_with_cost(
338 &self,
339 drive: &Drive,
340 block_info: Option<BlockInfo>,
341 transaction: TransactionArg,
342 platform_version: &PlatformVersion,
343 ) -> Result<(ContestedDocumentVotePollDriveQueryExecutionResult, u64), Error> {
344 let mut drive_operations = vec![];
345 let result =
346 self.execute_no_proof(drive, transaction, &mut drive_operations, platform_version)?;
347 let cost = if let Some(block_info) = block_info {
348 let fee_result = Drive::calculate_fee(
349 None,
350 Some(drive_operations),
351 &block_info.epoch,
352 drive.config.epochs_per_era,
353 platform_version,
354 None,
355 )?;
356 fee_result.processing_fee
357 } else {
358 0
359 };
360 Ok((result, cost))
361 }
362
363 #[cfg(feature = "server")]
364 pub fn execute_no_proof(
366 &self,
367 drive: &Drive,
368 transaction: TransactionArg,
369 drive_operations: &mut Vec<LowLevelDriveOperation>,
370 platform_version: &PlatformVersion,
371 ) -> Result<ContestedDocumentVotePollDriveQueryExecutionResult, Error> {
372 let resolved = self.resolve(drive, transaction, platform_version)?;
373 resolved.execute(drive, transaction, drive_operations, platform_version)
374 }
375}
376
377#[derive(Debug, PartialEq, Clone)]
379pub struct ResolvedContestedDocumentVotePollDriveQuery<'a> {
380 pub vote_poll: ContestedDocumentResourceVotePollWithContractInfoAllowBorrowed<'a>,
382 pub result_type: ContestedDocumentVotePollDriveQueryResultType,
384 pub offset: Option<u16>,
386 pub limit: Option<u16>,
388 pub start_at: Option<([u8; 32], bool)>,
390 pub allow_include_locked_and_abstaining_vote_tally: bool,
392}
393
394impl ResolvedContestedDocumentVotePollDriveQuery<'_> {
395 pub fn construct_path_query(
397 &self,
398 platform_version: &PlatformVersion,
399 ) -> Result<PathQuery, Error> {
400 let path = self.vote_poll.contenders_path(platform_version)?;
401
402 let mut query = Query::new();
403
404 let allow_include_locked_and_abstaining_vote_tally = self
405 .allow_include_locked_and_abstaining_vote_tally
406 && self.result_type.has_vote_tally();
407
408 let limit = match &self.start_at {
413 None => {
414 if allow_include_locked_and_abstaining_vote_tally {
415 match &self.result_type {
416 ContestedDocumentVotePollDriveQueryResultType::Documents => {
417 query.insert_range_after(RESOURCE_LOCK_VOTE_TREE_KEY_U8_32.to_vec()..);
419 self.limit
420 }
421 ContestedDocumentVotePollDriveQueryResultType::VoteTally => {
422 query.insert_all();
423 self.limit.map(|limit| limit.saturating_add(3))
424 }
425 ContestedDocumentVotePollDriveQueryResultType::DocumentsAndVoteTally => {
426 query.insert_all();
427 self.limit.map(|limit| limit.saturating_mul(2).saturating_add(3))
428 }
429 ContestedDocumentVotePollDriveQueryResultType::SingleDocumentByContender(contender_id) => {
430 query.insert_key(contender_id.to_vec());
431 self.limit
432 }
433 }
434 } else {
435 match &self.result_type {
436 ContestedDocumentVotePollDriveQueryResultType::Documents => {
437 query.insert_range_after(RESOURCE_LOCK_VOTE_TREE_KEY_U8_32.to_vec()..);
438 self.limit
439 }
440 ContestedDocumentVotePollDriveQueryResultType::SingleDocumentByContender(contender_id) => {
441 query.insert_key(contender_id.to_vec());
442 self.limit
443 }
444 ContestedDocumentVotePollDriveQueryResultType::VoteTally => {
445 query.insert_key(RESOURCE_STORED_INFO_KEY_U8_32.to_vec());
446 query.insert_range_after(RESOURCE_LOCK_VOTE_TREE_KEY_U8_32.to_vec()..);
447 self.limit.map(|limit| limit.saturating_add(1))
448 }
449 ContestedDocumentVotePollDriveQueryResultType::DocumentsAndVoteTally => {
450 query.insert_key(RESOURCE_STORED_INFO_KEY_U8_32.to_vec());
451 query.insert_range_after(RESOURCE_LOCK_VOTE_TREE_KEY_U8_32.to_vec()..);
452 self.limit.map(|limit| limit.saturating_mul(2).saturating_add(1))
453 }
454 }
455 }
456 }
457 Some((starts_at_key_bytes, start_at_included)) => {
458 let starts_at_key = starts_at_key_bytes.to_vec();
459 match start_at_included {
460 true => query.insert_range_from(starts_at_key..),
461 false => query.insert_range_after(starts_at_key..),
462 }
463 match &self.result_type {
464 ContestedDocumentVotePollDriveQueryResultType::Documents
465 | ContestedDocumentVotePollDriveQueryResultType::SingleDocumentByContender(_)
466 | ContestedDocumentVotePollDriveQueryResultType::VoteTally => self.limit,
467 ContestedDocumentVotePollDriveQueryResultType::DocumentsAndVoteTally => {
468 self.limit.map(|limit| limit.saturating_mul(2))
469 }
470 }
471 }
472 };
473
474 let (subquery_path, subquery) = match self.result_type {
475 ContestedDocumentVotePollDriveQueryResultType::Documents
476 | ContestedDocumentVotePollDriveQueryResultType::SingleDocumentByContender(_) => {
477 (Some(vec![vec![0]]), None)
478 }
479 ContestedDocumentVotePollDriveQueryResultType::VoteTally => (Some(vec![vec![1]]), None),
480 ContestedDocumentVotePollDriveQueryResultType::DocumentsAndVoteTally => {
481 let mut query = Query::new();
482 query.insert_keys(vec![vec![0], vec![1]]);
483 (None, Some(query.into()))
484 }
485 };
486
487 query.default_subquery_branch.subquery_path = subquery_path;
488 query.default_subquery_branch.subquery = subquery;
489
490 if allow_include_locked_and_abstaining_vote_tally {
491 query.add_conditional_subquery(
492 QueryItem::Key(RESOURCE_LOCK_VOTE_TREE_KEY_U8_32.to_vec()),
493 Some(vec![vec![1]]),
494 None,
495 );
496 query.add_conditional_subquery(
497 QueryItem::Key(RESOURCE_ABSTAIN_VOTE_TREE_KEY_U8_32.to_vec()),
498 Some(vec![vec![1]]),
499 None,
500 );
501 }
502
503 query.add_conditional_subquery(
504 QueryItem::Key(RESOURCE_STORED_INFO_KEY_U8_32.to_vec()),
505 None,
506 None,
507 );
508
509 Ok(PathQuery {
510 path,
511 query: SizedQuery {
512 query,
513 limit,
514 offset: self.offset,
515 },
516 })
517 }
518
519 #[cfg(feature = "server")]
520 pub fn execute(
522 &self,
523 drive: &Drive,
524 transaction: TransactionArg,
525 drive_operations: &mut Vec<LowLevelDriveOperation>,
526 platform_version: &PlatformVersion,
527 ) -> Result<ContestedDocumentVotePollDriveQueryExecutionResult, Error> {
528 let path_query = self.construct_path_query(platform_version)?;
529 let query_result = drive.grove_get_path_query(
531 &path_query,
532 transaction,
533 QueryResultType::QueryPathKeyElementTrioResultType,
534 drive_operations,
535 &platform_version.drive,
536 );
537 match query_result {
538 Err(Error::GroveDB(e))
539 if matches!(
540 e.as_ref(),
541 GroveError::PathKeyNotFound(_)
542 | GroveError::PathNotFound(_)
543 | GroveError::PathParentLayerNotFound(_)
544 ) =>
545 {
546 Ok(ContestedDocumentVotePollDriveQueryExecutionResult::default())
547 }
548 Err(e) => Err(e),
549 Ok((query_result_elements, skipped)) => {
550 match self.result_type {
551 ContestedDocumentVotePollDriveQueryResultType::Documents
552 | ContestedDocumentVotePollDriveQueryResultType::SingleDocumentByContender(_) =>
553 {
554 let contenders = query_result_elements
556 .to_path_key_elements()
557 .into_iter()
558 .map(|(mut path, _key, document)| {
559 let identity_id = path.pop().ok_or(Error::Drive(
560 DriveError::CorruptedDriveState(
561 "the path must have a last element".to_string(),
562 ),
563 ))?;
564 Ok(ContenderWithSerializedDocumentV0 {
565 identity_id: Identifier::try_from(identity_id)?,
566 serialized_document: Some(document.into_item_bytes()?),
567 vote_tally: None,
568 }
569 .into())
570 })
571 .collect::<Result<Vec<ContenderWithSerializedDocument>, Error>>()?;
572
573 Ok(ContestedDocumentVotePollDriveQueryExecutionResult {
574 contenders,
575 locked_vote_tally: None,
576 abstaining_vote_tally: None,
577 winner: None,
578 skipped,
579 })
580 }
581 ContestedDocumentVotePollDriveQueryResultType::VoteTally => {
582 let mut contenders = Vec::new();
583 let mut locked_vote_tally: Option<u32> = None;
584 let mut abstaining_vote_tally: Option<u32> = None;
585 let mut winner = None;
586
587 for (path, first_key, element) in
588 query_result_elements.to_path_key_elements().into_iter()
589 {
590 let Some(identity_bytes) = path.last() else {
591 return Err(Error::Drive(DriveError::CorruptedDriveState(
592 "the path must have a last element".to_string(),
593 )));
594 };
595 match element {
596 Element::SumTree(_, sum_tree_value, _) => {
597 if sum_tree_value < 0 || sum_tree_value > u32::MAX as i64 {
598 return Err(Error::Drive(DriveError::CorruptedDriveState(format!(
599 "sum tree value for vote tally must be between 0 and u32::Max, received {} from state",
600 sum_tree_value
601 ))));
602 }
603
604 if identity_bytes.as_slice()
605 == RESOURCE_LOCK_VOTE_TREE_KEY_U8_32.as_slice()
606 {
607 locked_vote_tally = Some(sum_tree_value as u32);
608 } else if identity_bytes.as_slice()
609 == RESOURCE_ABSTAIN_VOTE_TREE_KEY_U8_32.as_slice()
610 {
611 abstaining_vote_tally = Some(sum_tree_value as u32);
612 } else {
613 contenders.push(
614 ContenderWithSerializedDocumentV0 {
615 identity_id: Identifier::try_from(identity_bytes)?,
616 serialized_document: None,
617 vote_tally: Some(sum_tree_value as u32),
618 }
619 .into(),
620 );
621 }
622 }
623 Element::Item(serialized_item_info, _) => {
624 if first_key.as_slice() == RESOURCE_STORED_INFO_KEY_U8_32 {
625 let finalized_contested_document_vote_poll_stored_info = ContestedDocumentVotePollStoredInfo::deserialize_from_bytes(&serialized_item_info)?;
627 if finalized_contested_document_vote_poll_stored_info
628 .vote_poll_status()
629 .awarded_or_locked()
630 {
631 locked_vote_tally = Some(
632 finalized_contested_document_vote_poll_stored_info
633 .last_locked_votes()
634 .ok_or(Error::Drive(
635 DriveError::CorruptedDriveState(
636 "we should have last locked votes"
637 .to_string(),
638 ),
639 ))?,
640 );
641 abstaining_vote_tally = Some(
642 finalized_contested_document_vote_poll_stored_info
643 .last_abstain_votes()
644 .ok_or(Error::Drive(
645 DriveError::CorruptedDriveState(
646 "we should have last abstain votes"
647 .to_string(),
648 ),
649 ))?,
650 );
651 winner = Some((
652 finalized_contested_document_vote_poll_stored_info.winner(),
653 finalized_contested_document_vote_poll_stored_info
654 .last_finalization_block().ok_or(Error::Drive(DriveError::CorruptedDriveState(
655 "we should have a last finalization block".to_string(),
656 )))?,
657 ));
658 contenders = finalized_contested_document_vote_poll_stored_info
659 .contender_votes_in_vec_of_contender_with_serialized_document().ok_or(Error::Drive(DriveError::CorruptedDriveState(
660 "we should have a last contender votes".to_string(),
661 )))?;
662 }
663 } else {
664 return Err(Error::Drive(
665 DriveError::CorruptedDriveState(
666 "the only item that should be returned should be stored info"
667 .to_string(),
668 ),
669 ));
670 }
671 }
672 _ => {
673 return Err(Error::Drive(DriveError::CorruptedDriveState(
674 "unexpected element type in result".to_string(),
675 )));
676 }
677 }
678 }
679 Ok(ContestedDocumentVotePollDriveQueryExecutionResult {
680 contenders,
681 locked_vote_tally,
682 abstaining_vote_tally,
683 winner,
684 skipped,
685 })
686 }
687 ContestedDocumentVotePollDriveQueryResultType::DocumentsAndVoteTally => {
688 let mut elements_iter =
689 query_result_elements.to_path_key_elements().into_iter();
690 let mut contenders = vec![];
691 let mut locked_vote_tally: Option<u32> = None;
692 let mut abstaining_vote_tally: Option<u32> = None;
693 let mut winner = None;
694
695 while let Some((path, first_key, element)) = elements_iter.next() {
697 let Some(identity_bytes) = path.last() else {
698 return Err(Error::Drive(DriveError::CorruptedDriveState(
699 "the path must have a last element".to_string(),
700 )));
701 };
702
703 match element {
704 Element::SumTree(_, sum_tree_value, _) => {
705 if sum_tree_value < 0 || sum_tree_value > u32::MAX as i64 {
706 return Err(Error::Drive(DriveError::CorruptedDriveState(format!(
707 "sum tree value for vote tally must be between 0 and u32::Max, received {} from state",
708 sum_tree_value
709 ))));
710 }
711
712 if identity_bytes.as_slice()
713 == RESOURCE_LOCK_VOTE_TREE_KEY_U8_32.as_slice()
714 {
715 locked_vote_tally = Some(sum_tree_value as u32);
716 } else if identity_bytes.as_slice()
717 == RESOURCE_ABSTAIN_VOTE_TREE_KEY_U8_32.as_slice()
718 {
719 abstaining_vote_tally = Some(sum_tree_value as u32);
720 } else {
721 return Err(Error::Drive(DriveError::CorruptedDriveState(
722 "unexpected key for sum tree value".to_string(),
723 )));
724 }
725 }
726 Element::Item(serialized_item_info, _) => {
727 if first_key.as_slice() == RESOURCE_STORED_INFO_KEY_U8_32 {
728 let finalized_contested_document_vote_poll_stored_info = ContestedDocumentVotePollStoredInfo::deserialize_from_bytes(&serialized_item_info)?;
730 if finalized_contested_document_vote_poll_stored_info
731 .vote_poll_status()
732 .awarded_or_locked()
733 {
734 locked_vote_tally = Some(
735 finalized_contested_document_vote_poll_stored_info
736 .last_locked_votes()
737 .ok_or(Error::Drive(
738 DriveError::CorruptedDriveState(
739 "we should have last locked votes"
740 .to_string(),
741 ),
742 ))?,
743 );
744 abstaining_vote_tally = Some(
745 finalized_contested_document_vote_poll_stored_info
746 .last_abstain_votes()
747 .ok_or(Error::Drive(
748 DriveError::CorruptedDriveState(
749 "we should have last abstain votes"
750 .to_string(),
751 ),
752 ))?,
753 );
754 winner = Some((
755 finalized_contested_document_vote_poll_stored_info.winner(),
756 finalized_contested_document_vote_poll_stored_info
757 .last_finalization_block().ok_or(Error::Drive(DriveError::CorruptedDriveState(
758 "we should have a last finalization block".to_string(),
759 )))?,
760 ));
761 contenders = finalized_contested_document_vote_poll_stored_info
762 .contender_votes_in_vec_of_contender_with_serialized_document().ok_or(Error::Drive(DriveError::CorruptedDriveState(
763 "we should have a last contender votes".to_string(),
764 )))?;
765 }
766 } else {
767 if let Some((
769 path_tally,
770 second_key,
771 Element::SumTree(_, sum_tree_value, _),
772 )) = elements_iter.next()
773 {
774 if path != path_tally {
775 return Err(Error::Drive(DriveError::CorruptedDriveState(format!("the two results in a chunk when requesting documents and vote tally should both have the same path asc, got {}:{}, and {}:{}", path.iter().map(hex::encode).collect::<Vec<_>>().join("/"), hex::encode(first_key), path_tally.iter().map(hex::encode).collect::<Vec<_>>().join("/"), hex::encode(second_key)))));
776 }
777
778 if sum_tree_value < 0
779 || sum_tree_value > u32::MAX as i64
780 {
781 return Err(Error::Drive(DriveError::CorruptedDriveState(format!(
782 "sum tree value for vote tally must be between 0 and u32::Max, received {} from state",
783 sum_tree_value
784 ))));
785 }
786
787 let identity_id =
788 Identifier::from_bytes(identity_bytes)?;
789 let contender = ContenderWithSerializedDocumentV0 {
790 identity_id,
791 serialized_document: Some(serialized_item_info),
792 vote_tally: Some(sum_tree_value as u32),
793 }
794 .into();
795 contenders.push(contender);
796 } else {
797 return Err(Error::Drive(
798 DriveError::CorruptedDriveState(
799 "we should have a sum item after a normal item"
800 .to_string(),
801 ),
802 ));
803 }
804 }
805 }
806 _ => {
807 return Err(Error::Drive(DriveError::CorruptedDriveState(
808 "unexpected element type in result".to_string(),
809 )));
810 }
811 }
812 }
813
814 Ok(ContestedDocumentVotePollDriveQueryExecutionResult {
815 contenders,
816 locked_vote_tally,
817 abstaining_vote_tally,
818 winner,
819 skipped,
820 })
821 }
822 }
823 }
824 }
825 }
826}