drive_proof_verifier/proof/
groups.rs

1use crate::error::MapGroveDbError;
2use crate::types::groups::{GroupActionSigners, GroupActions, Groups};
3use crate::verify::verify_tenderdash_proof;
4use crate::{ContextProvider, Error, FromProof};
5use dapi_grpc::platform::v0::{
6    get_group_action_signers_request, get_group_actions_request, get_group_info_request,
7    get_group_infos_request, GetGroupActionSignersRequest, GetGroupActionSignersResponse,
8    GetGroupActionsRequest, GetGroupActionsResponse, GetGroupInfoRequest, GetGroupInfoResponse,
9    GetGroupInfosRequest, GetGroupInfosResponse, Proof, ResponseMetadata,
10};
11use dapi_grpc::platform::VersionedGrpcResponse;
12use dpp::dashcore::Network;
13use dpp::data_contract::group::{Group, GroupMemberPower};
14use dpp::data_contract::GroupContractPosition;
15use dpp::group::group_action::GroupAction;
16use dpp::group::group_action_status::GroupActionStatus;
17use dpp::identifier::Identifier;
18use dpp::version::PlatformVersion;
19use drive::drive::Drive;
20use indexmap::IndexMap;
21
22impl FromProof<GetGroupInfoRequest> for Group {
23    type Request = GetGroupInfoRequest;
24    type Response = GetGroupInfoResponse;
25
26    fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
27        request: I,
28        response: O,
29        _network: Network,
30        platform_version: &PlatformVersion,
31        provider: &'a dyn ContextProvider,
32    ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
33    where
34        Self: Sized + 'a,
35    {
36        let request: Self::Request = request.into();
37        let response: Self::Response = response.into();
38
39        let (contract_id, group_contract_position) = match request
40            .version
41            .ok_or(Error::EmptyVersion)?
42        {
43            get_group_info_request::Version::V0(v0) => {
44                let contract_id =
45                    Identifier::try_from(v0.contract_id).map_err(|error| Error::RequestError {
46                        error: format!("can't convert contract_id to identifier: {error}"),
47                    })?;
48
49                let group_contract_position = v0.group_contract_position as GroupContractPosition;
50
51                (contract_id, group_contract_position)
52            }
53        };
54
55        let metadata = response
56            .metadata()
57            .or(Err(Error::EmptyResponseMetadata))?
58            .clone();
59
60        let proof = response.proof_owned().or(Err(Error::NoProofInResult))?;
61
62        let (root_hash, result) = Drive::verify_group_info(
63            &proof.grovedb_proof,
64            contract_id,
65            group_contract_position,
66            false,
67            platform_version,
68        )
69        .map_drive_error(&proof, &metadata)?;
70
71        verify_tenderdash_proof(&proof, &metadata, &root_hash, provider)?;
72
73        Ok((result, metadata, proof))
74    }
75}
76
77impl FromProof<GetGroupInfosRequest> for Groups {
78    type Request = GetGroupInfosRequest;
79    type Response = GetGroupInfosResponse;
80
81    fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
82        request: I,
83        response: O,
84        _network: Network,
85        platform_version: &PlatformVersion,
86        provider: &'a dyn ContextProvider,
87    ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
88    where
89        Self: Sized + 'a,
90    {
91        let request: Self::Request = request.into();
92        let response: Self::Response = response.into();
93
94        let (contract_id, start_at_group_contract_position, count) = match request
95            .version
96            .ok_or(Error::EmptyVersion)?
97        {
98            get_group_infos_request::Version::V0(v0) => {
99                let contract_id =
100                    Identifier::try_from(v0.contract_id).map_err(|error| Error::RequestError {
101                        error: format!("can't convert contract_id to identifier: {error}"),
102                    })?;
103
104                let start_group_contract_position =
105                    v0.start_at_group_contract_position.map(|start_position| {
106                        (
107                            start_position.start_group_contract_position as GroupContractPosition,
108                            start_position.start_group_contract_position_included,
109                        )
110                    });
111
112                let count = v0.count.map(|count| count as u16);
113
114                (contract_id, start_group_contract_position, count)
115            }
116        };
117
118        let metadata = response
119            .metadata()
120            .or(Err(Error::EmptyResponseMetadata))?
121            .clone();
122
123        let proof = response.proof_owned().or(Err(Error::NoProofInResult))?;
124
125        let (root_hash, result) = Drive::verify_group_infos_in_contract(
126            &proof.grovedb_proof,
127            contract_id,
128            start_at_group_contract_position,
129            count,
130            false,
131            platform_version,
132        )
133        // Make value optional
134        .map(
135            |(root_hash, result): (_, IndexMap<GroupContractPosition, Group>)| {
136                let optional_value_map = result
137                    .into_iter()
138                    .map(|(action_id, group_action)| (action_id, Some(group_action)))
139                    .collect::<Groups>();
140                (root_hash, optional_value_map)
141            },
142        )
143        .map_drive_error(&proof, &metadata)?;
144
145        verify_tenderdash_proof(&proof, &metadata, &root_hash, provider)?;
146
147        Ok((Some(result), metadata, proof))
148    }
149}
150
151impl FromProof<GetGroupActionsRequest> for GroupActions {
152    type Request = GetGroupActionsRequest;
153    type Response = GetGroupActionsResponse;
154
155    fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
156        request: I,
157        response: O,
158        _network: Network,
159        platform_version: &PlatformVersion,
160        provider: &'a dyn ContextProvider,
161    ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
162    where
163        Self: Sized + 'a,
164    {
165        let request: Self::Request = request.into();
166        let response: Self::Response = response.into();
167
168        let (contract_id, group_contract_position, status, start_at_action_id, count) =
169            match request.version.ok_or(Error::EmptyVersion)? {
170                get_group_actions_request::Version::V0(v0) => {
171                    let contract_id = Identifier::try_from(v0.contract_id).map_err(|error| {
172                        Error::RequestError {
173                            error: format!("can't convert contract_id to identifier: {error}"),
174                        }
175                    })?;
176
177                    let start_at_action_id =
178                        v0.start_at_action_id
179                            .map(|start_at_action_id| {
180                                let start_action_id =
181                                    Identifier::try_from(start_at_action_id.start_action_id)
182                                        .map_err(|error| Error::RequestError {
183                                            error: format!(
184                                    "can't convert start_action_id to identifier: {error}"
185                                ),
186                                        })?;
187
188                                Ok::<_, Error>((
189                                    start_action_id,
190                                    start_at_action_id.start_action_id_included,
191                                ))
192                            })
193                            .transpose()?;
194
195                    let group_contract_position =
196                        v0.group_contract_position as GroupContractPosition;
197
198                    let count = v0.count.map(|count| count as u16);
199
200                    let status = GroupActionStatus::try_from(v0.status).map_err(|error| {
201                        Error::RequestError {
202                            error: format!("can't convert status to GroupActionStatus: {error}"),
203                        }
204                    })?;
205
206                    (
207                        contract_id,
208                        group_contract_position,
209                        status,
210                        start_at_action_id,
211                        count,
212                    )
213                }
214            };
215
216        let metadata = response
217            .metadata()
218            .or(Err(Error::EmptyResponseMetadata))?
219            .clone();
220
221        let proof = response.proof_owned().or(Err(Error::NoProofInResult))?;
222
223        let (root_hash, result) = Drive::verify_action_infos_in_contract(
224            &proof.grovedb_proof,
225            contract_id,
226            group_contract_position,
227            status,
228            start_at_action_id,
229            count,
230            false,
231            platform_version,
232        )
233        // Make value optional
234        .map(
235            |(root_hash, result): (_, IndexMap<Identifier, GroupAction>)| {
236                let optional_value_map = result
237                    .into_iter()
238                    .map(|(action_id, group_action)| (action_id, Some(group_action)))
239                    .collect::<GroupActions>();
240                (root_hash, optional_value_map)
241            },
242        )
243        .map_drive_error(&proof, &metadata)?;
244
245        verify_tenderdash_proof(&proof, &metadata, &root_hash, provider)?;
246
247        Ok((Some(result), metadata, proof))
248    }
249}
250
251impl FromProof<GetGroupActionSignersRequest> for GroupActionSigners {
252    type Request = GetGroupActionSignersRequest;
253    type Response = GetGroupActionSignersResponse;
254
255    fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
256        request: I,
257        response: O,
258        _network: Network,
259        platform_version: &PlatformVersion,
260        provider: &'a dyn ContextProvider,
261    ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
262    where
263        Self: Sized + 'a,
264    {
265        let request: Self::Request = request.into();
266        let response: Self::Response = response.into();
267
268        let (contract_id, group_contract_position, status, action_id) = match request
269            .version
270            .ok_or(Error::EmptyVersion)?
271        {
272            get_group_action_signers_request::Version::V0(v0) => {
273                let contract_id =
274                    Identifier::try_from(v0.contract_id).map_err(|error| Error::RequestError {
275                        error: format!("can't convert contract_id to identifier: {error}"),
276                    })?;
277
278                let action_id =
279                    Identifier::try_from(v0.action_id).map_err(|error| Error::RequestError {
280                        error: format!("can't convert action_id to identifier: {error}"),
281                    })?;
282
283                let group_contract_position = v0.group_contract_position as GroupContractPosition;
284
285                let status = GroupActionStatus::try_from(v0.status).map_err(|error| {
286                    Error::RequestError {
287                        error: format!("can't convert status to GroupActionStatus: {error}"),
288                    }
289                })?;
290
291                (contract_id, group_contract_position, status, action_id)
292            }
293        };
294
295        let metadata = response
296            .metadata()
297            .or(Err(Error::EmptyResponseMetadata))?
298            .clone();
299
300        let proof = response.proof_owned().or(Err(Error::NoProofInResult))?;
301
302        let (root_hash, result) = Drive::verify_action_signers(
303            &proof.grovedb_proof,
304            contract_id,
305            group_contract_position,
306            status,
307            action_id,
308            false,
309            platform_version,
310        )
311        // Make value optional
312        .map(
313            |(root_hash, result): (_, IndexMap<Identifier, GroupMemberPower>)| {
314                let optional_value_map = result
315                    .into_iter()
316                    .map(|(action_id, group_action)| (action_id, Some(group_action)))
317                    .collect::<GroupActionSigners>();
318                (root_hash, optional_value_map)
319            },
320        )
321        .map_drive_error(&proof, &metadata)?;
322
323        verify_tenderdash_proof(&proof, &metadata, &root_hash, provider)?;
324
325        Ok((Some(result), metadata, proof))
326    }
327}