drive/query/
vote_polls_by_end_date_query.rs

1use crate::drive::votes::paths::vote_end_date_queries_tree_path_vec;
2#[cfg(feature = "server")]
3use crate::drive::Drive;
4#[cfg(feature = "server")]
5use crate::error::drive::DriveError;
6#[cfg(feature = "server")]
7use crate::error::Error;
8#[cfg(feature = "server")]
9use crate::fees::op::LowLevelDriveOperation;
10#[cfg(feature = "server")]
11use crate::query::GroveError;
12use crate::query::Query;
13#[cfg(feature = "server")]
14use crate::util::common::encode::decode_u64;
15use crate::util::common::encode::encode_u64;
16use bincode::{Decode, Encode};
17#[cfg(feature = "server")]
18use dpp::block::block_info::BlockInfo;
19#[cfg(feature = "server")]
20use dpp::fee::Credits;
21use dpp::prelude::{TimestampIncluded, TimestampMillis};
22#[cfg(feature = "server")]
23use dpp::serialization::PlatformDeserializable;
24#[cfg(feature = "server")]
25use dpp::voting::vote_polls::VotePoll;
26#[cfg(feature = "server")]
27use grovedb::query_result_type::{QueryResultElements, QueryResultType};
28#[cfg(feature = "server")]
29use grovedb::TransactionArg;
30use grovedb::{PathQuery, SizedQuery};
31#[cfg(feature = "server")]
32use platform_version::version::PlatformVersion;
33#[cfg(feature = "server")]
34use std::collections::BTreeMap;
35
36/// Vote Poll Drive Query struct
37#[derive(Debug, PartialEq, Clone, Encode, Decode)]
38pub struct VotePollsByEndDateDriveQuery {
39    /// What is the start time we are asking for
40    pub start_time: Option<(TimestampMillis, TimestampIncluded)>,
41    /// What vote poll are we asking for?
42    pub end_time: Option<(TimestampMillis, TimestampIncluded)>,
43    /// Limit
44    pub limit: Option<u16>,
45    /// Offset
46    pub offset: Option<u16>,
47    /// Ascending
48    pub order_ascending: bool,
49}
50
51impl VotePollsByEndDateDriveQuery {
52    /// Get the path query for an abci query that gets vote polls until an end time
53    pub fn path_query_for_end_time_included(end_time: TimestampMillis, limit: u16) -> PathQuery {
54        let path = vote_end_date_queries_tree_path_vec();
55
56        let mut query = Query::new_with_direction(true);
57
58        let encoded_time = encode_u64(end_time);
59
60        query.insert_range_to_inclusive(..=encoded_time);
61
62        let mut sub_query = Query::new();
63
64        sub_query.insert_all();
65
66        query.default_subquery_branch.subquery = Some(sub_query.into());
67
68        PathQuery {
69            path,
70            query: SizedQuery {
71                query,
72                limit: Some(limit),
73                offset: None,
74            },
75        }
76    }
77
78    /// Get the path query for an abci query that gets vote polls at an the end time
79    pub fn path_query_for_single_end_time(end_time: TimestampMillis, limit: u16) -> PathQuery {
80        let path = vote_end_date_queries_tree_path_vec();
81
82        let mut query = Query::new_with_direction(true);
83
84        let encoded_time = encode_u64(end_time);
85
86        query.insert_key(encoded_time);
87
88        let mut sub_query = Query::new();
89
90        sub_query.insert_all();
91
92        query.default_subquery_branch.subquery = Some(sub_query.into());
93
94        PathQuery {
95            path,
96            query: SizedQuery {
97                query,
98                limit: Some(limit),
99                offset: None,
100            },
101        }
102    }
103
104    #[cfg(feature = "server")]
105    /// Executes a special query with no proof to get contested document resource vote polls.
106    /// This is meant for platform abci to get votes that have finished
107    pub fn execute_no_proof_for_specialized_end_time_query(
108        end_time: TimestampMillis,
109        limit: u16,
110        drive: &Drive,
111        transaction: TransactionArg,
112        drive_operations: &mut Vec<LowLevelDriveOperation>,
113        platform_version: &PlatformVersion,
114    ) -> Result<BTreeMap<TimestampMillis, Vec<VotePoll>>, Error> {
115        let path_query = Self::path_query_for_end_time_included(end_time, limit);
116        let query_result = drive.grove_get_path_query(
117            &path_query,
118            transaction,
119            QueryResultType::QueryPathKeyElementTrioResultType,
120            drive_operations,
121            &platform_version.drive,
122        );
123        match query_result {
124            Err(Error::GroveDB(e))
125                if matches!(
126                    e.as_ref(),
127                    GroveError::PathKeyNotFound(_)
128                        | GroveError::PathNotFound(_)
129                        | GroveError::PathParentLayerNotFound(_)
130                ) =>
131            {
132                Ok(BTreeMap::new())
133            }
134            Err(e) => Err(e),
135            Ok((query_result_elements, _)) => {
136                let vote_polls_by_end_date = query_result_elements
137                    .to_path_key_elements()
138                    .into_iter()
139                    .map(|(path, _, element)| {
140                        let Some(last_path_component) = path.last() else {
141                            return Err(Error::Drive(DriveError::CorruptedDriveState(
142                                "we should always have a path not be null".to_string(),
143                            )));
144                        };
145                        let timestamp = decode_u64(last_path_component)?;
146                        let contested_document_resource_vote_poll_bytes =
147                            element.into_item_bytes().map_err(Error::from)?;
148                        let vote_poll = VotePoll::deserialize_from_bytes(
149                            &contested_document_resource_vote_poll_bytes,
150                        )?;
151                        Ok((timestamp, vote_poll))
152                    })
153                    .collect::<Result<Vec<_>, Error>>()?
154                    .into_iter()
155                    .fold(
156                        BTreeMap::new(),
157                        |mut acc: BTreeMap<u64, Vec<VotePoll>>, (timestamp, vote_poll)| {
158                            acc.entry(timestamp).or_default().push(vote_poll);
159                            acc
160                        },
161                    );
162                Ok(vote_polls_by_end_date)
163            }
164        }
165    }
166
167    #[cfg(feature = "server")]
168    /// Executes a special query with no proof to get contested document resource vote polls.
169    /// This is meant for platform abci to get votes that have finished
170    pub fn execute_no_proof_for_specialized_end_time_query_only_check_end_time(
171        end_time: TimestampMillis,
172        limit: u16,
173        drive: &Drive,
174        transaction: TransactionArg,
175        drive_operations: &mut Vec<LowLevelDriveOperation>,
176        platform_version: &PlatformVersion,
177    ) -> Result<Vec<VotePoll>, Error> {
178        let path_query = Self::path_query_for_single_end_time(end_time, limit);
179        let query_result = drive.grove_get_path_query(
180            &path_query,
181            transaction,
182            QueryResultType::QueryPathKeyElementTrioResultType,
183            drive_operations,
184            &platform_version.drive,
185        );
186        match query_result {
187            Err(Error::GroveDB(e))
188                if matches!(
189                    e.as_ref(),
190                    GroveError::PathKeyNotFound(_)
191                        | GroveError::PathNotFound(_)
192                        | GroveError::PathParentLayerNotFound(_)
193                ) =>
194            {
195                Ok(vec![])
196            }
197            Err(e) => Err(e),
198            Ok((query_result_elements, _)) => {
199                // Process the query result elements and collect VotePolls
200                let vote_polls = query_result_elements
201                    .to_path_key_elements()
202                    .into_iter()
203                    .map(|(_, _, element)| {
204                        // Extract the bytes from the element
205                        let vote_poll_bytes = element.into_item_bytes().map_err(Error::from)?;
206                        // Deserialize the bytes into a VotePoll
207                        let vote_poll = VotePoll::deserialize_from_bytes(&vote_poll_bytes)?;
208                        Ok(vote_poll)
209                    })
210                    .collect::<Result<Vec<_>, Error>>()?;
211                Ok(vote_polls)
212            }
213        }
214    }
215
216    /// Operations to construct a path query.
217    pub fn construct_path_query(&self) -> PathQuery {
218        let path = vote_end_date_queries_tree_path_vec();
219
220        let mut query = Query::new_with_direction(self.order_ascending);
221
222        // this is a range on all elements
223        match &(self.start_time, self.end_time) {
224            (None, None) => {
225                query.insert_all();
226            }
227            (Some((starts_at_key_bytes, start_at_included)), None) => {
228                let starts_at_key = encode_u64(*starts_at_key_bytes);
229                match start_at_included {
230                    true => query.insert_range_from(starts_at_key..),
231                    false => query.insert_range_after(starts_at_key..),
232                }
233            }
234            (None, Some((ends_at_key_bytes, ends_at_included))) => {
235                let ends_at_key = encode_u64(*ends_at_key_bytes);
236                match ends_at_included {
237                    true => query.insert_range_to_inclusive(..=ends_at_key),
238                    false => query.insert_range_to(..ends_at_key),
239                }
240            }
241            (
242                Some((starts_at_key_bytes, start_at_included)),
243                Some((ends_at_key_bytes, ends_at_included)),
244            ) => {
245                let starts_at_key = encode_u64(*starts_at_key_bytes);
246                let ends_at_key = encode_u64(*ends_at_key_bytes);
247                match (start_at_included, ends_at_included) {
248                    (true, true) => query.insert_range_inclusive(starts_at_key..=ends_at_key),
249                    (true, false) => query.insert_range(starts_at_key..ends_at_key),
250                    (false, true) => {
251                        query.insert_range_after_to_inclusive(starts_at_key..=ends_at_key)
252                    }
253                    (false, false) => query.insert_range_after_to(starts_at_key..ends_at_key),
254                }
255            }
256        }
257
258        let mut sub_query = Query::new();
259
260        sub_query.insert_all();
261
262        query.default_subquery_branch.subquery = Some(sub_query.into());
263
264        PathQuery {
265            path,
266            query: SizedQuery {
267                query,
268                limit: self.limit,
269                offset: None,
270            },
271        }
272    }
273    #[cfg(feature = "server")]
274    /// Executes a query with proof and returns the items and fee.
275    pub fn execute_with_proof(
276        self,
277        drive: &Drive,
278        block_info: Option<BlockInfo>,
279        transaction: TransactionArg,
280        platform_version: &PlatformVersion,
281    ) -> Result<(Vec<u8>, u64), Error> {
282        let mut drive_operations = vec![];
283        let items = self.execute_with_proof_internal(
284            drive,
285            transaction,
286            &mut drive_operations,
287            platform_version,
288        )?;
289        let cost = if let Some(block_info) = block_info {
290            let fee_result = Drive::calculate_fee(
291                None,
292                Some(drive_operations),
293                &block_info.epoch,
294                drive.config.epochs_per_era,
295                platform_version,
296                None,
297            )?;
298            fee_result.processing_fee
299        } else {
300            0
301        };
302        Ok((items, cost))
303    }
304
305    #[cfg(feature = "server")]
306    /// Executes an internal query with proof and returns the items.
307    pub(crate) fn execute_with_proof_internal(
308        self,
309        drive: &Drive,
310        transaction: TransactionArg,
311        drive_operations: &mut Vec<LowLevelDriveOperation>,
312        platform_version: &PlatformVersion,
313    ) -> Result<Vec<u8>, Error> {
314        let path_query = self.construct_path_query();
315        drive.grove_get_proved_path_query(
316            &path_query,
317            transaction,
318            drive_operations,
319            &platform_version.drive,
320        )
321    }
322    #[cfg(feature = "server")]
323    /// Executes a query with no proof and returns the items, skipped items, and fee.
324    pub fn execute_no_proof_with_cost(
325        &self,
326        drive: &Drive,
327        block_info: Option<BlockInfo>,
328        transaction: TransactionArg,
329        platform_version: &PlatformVersion,
330    ) -> Result<(BTreeMap<TimestampMillis, Vec<VotePoll>>, Credits), Error> {
331        let mut drive_operations = vec![];
332        let result =
333            self.execute_no_proof(drive, transaction, &mut drive_operations, platform_version)?;
334        let cost = if let Some(block_info) = block_info {
335            let fee_result = Drive::calculate_fee(
336                None,
337                Some(drive_operations),
338                &block_info.epoch,
339                drive.config.epochs_per_era,
340                platform_version,
341                None,
342            )?;
343            fee_result.processing_fee
344        } else {
345            0
346        };
347        Ok((result, cost))
348    }
349
350    #[cfg(feature = "server")]
351    /// Executes an internal query with no proof and returns the values and skipped items.
352    pub fn execute_no_proof(
353        &self,
354        drive: &Drive,
355        transaction: TransactionArg,
356        drive_operations: &mut Vec<LowLevelDriveOperation>,
357        platform_version: &PlatformVersion,
358    ) -> Result<BTreeMap<TimestampMillis, Vec<VotePoll>>, Error> {
359        let path_query = self.construct_path_query();
360        let query_result = drive.grove_get_path_query(
361            &path_query,
362            transaction,
363            QueryResultType::QueryPathKeyElementTrioResultType,
364            drive_operations,
365            &platform_version.drive,
366        );
367        match query_result {
368            Err(Error::GroveDB(e))
369                if matches!(
370                    e.as_ref(),
371                    GroveError::PathKeyNotFound(_)
372                        | GroveError::PathNotFound(_)
373                        | GroveError::PathParentLayerNotFound(_)
374                ) =>
375            {
376                Ok(BTreeMap::new())
377            }
378            Err(e) => Err(e),
379            Ok((query_result_elements, _)) => {
380                let vote_polls_by_end_date = query_result_elements
381                    .to_path_key_elements()
382                    .into_iter()
383                    .map(|(path, _, element)| {
384                        let Some(last_path_component) = path.last() else {
385                            return Err(Error::Drive(DriveError::CorruptedDriveState(
386                                "we should always have a path not be null".to_string(),
387                            )));
388                        };
389                        let timestamp = decode_u64(last_path_component)?;
390                        let contested_document_resource_vote_poll_bytes =
391                            element.into_item_bytes().map_err(Error::from)?;
392                        let vote_poll = VotePoll::deserialize_from_bytes(
393                            &contested_document_resource_vote_poll_bytes,
394                        )?;
395                        Ok((timestamp, vote_poll))
396                    })
397                    .collect::<Result<Vec<_>, Error>>()?
398                    .into_iter()
399                    .fold(
400                        BTreeMap::new(),
401                        |mut acc: BTreeMap<u64, Vec<VotePoll>>, (timestamp, vote_poll)| {
402                            acc.entry(timestamp).or_default().push(vote_poll);
403                            acc
404                        },
405                    );
406                Ok(vote_polls_by_end_date)
407            }
408        }
409    }
410
411    #[cfg(feature = "server")]
412    /// Executes an internal query with no proof and returns the values and skipped items.
413    pub fn execute_no_proof_keep_serialized(
414        &self,
415        drive: &Drive,
416        transaction: TransactionArg,
417        drive_operations: &mut Vec<LowLevelDriveOperation>,
418        platform_version: &PlatformVersion,
419    ) -> Result<BTreeMap<TimestampMillis, Vec<Vec<u8>>>, Error> {
420        let path_query = self.construct_path_query();
421        let query_result = drive.grove_get_path_query(
422            &path_query,
423            transaction,
424            QueryResultType::QueryPathKeyElementTrioResultType,
425            drive_operations,
426            &platform_version.drive,
427        );
428        match query_result {
429            Err(Error::GroveDB(e))
430                if matches!(
431                    e.as_ref(),
432                    GroveError::PathKeyNotFound(_)
433                        | GroveError::PathNotFound(_)
434                        | GroveError::PathParentLayerNotFound(_)
435                ) =>
436            {
437                Ok(BTreeMap::new())
438            }
439            Err(e) => Err(e),
440            Ok((query_result_elements, _)) => {
441                let vote_polls_by_end_date = query_result_elements
442                    .to_path_key_elements()
443                    .into_iter()
444                    .map(|(path, _, element)| {
445                        let Some(last_path_component) = path.last() else {
446                            return Err(Error::Drive(DriveError::CorruptedDriveState(
447                                "we should always have a path not be null".to_string(),
448                            )));
449                        };
450                        let timestamp = decode_u64(last_path_component)?;
451                        let contested_document_resource_vote_poll_bytes =
452                            element.into_item_bytes().map_err(Error::from)?;
453                        Ok((timestamp, contested_document_resource_vote_poll_bytes))
454                    })
455                    .collect::<Result<Vec<_>, Error>>()?
456                    .into_iter()
457                    .fold(
458                        BTreeMap::new(),
459                        |mut acc: BTreeMap<u64, Vec<Vec<u8>>>,
460                         (timestamp, vote_poll_serialized)| {
461                            acc.entry(timestamp).or_default().push(vote_poll_serialized);
462                            acc
463                        },
464                    );
465                Ok(vote_polls_by_end_date)
466            }
467        }
468    }
469
470    #[cfg(feature = "server")]
471    #[allow(unused)]
472    /// Executes an internal query with no proof and returns the values and skipped items.
473    pub(crate) fn execute_no_proof_internal(
474        &self,
475        drive: &Drive,
476        result_type: QueryResultType,
477        transaction: TransactionArg,
478        drive_operations: &mut Vec<LowLevelDriveOperation>,
479        platform_version: &PlatformVersion,
480    ) -> Result<QueryResultElements, Error> {
481        let path_query = self.construct_path_query();
482        let query_result = drive.grove_get_path_query(
483            &path_query,
484            transaction,
485            result_type,
486            drive_operations,
487            &platform_version.drive,
488        );
489        match query_result {
490            Err(Error::GroveDB(e))
491                if matches!(
492                    e.as_ref(),
493                    GroveError::PathKeyNotFound(_)
494                        | GroveError::PathNotFound(_)
495                        | GroveError::PathParentLayerNotFound(_)
496                ) =>
497            {
498                Ok(QueryResultElements::new())
499            }
500            _ => {
501                let (data, _) = query_result?;
502                {
503                    Ok(data)
504                }
505            }
506        }
507    }
508}