drive/query/
contested_resource_votes_given_by_identity_query.rs

1use crate::drive::votes::paths::vote_contested_resource_identity_votes_tree_path_for_identity_vec;
2#[cfg(feature = "server")]
3use crate::drive::votes::storage_form::contested_document_resource_reference_storage_form::ContestedDocumentResourceVoteReferenceStorageForm;
4#[cfg(feature = "server")]
5use crate::drive::votes::storage_form::contested_document_resource_storage_form::ContestedDocumentResourceVoteStorageForm;
6#[cfg(feature = "server")]
7use crate::drive::votes::tree_path_storage_form::TreePathStorageForm;
8#[cfg(feature = "server")]
9use crate::drive::Drive;
10#[cfg(feature = "server")]
11use crate::error::drive::DriveError;
12use crate::error::Error;
13#[cfg(feature = "server")]
14use crate::fees::op::LowLevelDriveOperation;
15#[cfg(feature = "server")]
16use crate::query::GroveError;
17use crate::query::Query;
18#[cfg(feature = "server")]
19use dpp::bincode;
20#[cfg(feature = "server")]
21use dpp::block::block_info::BlockInfo;
22use dpp::identifier::Identifier;
23#[cfg(feature = "server")]
24use grovedb::query_result_type::{QueryResultElements, QueryResultType};
25#[cfg(feature = "server")]
26use grovedb::TransactionArg;
27use grovedb::{PathQuery, SizedQuery};
28#[cfg(feature = "server")]
29use platform_version::version::PlatformVersion;
30#[cfg(feature = "server")]
31use std::collections::BTreeMap;
32
33/// Vote Poll Drive Query struct
34#[derive(Debug, PartialEq, Clone)]
35pub struct ContestedResourceVotesGivenByIdentityQuery {
36    /// Which contestant do we want to get the votes for
37    pub identity_id: Identifier,
38    /// Offset
39    pub offset: Option<u16>,
40    /// Limit
41    pub limit: Option<u16>,
42    /// Start at vote id
43    pub start_at: Option<([u8; 32], bool)>,
44    /// Ascending
45    pub order_ascending: bool,
46}
47
48impl ContestedResourceVotesGivenByIdentityQuery {
49    #[cfg(feature = "server")]
50    /// Executes a query with proof and returns the items and fee.
51    pub fn execute_with_proof(
52        self,
53        drive: &Drive,
54        block_info: Option<BlockInfo>,
55        transaction: TransactionArg,
56        platform_version: &PlatformVersion,
57    ) -> Result<(Vec<u8>, u64), Error> {
58        let mut drive_operations = vec![];
59        let items = self.execute_with_proof_internal(
60            drive,
61            transaction,
62            &mut drive_operations,
63            platform_version,
64        )?;
65        let cost = if let Some(block_info) = block_info {
66            let fee_result = Drive::calculate_fee(
67                None,
68                Some(drive_operations),
69                &block_info.epoch,
70                drive.config.epochs_per_era,
71                platform_version,
72                None,
73            )?;
74            fee_result.processing_fee
75        } else {
76            0
77        };
78        Ok((items, cost))
79    }
80
81    #[cfg(feature = "server")]
82    /// Executes an internal query with proof and returns the items.
83    pub(crate) fn execute_with_proof_internal(
84        self,
85        drive: &Drive,
86        transaction: TransactionArg,
87        drive_operations: &mut Vec<LowLevelDriveOperation>,
88        platform_version: &PlatformVersion,
89    ) -> Result<Vec<u8>, Error> {
90        let path_query = self.construct_path_query()?;
91        drive.grove_get_proved_path_query(
92            &path_query,
93            transaction,
94            drive_operations,
95            &platform_version.drive,
96        )
97    }
98
99    #[cfg(feature = "server")]
100    /// Executes a query with no proof and returns the items, skipped items, and fee.
101    pub fn execute_no_proof_with_cost(
102        &self,
103        drive: &Drive,
104        block_info: Option<BlockInfo>,
105        transaction: TransactionArg,
106        platform_version: &PlatformVersion,
107    ) -> Result<
108        (
109            BTreeMap<Identifier, ContestedDocumentResourceVoteStorageForm>,
110            u64,
111        ),
112        Error,
113    > {
114        let mut drive_operations = vec![];
115        let result =
116            self.execute_no_proof(drive, transaction, &mut drive_operations, platform_version)?;
117        let cost = if let Some(block_info) = block_info {
118            let fee_result = Drive::calculate_fee(
119                None,
120                Some(drive_operations),
121                &block_info.epoch,
122                drive.config.epochs_per_era,
123                platform_version,
124                None,
125            )?;
126            fee_result.processing_fee
127        } else {
128            0
129        };
130        Ok((result, cost))
131    }
132
133    #[cfg(feature = "server")]
134    /// Executes an internal query with no proof and returns the values and skipped items.
135    pub fn execute_no_proof(
136        &self,
137        drive: &Drive,
138        transaction: TransactionArg,
139        drive_operations: &mut Vec<LowLevelDriveOperation>,
140        platform_version: &PlatformVersion,
141    ) -> Result<BTreeMap<Identifier, ContestedDocumentResourceVoteStorageForm>, Error> {
142        let path_query = self.construct_path_query()?;
143        let query_result = drive.grove_get_raw_path_query(
144            &path_query,
145            transaction,
146            QueryResultType::QueryPathKeyElementTrioResultType,
147            drive_operations,
148            &platform_version.drive,
149        );
150        match query_result {
151            Err(Error::GroveDB(e))
152                if matches!(
153                    e.as_ref(),
154                    GroveError::PathKeyNotFound(_)
155                        | GroveError::PathNotFound(_)
156                        | GroveError::PathParentLayerNotFound(_)
157                ) =>
158            {
159                Ok(BTreeMap::new())
160            }
161            Err(e) => Err(e),
162            Ok((query_result_elements, _)) => {
163                let voters =
164                    query_result_elements
165                        .to_path_key_elements()
166                        .into_iter()
167                        .map(|(path, key, element)| {
168                            let serialized_reference = element.into_item_bytes()?;
169                            let bincode_config = bincode::config::standard()
170                                .with_big_endian()
171                                .with_no_limit();
172                            let reference: ContestedDocumentResourceVoteReferenceStorageForm =
173                                bincode::decode_from_slice(&serialized_reference, bincode_config)
174                                    .map_err(|e| {
175                                        Error::Drive(DriveError::CorruptedSerialization(format!(
176                                            "serialization of reference {} is corrupted: {}",
177                                            hex::encode(serialized_reference),
178                                            e
179                                        )))
180                                    })?
181                                    .0;
182                            let absolute_path = reference
183                                .reference_path_type
184                                .absolute_path(path.as_slice(), Some(key.as_slice()))?;
185                            let vote_id = Identifier::from_vec(key)?;
186                            Ok((
187                                vote_id,
188                                ContestedDocumentResourceVoteStorageForm::try_from_tree_path(
189                                    absolute_path,
190                                )?,
191                            ))
192                        })
193                        .collect::<Result<
194                            BTreeMap<Identifier, ContestedDocumentResourceVoteStorageForm>,
195                            Error,
196                        >>()?;
197
198                Ok(voters)
199            }
200        }
201    }
202
203    #[cfg(feature = "server")]
204    #[allow(unused)]
205    /// Executes an internal query with no proof and returns the values and skipped items.
206    pub(crate) fn execute_no_proof_internal(
207        &self,
208        drive: &Drive,
209        result_type: QueryResultType,
210        transaction: TransactionArg,
211        drive_operations: &mut Vec<LowLevelDriveOperation>,
212        platform_version: &PlatformVersion,
213    ) -> Result<(QueryResultElements, u16), Error> {
214        let path_query = self.construct_path_query()?;
215        let query_result = drive.grove_get_path_query(
216            &path_query,
217            transaction,
218            result_type,
219            drive_operations,
220            &platform_version.drive,
221        );
222        match query_result {
223            Err(Error::GroveDB(e))
224                if matches!(
225                    e.as_ref(),
226                    GroveError::PathKeyNotFound(_)
227                        | GroveError::PathNotFound(_)
228                        | GroveError::PathParentLayerNotFound(_)
229                ) =>
230            {
231                Ok((QueryResultElements::new(), 0))
232            }
233            _ => {
234                let (data, skipped) = query_result?;
235                {
236                    Ok((data, skipped))
237                }
238            }
239        }
240    }
241    /// Operations to construct a path query.
242    pub fn construct_path_query(&self) -> Result<PathQuery, Error> {
243        let path = vote_contested_resource_identity_votes_tree_path_for_identity_vec(
244            self.identity_id.as_bytes(),
245        );
246
247        let mut query = Query::new_with_direction(self.order_ascending);
248
249        // this is a range on all elements
250        match &self.start_at {
251            None => {
252                query.insert_all();
253            }
254            Some((starts_at_key_bytes, start_at_included)) => {
255                let starts_at_key = starts_at_key_bytes.to_vec();
256                match self.order_ascending {
257                    true => match start_at_included {
258                        true => query.insert_range_from(starts_at_key..),
259                        false => query.insert_range_after(starts_at_key..),
260                    },
261                    false => match start_at_included {
262                        true => query.insert_range_to_inclusive(..=starts_at_key),
263                        false => query.insert_range_to(..starts_at_key),
264                    },
265                }
266            }
267        }
268
269        Ok(PathQuery {
270            path,
271            query: SizedQuery {
272                query,
273                limit: self.limit,
274                offset: self.offset,
275            },
276        })
277    }
278}