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 .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 .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 .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}