drive_proof_verifier/proof/
token_info.rs1use crate::error::MapGroveDbError;
2use crate::types::token_info::{IdentitiesTokenInfos, IdentityTokenInfos};
3use crate::verify::verify_tenderdash_proof;
4use crate::{ContextProvider, Error, FromProof};
5use dapi_grpc::platform::v0::{
6 get_identities_token_infos_request, get_identity_token_infos_request,
7 GetIdentitiesTokenInfosRequest, GetIdentitiesTokenInfosResponse, GetIdentityTokenInfosRequest,
8 GetIdentityTokenInfosResponse, Proof, ResponseMetadata,
9};
10use dapi_grpc::platform::VersionedGrpcResponse;
11use dpp::dashcore::Network;
12use dpp::version::PlatformVersion;
13use drive::drive::Drive;
14
15impl FromProof<GetIdentityTokenInfosRequest> for IdentityTokenInfos {
16 type Request = GetIdentityTokenInfosRequest;
17 type Response = GetIdentityTokenInfosResponse;
18
19 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
20 request: I,
21 response: O,
22 _network: Network,
23 platform_version: &PlatformVersion,
24 provider: &'a dyn ContextProvider,
25 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
26 where
27 Self: Sized + 'a,
28 {
29 let request: Self::Request = request.into();
30 let response: Self::Response = response.into();
31
32 let (token_ids, identity_id) = match request.version.ok_or(Error::EmptyVersion)? {
33 get_identity_token_infos_request::Version::V0(v0) => {
34 let identity_id =
35 <[u8; 32]>::try_from(v0.identity_id).map_err(|_| Error::RequestError {
36 error: "can't convert identity_id to [u8; 32]".to_string(),
37 })?;
38
39 let token_ids = v0
40 .token_ids
41 .into_iter()
42 .map(<[u8; 32]>::try_from)
43 .collect::<Result<Vec<_>, _>>()
44 .map_err(|_| Error::RequestError {
45 error: "can't convert token_id to [u8; 32]".to_string(),
46 })?;
47
48 (token_ids, identity_id)
49 }
50 };
51
52 let metadata = response
53 .metadata()
54 .or(Err(Error::EmptyResponseMetadata))?
55 .clone();
56
57 let proof = response.proof_owned().or(Err(Error::NoProofInResult))?;
58
59 let (root_hash, result) = Drive::verify_token_infos_for_identity_id(
60 &proof.grovedb_proof,
61 &token_ids,
62 identity_id,
63 false,
64 platform_version,
65 )
66 .map_drive_error(&proof, &metadata)?;
67
68 verify_tenderdash_proof(&proof, &metadata, &root_hash, provider)?;
69
70 Ok((Some(result), metadata, proof))
71 }
72}
73
74impl FromProof<GetIdentitiesTokenInfosRequest> for IdentitiesTokenInfos {
75 type Request = GetIdentitiesTokenInfosRequest;
76 type Response = GetIdentitiesTokenInfosResponse;
77
78 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
79 request: I,
80 response: O,
81 _network: Network,
82 platform_version: &PlatformVersion,
83 provider: &'a dyn ContextProvider,
84 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
85 where
86 Self: Sized + 'a,
87 {
88 let request: Self::Request = request.into();
89 let response: Self::Response = response.into();
90
91 let (token_id, identity_ids) = match request.version.ok_or(Error::EmptyVersion)? {
92 get_identities_token_infos_request::Version::V0(v0) => {
93 let token_id =
94 <[u8; 32]>::try_from(v0.token_id.clone()).map_err(|_| Error::RequestError {
95 error: "can't convert token_id to [u8; 32]".to_string(),
96 })?;
97
98 let identity_ids = v0
99 .identity_ids
100 .into_iter()
101 .map(<[u8; 32]>::try_from)
102 .collect::<Result<Vec<_>, _>>()
103 .map_err(|_| Error::RequestError {
104 error: "can't convert identity_id to [u8; 32]".to_string(),
105 })?;
106
107 (token_id, identity_ids)
108 }
109 };
110
111 let metadata = response
112 .metadata()
113 .or(Err(Error::EmptyResponseMetadata))?
114 .clone();
115
116 let proof = response.proof_owned().or(Err(Error::NoProofInResult))?;
117
118 let (root_hash, result) = Drive::verify_token_infos_for_identity_ids(
119 &proof.grovedb_proof,
120 token_id,
121 &identity_ids,
122 false,
123 platform_version,
124 )
125 .map_drive_error(&proof, &metadata)?;
126
127 verify_tenderdash_proof(&proof, &metadata, &root_hash, provider)?;
128
129 Ok((Some(result), metadata, proof))
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136 use dapi_grpc::platform::v0::get_identities_token_infos_request::{
137 GetIdentitiesTokenInfosRequestV0, Version as IdsReqVersion,
138 };
139 use dapi_grpc::platform::v0::get_identity_token_infos_request::{
140 GetIdentityTokenInfosRequestV0, Version as IdReqVersion,
141 };
142 use dash_context_provider::ContextProviderError;
143 use dpp::data_contract::TokenConfiguration;
144 use dpp::prelude::{CoreBlockHeight, DataContract, Identifier};
145 use std::sync::Arc;
146
147 struct UnreachableProvider;
148
149 impl ContextProvider for UnreachableProvider {
150 fn get_data_contract(
151 &self,
152 _id: &Identifier,
153 _pv: &PlatformVersion,
154 ) -> Result<Option<Arc<DataContract>>, ContextProviderError> {
155 panic!("should not be called")
156 }
157 fn get_token_configuration(
158 &self,
159 _id: &Identifier,
160 ) -> Result<Option<TokenConfiguration>, ContextProviderError> {
161 panic!("should not be called")
162 }
163 fn get_quorum_public_key(
164 &self,
165 _qt: u32,
166 _qh: [u8; 32],
167 _h: u32,
168 ) -> Result<[u8; 48], ContextProviderError> {
169 panic!("should not be called")
170 }
171 fn get_platform_activation_height(&self) -> Result<CoreBlockHeight, ContextProviderError> {
172 panic!("should not be called")
173 }
174 }
175
176 fn pv() -> &'static PlatformVersion {
177 PlatformVersion::latest()
178 }
179
180 #[test]
183 fn identity_token_infos_empty_version_on_request_missing() {
184 let request = GetIdentityTokenInfosRequest { version: None };
185 let response = GetIdentityTokenInfosResponse::default();
186 let err = <IdentityTokenInfos as FromProof<_>>::maybe_from_proof(
187 request,
188 response,
189 Network::Testnet,
190 pv(),
191 &UnreachableProvider,
192 )
193 .unwrap_err();
194 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
195 }
196
197 #[test]
198 fn identity_token_infos_request_error_on_bad_identity_id() {
199 let request = GetIdentityTokenInfosRequest {
200 version: Some(IdReqVersion::V0(GetIdentityTokenInfosRequestV0 {
201 identity_id: vec![0u8; 8], token_ids: vec![vec![0u8; 32]],
203 prove: true,
204 })),
205 };
206 let response = GetIdentityTokenInfosResponse::default();
207 let err = <IdentityTokenInfos as FromProof<_>>::maybe_from_proof(
208 request,
209 response,
210 Network::Testnet,
211 pv(),
212 &UnreachableProvider,
213 )
214 .unwrap_err();
215 match err {
216 Error::RequestError { error } => assert!(error.contains("identity_id"), "got: {error}"),
217 other => panic!("expected RequestError, got: {other:?}"),
218 }
219 }
220
221 #[test]
222 fn identity_token_infos_request_error_on_bad_token_id() {
223 let request = GetIdentityTokenInfosRequest {
224 version: Some(IdReqVersion::V0(GetIdentityTokenInfosRequestV0 {
225 identity_id: vec![0u8; 32],
226 token_ids: vec![vec![0u8; 4]], prove: true,
228 })),
229 };
230 let response = GetIdentityTokenInfosResponse::default();
231 let err = <IdentityTokenInfos as FromProof<_>>::maybe_from_proof(
232 request,
233 response,
234 Network::Testnet,
235 pv(),
236 &UnreachableProvider,
237 )
238 .unwrap_err();
239 match err {
240 Error::RequestError { error } => assert!(error.contains("token_id"), "got: {error}"),
241 other => panic!("expected RequestError, got: {other:?}"),
242 }
243 }
244
245 #[test]
248 fn identities_token_infos_empty_version_on_request_missing() {
249 let request = GetIdentitiesTokenInfosRequest { version: None };
250 let response = GetIdentitiesTokenInfosResponse::default();
251 let err = <IdentitiesTokenInfos as FromProof<_>>::maybe_from_proof(
252 request,
253 response,
254 Network::Testnet,
255 pv(),
256 &UnreachableProvider,
257 )
258 .unwrap_err();
259 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
260 }
261
262 #[test]
263 fn identities_token_infos_request_error_on_bad_token_id() {
264 let request = GetIdentitiesTokenInfosRequest {
265 version: Some(IdsReqVersion::V0(GetIdentitiesTokenInfosRequestV0 {
266 token_id: vec![0u8; 4], identity_ids: vec![vec![0u8; 32]],
268 prove: true,
269 })),
270 };
271 let response = GetIdentitiesTokenInfosResponse::default();
272 let err = <IdentitiesTokenInfos as FromProof<_>>::maybe_from_proof(
273 request,
274 response,
275 Network::Testnet,
276 pv(),
277 &UnreachableProvider,
278 )
279 .unwrap_err();
280 match err {
281 Error::RequestError { error } => assert!(error.contains("token_id"), "got: {error}"),
282 other => panic!("expected RequestError, got: {other:?}"),
283 }
284 }
285
286 #[test]
287 fn identities_token_infos_request_error_on_bad_identity_id() {
288 let request = GetIdentitiesTokenInfosRequest {
289 version: Some(IdsReqVersion::V0(GetIdentitiesTokenInfosRequestV0 {
290 token_id: vec![0u8; 32],
291 identity_ids: vec![vec![0u8; 32], vec![1u8; 1]], prove: true,
293 })),
294 };
295 let response = GetIdentitiesTokenInfosResponse::default();
296 let err = <IdentitiesTokenInfos as FromProof<_>>::maybe_from_proof(
297 request,
298 response,
299 Network::Testnet,
300 pv(),
301 &UnreachableProvider,
302 )
303 .unwrap_err();
304 match err {
305 Error::RequestError { error } => assert!(error.contains("identity_id"), "got: {error}"),
306 other => panic!("expected RequestError, got: {other:?}"),
307 }
308 }
309}