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#[derive(Debug, PartialEq, Clone, Encode, Decode)]
38pub struct VotePollsByEndDateDriveQuery {
39 pub start_time: Option<(TimestampMillis, TimestampIncluded)>,
41 pub end_time: Option<(TimestampMillis, TimestampIncluded)>,
43 pub limit: Option<u16>,
45 pub offset: Option<u16>,
47 pub order_ascending: bool,
49}
50
51impl VotePollsByEndDateDriveQuery {
52 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 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 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 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 let vote_polls = query_result_elements
201 .to_path_key_elements()
202 .into_iter()
203 .map(|(_, _, element)| {
204 let vote_poll_bytes = element.into_item_bytes().map_err(Error::from)?;
206 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 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 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 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 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 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 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 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 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}