1pub mod groups;
2pub mod identity_token_balance;
3pub mod token_contract_info;
4pub mod token_direct_purchase;
5pub mod token_info;
6pub mod token_perpetual_distribution_last_claim;
7pub mod token_pre_programmed_distributions;
8pub mod token_status;
9pub mod token_total_supply;
10
11use crate::from_request::TryFromRequest;
12use crate::verify::verify_tenderdash_proof;
13use crate::{types::*, ContextProvider, DataContractProvider, Error};
14use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::get_evonodes_proposed_epoch_blocks_by_range_request_v0::Start;
15use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0;
16use dapi_grpc::platform::v0::get_path_elements_request::GetPathElementsRequestV0;
17use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_request::{
18 self, GetProtocolVersionUpgradeVoteStatusRequestV0,
19};
20use dapi_grpc::platform::v0::security_level_map::KeyKindRequestType as GrpcKeyKind;
21use dapi_grpc::platform::v0::{
22 get_address_info_request, get_addresses_infos_request,
23 get_contested_resource_identity_votes_request, get_data_contract_history_request, get_data_contract_request, get_data_contracts_request, get_epochs_info_request, get_evonodes_proposed_epoch_blocks_by_ids_request, get_evonodes_proposed_epoch_blocks_by_range_request, get_finalized_epoch_infos_request, get_identities_balances_request, get_identities_contract_keys_request, get_identity_balance_and_revision_request, get_identity_balance_request, get_identity_by_non_unique_public_key_hash_request,
24 get_identity_by_public_key_hash_request, get_identity_contract_nonce_request, get_identity_keys_request, get_identity_nonce_request, get_identity_request, get_path_elements_request, get_prefunded_specialized_balance_request, GetContestedResourceVotersForIdentityRequest, GetContestedResourceVotersForIdentityResponse, GetPathElementsRequest, GetPathElementsResponse, GetProtocolVersionUpgradeStateRequest, GetProtocolVersionUpgradeStateResponse, GetProtocolVersionUpgradeVoteStatusRequest, GetProtocolVersionUpgradeVoteStatusResponse, Proof, ResponseMetadata
25};
26use dapi_grpc::platform::{
27 v0::{self as platform, key_request_type, KeyRequestType as GrpcKeyType},
28 VersionedGrpcResponse,
29};
30use dpp::address_funds::PlatformAddress;
31use dpp::block::block_info::BlockInfo;
32use dpp::block::epoch::EpochIndex;
33use dpp::block::extended_epoch_info::ExtendedEpochInfo;
34use dpp::core_subsidy::NetworkCoreSubsidy;
35use dpp::dashcore::hashes::Hash;
36use dpp::dashcore::{Network, ProTxHash};
37use dpp::document::{Document, DocumentV0Getters};
38use dpp::fee::Credits;
39use dpp::identity::identities_contract_keys::IdentitiesContractKeys;
40use dpp::identity::Purpose;
41use dpp::platform_value::{self};
42use dpp::prelude::{AddressNonce, DataContract, Identifier, Identity};
43use dpp::serialization::PlatformDeserializable;
44use dpp::state_transition::proof_result::StateTransitionProofResult;
45use dpp::state_transition::StateTransition;
46use dpp::version::PlatformVersion;
47use dpp::voting::votes::Vote;
48use drive::drive::identity::identity_and_non_unique_public_key_hash_double_proof::IdentityAndNonUniquePublicKeyHashDoubleProof;
49use drive::drive::identity::key::fetch::{
50 IdentityKeysRequest, KeyKindRequestType, KeyRequestType, PurposeU8, SecurityLevelU8,
51};
52use drive::drive::Drive;
53use drive::error::proof::ProofError;
54use drive::grovedb::Error as GroveError;
55use drive::grovedb::GroveTrunkQueryResult;
56use drive::query::contested_resource_votes_given_by_identity_query::ContestedResourceVotesGivenByIdentityQuery;
57use drive::query::proposer_block_count_query::ProposerQueryType;
58use drive::query::vote_poll_contestant_votes_query::ContestedDocumentVotePollVotesDriveQuery;
59use drive::query::vote_poll_vote_state_query::ContestedDocumentVotePollDriveQuery;
60use drive::query::vote_polls_by_document_type_query::VotePollsByDocumentTypeQuery;
61use drive::query::{DriveDocumentQuery, VotePollsByEndDateDriveQuery};
62use indexmap::IndexMap;
63use std::array::TryFromSliceError;
64use std::collections::BTreeMap;
65use std::num::TryFromIntError;
66use crate::error::MapGroveDbError;
67
68pub trait FromProof<Req> {
82 type Request;
84 type Response;
86
87 fn maybe_from_proof<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
104 request: I,
105 response: O,
106 network: Network,
107 platform_version: &PlatformVersion,
108 provider: &'a dyn ContextProvider,
109 ) -> Result<Option<Self>, Error>
110 where
111 Self: Sized + 'a,
112 {
113 Self::maybe_from_proof_with_metadata(request, response, network, platform_version, provider)
114 .map(|maybe_result| maybe_result.0)
115 }
116
117 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
134 request: I,
135 response: O,
136 network: Network,
137 platform_version: &PlatformVersion,
138 provider: &'a dyn ContextProvider,
139 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
140 where
141 Self: Sized + 'a;
142
143 fn from_proof<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
164 request: I,
165 response: O,
166 network: Network,
167 platform_version: &PlatformVersion,
168 provider: &'a dyn ContextProvider,
169 ) -> Result<Self, Error>
170 where
171 Self: Sized + 'a,
172 {
173 Self::maybe_from_proof(request, response, network, platform_version, provider)?
174 .ok_or(Error::NotFound)
175 }
176
177 fn from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
198 request: I,
199 response: O,
200 network: Network,
201 platform_version: &PlatformVersion,
202 provider: &'a dyn ContextProvider,
203 ) -> Result<(Self, ResponseMetadata), Error>
204 where
205 Self: Sized + 'a,
206 {
207 let (main_item, response_metadata, _) = Self::maybe_from_proof_with_metadata(
208 request,
209 response,
210 network,
211 platform_version,
212 provider,
213 )?;
214 Ok((main_item.ok_or(Error::NotFound)?, response_metadata))
215 }
216
217 fn from_proof_with_metadata_and_proof<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
238 request: I,
239 response: O,
240 network: Network,
241 platform_version: &PlatformVersion,
242 provider: &'a dyn ContextProvider,
243 ) -> Result<(Self, ResponseMetadata, Proof), Error>
244 where
245 Self: Sized + 'a,
246 {
247 let (main_item, response_metadata, proof) = Self::maybe_from_proof_with_metadata(
248 request,
249 response,
250 network,
251 platform_version,
252 provider,
253 )?;
254 Ok((main_item.ok_or(Error::NotFound)?, response_metadata, proof))
255 }
256}
257
258impl FromProof<platform::GetIdentityRequest> for Identity {
259 type Request = platform::GetIdentityRequest;
260 type Response = platform::GetIdentityResponse;
261
262 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
263 request: I,
264 response: O,
265 _network: Network,
266 platform_version: &PlatformVersion,
267 provider: &'a dyn ContextProvider,
268 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
269 where
270 Identity: Sized + 'a,
271 {
272 let request: platform::GetIdentityRequest = request.into();
273 let response: Self::Response = response.into();
274
275 let proof = response.proof().or(Err(Error::NoProofInResult))?;
277 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
278
279 let id = match request.version.ok_or(Error::EmptyVersion)? {
280 get_identity_request::Version::V0(v0) => {
281 Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
282 error: e.to_string(),
283 })?
284 }
285 };
286
287 let (root_hash, maybe_identity) = Drive::verify_full_identity_by_identity_id(
289 &proof.grovedb_proof,
290 false,
291 id.into_buffer(),
292 platform_version,
293 )
294 .map_drive_error(proof, mtd)?;
295
296 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
297
298 Ok((maybe_identity, mtd.clone(), proof.clone()))
299 }
300}
301
302impl FromProof<platform::GetIdentityByPublicKeyHashRequest> for Identity {
304 type Request = platform::GetIdentityByPublicKeyHashRequest;
305 type Response = platform::GetIdentityByPublicKeyHashResponse;
306
307 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
308 request: I,
309 response: O,
310 _network: Network,
311 platform_version: &PlatformVersion,
312 provider: &'a dyn ContextProvider,
313 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
314 where
315 Identity: 'a,
316 {
317 let request = request.into();
318 let response = response.into();
319 let proof = response.proof().or(Err(Error::NoProofInResult))?;
321
322 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
323
324 let public_key_hash = match request.version.ok_or(Error::EmptyVersion)? {
325 get_identity_by_public_key_hash_request::Version::V0(v0) => {
326 let public_key_hash: [u8; 20] =
327 v0.public_key_hash
328 .try_into()
329 .map_err(|_| Error::DriveError {
330 error: "Invalid public key hash length".to_string(),
331 })?;
332 public_key_hash
333 }
334 };
335
336 let (root_hash, maybe_identity) = Drive::verify_full_identity_by_unique_public_key_hash(
338 &proof.grovedb_proof,
339 public_key_hash,
340 platform_version,
341 )
342 .map_drive_error(proof, mtd)?;
343
344 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
345
346 Ok((maybe_identity, mtd.clone(), proof.clone()))
347 }
348}
349
350impl FromProof<platform::GetIdentityByNonUniquePublicKeyHashRequest> for Identity {
351 type Request = platform::GetIdentityByNonUniquePublicKeyHashRequest;
352 type Response = platform::GetIdentityByNonUniquePublicKeyHashResponse;
353 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
354 request: I,
355 response: O,
356 _network: Network,
357 platform_version: &PlatformVersion,
358 provider: &'a dyn ContextProvider,
359 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
360 where
361 Self: Sized + 'a,
362 {
363 let request = request.into();
364 let response = response.into();
365 use platform::get_identity_by_non_unique_public_key_hash_response::{
369 get_identity_by_non_unique_public_key_hash_response_v0::Result as V0Result, Version::V0,
370 };
371
372 let (proved_response, mtd) = match response.version {
373 Some(V0(v0)) => {
374 let proof = if let V0Result::Proof(p) = v0.result.ok_or(Error::NoProofInResult)? {
375 p
376 } else {
377 return Err(Error::NoProofInResult);
378 };
379
380 (proof, v0.metadata.ok_or(Error::EmptyResponseMetadata)?)
381 }
382 _ => return Err(Error::EmptyResponseMetadata),
383 };
384
385 let (public_key_hash, after_identity) = match request.version.ok_or(Error::EmptyVersion)? {
388 get_identity_by_non_unique_public_key_hash_request::Version::V0(v0) => {
389 let public_key_hash =
390 v0.public_key_hash
391 .try_into()
392 .map_err(|_| Error::RequestError {
393 error: "Invalid public key hash length".to_string(),
394 })?;
395
396 let after = v0
397 .start_after
398 .map(|a| {
399 a.try_into().map_err(|_| Error::RequestError {
400 error: "Invalid start_after length".to_string(),
401 })
402 })
403 .transpose()?;
404 (public_key_hash, after)
405 }
406 };
407
408 let proof = proved_response
410 .grovedb_identity_public_key_hash_proof
411 .ok_or(Error::NoProofInResult)?;
412
413 let proof_tuple = IdentityAndNonUniquePublicKeyHashDoubleProof {
414 identity_proof: proved_response.identity_proof_bytes,
415 identity_id_public_key_hash_proof: proof.grovedb_proof.clone(),
416 };
417
418 let (root_hash, maybe_identity) =
420 Drive::verify_full_identity_by_non_unique_public_key_hash(
421 &proof_tuple,
422 public_key_hash,
423 after_identity,
424 platform_version,
425 )
426 .map_err(|e| match e {
427 drive::error::Error::GroveDB(e) => {
428 let maybe_query = match e.as_ref() {
430 GroveError::InvalidProof(path_query, ..) => Some(path_query.clone()),
431 _ => None,
432 };
433
434 Error::GroveDBError {
435 proof_bytes: proof.grovedb_proof.clone(),
436 path_query: maybe_query,
437 height: mtd.height,
438 time_ms: mtd.time_ms,
439 error: e.to_string(),
440 }
441 }
442 _ => e.into(),
443 })?;
444
445 verify_tenderdash_proof(&proof, &mtd, &root_hash, provider)?;
446
447 Ok((maybe_identity, mtd.clone(), proof))
448 }
449}
450
451impl FromProof<platform::GetIdentityKeysRequest> for IdentityPublicKeys {
452 type Request = platform::GetIdentityKeysRequest;
453 type Response = platform::GetIdentityKeysResponse;
454
455 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
456 request: I,
457 response: O,
458 _network: Network,
459 platform_version: &PlatformVersion,
460 provider: &'a dyn ContextProvider,
461 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
462 where
463 IdentityPublicKeys: 'a,
464 {
465 let request: Self::Request = request.into();
466 let response: Self::Response = response.into();
467
468 let proof = response.proof().or(Err(Error::NoProofInResult))?;
470
471 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
472
473 let (request_type, identity_id, limit, offset) =
474 match request.version.ok_or(Error::EmptyVersion)? {
475 get_identity_keys_request::Version::V0(v0) => {
476 let request_type = v0.request_type;
477 let identity_id = Identifier::from_bytes(&v0.identity_id)
478 .map_err(|e| Error::ProtocolError {
479 error: e.to_string(),
480 })?
481 .into_buffer();
482 let limit = v0.limit.map(try_u32_to_u16).transpose()?;
483 let offset = v0.offset.map(try_u32_to_u16).transpose()?;
484 (request_type, identity_id, limit, offset)
485 }
486 };
487
488 let request_type = parse_key_request_type(&request_type)?;
489
490 let key_request = IdentityKeysRequest {
491 identity_id,
492 request_type,
493 limit,
494 offset,
495 };
496
497 tracing::debug!(?identity_id, "checking proof of identity keys");
498
499 let (root_hash, maybe_identity) = Drive::verify_identity_keys_by_identity_id(
501 &proof.grovedb_proof,
502 key_request,
503 false,
504 false,
505 false,
506 platform_version,
507 )
508 .map_drive_error(proof, mtd)?;
509
510 let maybe_keys: Option<IdentityPublicKeys> = if let Some(identity) = maybe_identity {
511 if identity.loaded_public_keys.is_empty() {
512 None
513 } else {
514 let mut keys = identity
515 .loaded_public_keys
516 .into_iter()
517 .map(|(k, v)| (k, Some(v.clone())))
518 .collect::<IdentityPublicKeys>();
519
520 let mut not_found = identity
521 .not_found_public_keys
522 .into_iter()
523 .map(|k| (k, None))
524 .collect::<IdentityPublicKeys>();
525
526 keys.append(&mut not_found);
527
528 Some(keys)
529 }
530 } else {
531 None
532 };
533
534 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
535
536 Ok((maybe_keys, mtd.clone(), proof.clone()))
537 }
538}
539
540fn parse_key_request_type(request: &Option<GrpcKeyType>) -> Result<KeyRequestType, Error> {
541 let key_request_type = request
542 .to_owned()
543 .ok_or(Error::RequestError {
544 error: "missing key request type".to_string(),
545 })?
546 .request
547 .ok_or(Error::RequestError {
548 error: "empty request field in key request type".to_string(),
549 })?;
550
551 let request_type = match key_request_type {
552 key_request_type::Request::AllKeys(_) => KeyRequestType::AllKeys,
553 key_request_type::Request::SpecificKeys(specific_keys) => {
554 KeyRequestType::SpecificKeys(specific_keys.key_ids)
555 }
556 key_request_type::Request::SearchKey(search_key) => {
557 let purpose = search_key
558 .purpose_map
559 .iter()
560 .map(|(k, v)| {
561 let v = v.security_level_map
562 .iter()
563 .map(|(level, &kind)| {
564 let kt = match GrpcKeyKind::try_from(kind) {
565 Ok(GrpcKeyKind::CurrentKeyOfKindRequest) => {
566 Ok(KeyKindRequestType::CurrentKeyOfKindRequest)
567 }
568 Ok(GrpcKeyKind::AllKeysOfKindRequest) => {
569 Ok(KeyKindRequestType::AllKeysOfKindRequest)
570 }
571 _ => Err(Error::RequestError {
572 error: format!("missing requested key type: {}", kind),
573 }),
574 };
575 match kt {
576 Err(e) => Err(e),
577 Ok(d) => Ok((*level as u8, d))
578 }
579 })
580 .collect::<Result<BTreeMap<SecurityLevelU8,KeyKindRequestType>,Error>>();
581
582 match v {
583 Err(e) =>Err(e),
584 Ok(d) => Ok((*k as u8,d)),
585 }
586 })
587 .collect::<Result<BTreeMap<PurposeU8, BTreeMap<SecurityLevelU8, KeyKindRequestType>>,Error>>()?;
588
589 KeyRequestType::SearchKey(purpose)
590 }
591 };
592
593 Ok(request_type)
594}
595
596impl FromProof<platform::GetIdentityNonceRequest> for IdentityNonceFetcher {
597 type Request = platform::GetIdentityNonceRequest;
598 type Response = platform::GetIdentityNonceResponse;
599
600 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
601 request: I,
602 response: O,
603 _network: Network,
604 platform_version: &PlatformVersion,
605 provider: &'a dyn ContextProvider,
606 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
607 where
608 IdentityNonceFetcher: 'a,
609 {
610 let request: Self::Request = request.into();
611 let response: Self::Response = response.into();
612
613 let proof = response.proof().or(Err(Error::NoProofInResult))?;
615
616 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
617
618 let identity_id =
619 match request.version.ok_or(Error::EmptyVersion)? {
620 get_identity_nonce_request::Version::V0(v0) => Ok::<Identifier, Error>(
621 Identifier::from_bytes(&v0.identity_id).map_err(|e| Error::ProtocolError {
622 error: e.to_string(),
623 })?,
624 ),
625 }?;
626
627 let (root_hash, maybe_nonce) = Drive::verify_identity_nonce(
629 &proof.grovedb_proof,
630 identity_id.into_buffer(),
631 false,
632 platform_version,
633 )
634 .map_drive_error(proof, mtd)?;
635
636 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
637
638 Ok((
639 maybe_nonce.map(IdentityNonceFetcher),
640 mtd.clone(),
641 proof.clone(),
642 ))
643 }
644}
645
646impl FromProof<platform::GetIdentityContractNonceRequest> for IdentityContractNonceFetcher {
647 type Request = platform::GetIdentityContractNonceRequest;
648 type Response = platform::GetIdentityContractNonceResponse;
649
650 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
651 request: I,
652 response: O,
653 _network: Network,
654 platform_version: &PlatformVersion,
655 provider: &'a dyn ContextProvider,
656 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
657 where
658 IdentityContractNonceFetcher: 'a,
659 {
660 let request: Self::Request = request.into();
661 let response: Self::Response = response.into();
662
663 let proof = response.proof().or(Err(Error::NoProofInResult))?;
665
666 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
667
668 let (identity_id, contract_id) = match request.version.ok_or(Error::EmptyVersion)? {
669 get_identity_contract_nonce_request::Version::V0(v0) => {
670 Ok::<(Identifier, Identifier), Error>((
671 Identifier::from_bytes(&v0.identity_id).map_err(|e| Error::ProtocolError {
672 error: e.to_string(),
673 })?,
674 Identifier::from_bytes(&v0.contract_id).map_err(|e| Error::ProtocolError {
675 error: e.to_string(),
676 })?,
677 ))
678 }
679 }?;
680
681 let (root_hash, maybe_identity) = Drive::verify_identity_contract_nonce(
683 &proof.grovedb_proof,
684 identity_id.into_buffer(),
685 contract_id.into_buffer(),
686 false,
687 platform_version,
688 )
689 .map_drive_error(proof, mtd)?;
690
691 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
692
693 Ok((
694 maybe_identity.map(IdentityContractNonceFetcher),
695 mtd.clone(),
696 proof.clone(),
697 ))
698 }
699}
700
701impl FromProof<platform::GetIdentityBalanceRequest> for IdentityBalance {
702 type Request = platform::GetIdentityBalanceRequest;
703 type Response = platform::GetIdentityBalanceResponse;
704
705 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
706 request: I,
707 response: O,
708 _network: Network,
709 platform_version: &PlatformVersion,
710 provider: &'a dyn ContextProvider,
711 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
712 where
713 IdentityBalance: 'a,
714 {
715 let request: Self::Request = request.into();
716 let response: Self::Response = response.into();
717
718 let proof = response.proof().or(Err(Error::NoProofInResult))?;
720
721 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
722
723 let id = match request.version.ok_or(Error::EmptyVersion)? {
724 get_identity_balance_request::Version::V0(v0) => Identifier::from_bytes(&v0.id)
725 .map_err(|e| Error::ProtocolError {
726 error: e.to_string(),
727 }),
728 }?;
729
730 let (root_hash, maybe_identity) = Drive::verify_identity_balance_for_identity_id(
732 &proof.grovedb_proof,
733 id.into_buffer(),
734 false,
735 platform_version,
736 )
737 .map_drive_error(proof, mtd)?;
738
739 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
740
741 Ok((maybe_identity, mtd.clone(), proof.clone()))
742 }
743}
744
745impl FromProof<platform::GetIdentitiesBalancesRequest> for IdentityBalances {
746 type Request = platform::GetIdentitiesBalancesRequest;
747 type Response = platform::GetIdentitiesBalancesResponse;
748
749 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
750 request: I,
751 response: O,
752 _network: Network,
753 platform_version: &PlatformVersion,
754 provider: &'a dyn ContextProvider,
755 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
756 where
757 IdentityBalances: 'a,
758 {
759 let request: Self::Request = request.into();
760 let response: Self::Response = response.into();
761 let proof = response.proof().or(Err(Error::NoProofInResult))?;
763
764 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
765
766 let identities_ids = match request.version.ok_or(Error::EmptyVersion)? {
767 get_identities_balances_request::Version::V0(v0) => v0.ids,
768 };
769
770 let identity_ids = identities_ids
771 .into_iter()
772 .map(|identity_bytes| {
773 Identifier::from_bytes(&identity_bytes)
774 .map(|identifier| identifier.into_buffer())
775 .map_err(|e| Error::RequestError {
776 error: format!("identities must be all 32 bytes {}", e),
777 })
778 })
779 .collect::<Result<Vec<[u8; 32]>, Error>>()?;
780 let (root_hash, balances) = Drive::verify_identity_balances_for_identity_ids(
781 &proof.grovedb_proof,
782 false,
783 &identity_ids,
784 platform_version,
785 )
786 .map_drive_error(proof, mtd)?;
787
788 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
789
790 Ok((Some(balances), mtd.clone(), proof.clone()))
791 }
792}
793
794impl FromProof<platform::GetIdentityBalanceAndRevisionRequest> for IdentityBalanceAndRevision {
795 type Request = platform::GetIdentityBalanceAndRevisionRequest;
796 type Response = platform::GetIdentityBalanceAndRevisionResponse;
797
798 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
799 request: I,
800 response: O,
801 _network: Network,
802 platform_version: &PlatformVersion,
803 provider: &'a dyn ContextProvider,
804 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
805 where
806 IdentityBalanceAndRevision: 'a,
807 {
808 let request: Self::Request = request.into();
809 let response: Self::Response = response.into();
810
811 let proof = response.proof().or(Err(Error::NoProofInResult))?;
813
814 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
815
816 let id = match request.version.ok_or(Error::EmptyVersion)? {
817 get_identity_balance_and_revision_request::Version::V0(v0) => {
818 Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
819 error: e.to_string(),
820 })
821 }
822 }?;
823
824 let (root_hash, maybe_identity) =
826 Drive::verify_identity_balance_and_revision_for_identity_id(
827 &proof.grovedb_proof,
828 id.into_buffer(),
829 false,
830 platform_version,
831 )
832 .map_drive_error(proof, mtd)?;
833
834 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
835
836 Ok((maybe_identity, mtd.clone(), proof.clone()))
837 }
838}
839
840impl FromProof<platform::GetAddressInfoRequest> for AddressInfo {
841 type Request = platform::GetAddressInfoRequest;
842 type Response = platform::GetAddressInfoResponse;
843
844 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
845 request: I,
846 response: O,
847 _network: Network,
848 platform_version: &PlatformVersion,
849 provider: &'a dyn ContextProvider,
850 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
851 where
852 AddressInfo: 'a,
853 {
854 let request: Self::Request = request.into();
855 let response: Self::Response = response.into();
856
857 let proof = response.proof().or(Err(Error::NoProofInResult))?;
858 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
859
860 let address = match request.version.ok_or(Error::EmptyVersion)? {
861 get_address_info_request::Version::V0(v0) => PlatformAddress::from_bytes(&v0.address)
862 .map_err(|e| Error::RequestError {
863 error: format!("invalid address: {}", e),
864 })?,
865 };
866
867 let (root_hash, maybe_info) =
868 Drive::verify_address_info(&proof.grovedb_proof, &address, false, platform_version)
869 .map_drive_error(proof, mtd)?;
870
871 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
872
873 let info = maybe_info.map(|(nonce, balance)| AddressInfo {
874 address,
875 nonce,
876 balance,
877 });
878
879 Ok((info, mtd.clone(), proof.clone()))
880 }
881}
882
883impl FromProof<platform::GetAddressesInfosRequest> for AddressInfos {
884 type Request = platform::GetAddressesInfosRequest;
885 type Response = platform::GetAddressesInfosResponse;
886
887 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
888 request: I,
889 response: O,
890 _network: Network,
891 platform_version: &PlatformVersion,
892 provider: &'a dyn ContextProvider,
893 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
894 where
895 AddressInfos: 'a,
896 {
897 let request: Self::Request = request.into();
898 let response: Self::Response = response.into();
899
900 let proof = response.proof().or(Err(Error::NoProofInResult))?;
901 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
902
903 let addresses_bytes = match request.version.ok_or(Error::EmptyVersion)? {
904 get_addresses_infos_request::Version::V0(v0) => v0.addresses,
905 };
906
907 let addresses: Vec<PlatformAddress> = addresses_bytes
908 .into_iter()
909 .map(|bytes| {
910 PlatformAddress::from_bytes(&bytes).map_err(|e| Error::RequestError {
911 error: format!("invalid address: {}", e),
912 })
913 })
914 .collect::<Result<_, _>>()?;
915
916 let (root_hash, entries) = Drive::verify_addresses_infos::<
917 _,
918 Vec<(PlatformAddress, Option<(AddressNonce, Credits)>)>,
919 >(
920 &proof.grovedb_proof,
921 addresses.iter(),
922 false,
923 platform_version,
924 )
925 .map_drive_error(proof, mtd)?;
926
927 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
928
929 let infos = entries
930 .into_iter()
931 .map(|(address, maybe_info)| {
932 let info = maybe_info.map(|(nonce, balance)| AddressInfo {
933 address,
934 nonce,
935 balance,
936 });
937 (address, info)
938 })
939 .collect::<AddressInfos>();
940
941 Ok((Some(infos), mtd.clone(), proof.clone()))
942 }
943}
944
945impl FromProof<platform::GetRecentAddressBalanceChangesRequest> for RecentAddressBalanceChanges {
946 type Request = platform::GetRecentAddressBalanceChangesRequest;
947 type Response = platform::GetRecentAddressBalanceChangesResponse;
948
949 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
950 request: I,
951 response: O,
952 _network: Network,
953 platform_version: &PlatformVersion,
954 provider: &'a dyn ContextProvider,
955 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
956 where
957 RecentAddressBalanceChanges: 'a,
958 {
959 use dapi_grpc::platform::v0::get_recent_address_balance_changes_request;
960
961 let request: Self::Request = request.into();
962 let response: Self::Response = response.into();
963
964 let proof = response.proof().or(Err(Error::NoProofInResult))?;
965 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
966
967 let (start_height, start_height_exclusive) =
968 match request.version.ok_or(Error::EmptyVersion)? {
969 get_recent_address_balance_changes_request::Version::V0(v0) => {
970 (v0.start_height, v0.start_height_exclusive)
971 }
972 };
973
974 let limit = Some(100u16); let (root_hash, verified_changes) = if start_height_exclusive {
977 Drive::verify_recent_address_balance_changes_after(
978 &proof.grovedb_proof,
979 start_height,
980 limit,
981 false,
982 platform_version,
983 )
984 .map_drive_error(proof, mtd)?
985 } else {
986 Drive::verify_recent_address_balance_changes(
987 &proof.grovedb_proof,
988 start_height,
989 limit,
990 false,
991 platform_version,
992 )
993 .map_drive_error(proof, mtd)?
994 };
995
996 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
997
998 let result = RecentAddressBalanceChanges(
999 verified_changes
1000 .into_iter()
1001 .map(|(block_height, changes)| BlockAddressBalanceChanges {
1002 block_height,
1003 changes,
1004 })
1005 .collect(),
1006 );
1007
1008 Ok((Some(result), mtd.clone(), proof.clone()))
1009 }
1010}
1011
1012impl FromProof<platform::GetRecentCompactedAddressBalanceChangesRequest>
1013 for RecentCompactedAddressBalanceChanges
1014{
1015 type Request = platform::GetRecentCompactedAddressBalanceChangesRequest;
1016 type Response = platform::GetRecentCompactedAddressBalanceChangesResponse;
1017
1018 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1019 request: I,
1020 response: O,
1021 _network: Network,
1022 platform_version: &PlatformVersion,
1023 provider: &'a dyn ContextProvider,
1024 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1025 where
1026 RecentCompactedAddressBalanceChanges: 'a,
1027 {
1028 use dapi_grpc::platform::v0::get_recent_compacted_address_balance_changes_request;
1029
1030 let request: Self::Request = request.into();
1031 let response: Self::Response = response.into();
1032
1033 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1034 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1035
1036 let start_block_height = match request.version.ok_or(Error::EmptyVersion)? {
1037 get_recent_compacted_address_balance_changes_request::Version::V0(v0) => {
1038 v0.start_block_height
1039 }
1040 };
1041
1042 let limit = Some(25u16);
1045
1046 let (root_hash, verified_changes) = Drive::verify_compacted_address_balance_changes(
1047 &proof.grovedb_proof,
1048 start_block_height,
1049 limit,
1050 platform_version,
1051 )
1052 .map_drive_error(proof, mtd)?;
1053
1054 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1055
1056 let result = RecentCompactedAddressBalanceChanges(
1057 verified_changes
1058 .into_iter()
1059 .map(|(start_block_height, end_block_height, changes)| {
1060 CompactedBlockAddressBalanceChanges {
1061 start_block_height,
1062 end_block_height,
1063 changes,
1064 }
1065 })
1066 .collect(),
1067 );
1068
1069 Ok((Some(result), mtd.clone(), proof.clone()))
1070 }
1071}
1072
1073impl FromProof<platform::GetAddressesTrunkStateRequest> for GroveTrunkQueryResult {
1074 type Request = platform::GetAddressesTrunkStateRequest;
1075 type Response = platform::GetAddressesTrunkStateResponse;
1076
1077 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1078 _request: I,
1079 response: O,
1080 _network: Network,
1081 platform_version: &PlatformVersion,
1082 provider: &'a dyn ContextProvider,
1083 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1084 where
1085 GroveTrunkQueryResult: 'a,
1086 {
1087 let response: Self::Response = response.into();
1088
1089 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1090 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1091
1092 let (root_hash, trunk_result) =
1093 Drive::verify_address_funds_trunk_query(&proof.grovedb_proof, platform_version)
1094 .map_drive_error(proof, mtd)?;
1095
1096 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1097
1098 Ok((Some(trunk_result), mtd.clone(), proof.clone()))
1099 }
1100}
1101
1102impl FromProof<platform::GetAddressesTrunkStateRequest> for PlatformAddressTrunkState {
1103 type Request = platform::GetAddressesTrunkStateRequest;
1104 type Response = platform::GetAddressesTrunkStateResponse;
1105
1106 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1107 request: I,
1108 response: O,
1109 network: Network,
1110 platform_version: &PlatformVersion,
1111 provider: &'a dyn ContextProvider,
1112 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1113 where
1114 PlatformAddressTrunkState: 'a,
1115 {
1116 let (result, metadata, proof) = <GroveTrunkQueryResult as FromProof<
1117 platform::GetAddressesTrunkStateRequest,
1118 >>::maybe_from_proof_with_metadata(
1119 request, response, network, platform_version, provider
1120 )?;
1121
1122 Ok((result.map(PlatformAddressTrunkState), metadata, proof))
1123 }
1124}
1125
1126impl FromProof<platform::GetNullifiersTrunkStateRequest> for GroveTrunkQueryResult {
1127 type Request = platform::GetNullifiersTrunkStateRequest;
1128 type Response = platform::GetNullifiersTrunkStateResponse;
1129
1130 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1131 request: I,
1132 response: O,
1133 _network: Network,
1134 platform_version: &PlatformVersion,
1135 provider: &'a dyn ContextProvider,
1136 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1137 where
1138 GroveTrunkQueryResult: 'a,
1139 {
1140 let request: Self::Request = request.into();
1141 let response: Self::Response = response.into();
1142
1143 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1144 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1145
1146 let (pool_type, pool_identifier) = match &request.version {
1148 Some(platform::get_nullifiers_trunk_state_request::Version::V0(v0)) => {
1149 let pool_id = if v0.pool_identifier.is_empty() {
1150 None
1151 } else {
1152 Some(v0.pool_identifier.as_slice())
1153 };
1154 (v0.pool_type, pool_id)
1155 }
1156 None => return Err(Error::EmptyVersion),
1157 };
1158
1159 let (root_hash, trunk_result) = Drive::verify_nullifiers_trunk_query(
1160 &proof.grovedb_proof,
1161 pool_type,
1162 pool_identifier,
1163 platform_version,
1164 )
1165 .map_drive_error(proof, mtd)?;
1166
1167 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1168
1169 Ok((Some(trunk_result), mtd.clone(), proof.clone()))
1170 }
1171}
1172
1173impl FromProof<platform::GetNullifiersTrunkStateRequest> for NullifiersTrunkState {
1174 type Request = platform::GetNullifiersTrunkStateRequest;
1175 type Response = platform::GetNullifiersTrunkStateResponse;
1176
1177 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1178 request: I,
1179 response: O,
1180 network: Network,
1181 platform_version: &PlatformVersion,
1182 provider: &'a dyn ContextProvider,
1183 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1184 where
1185 NullifiersTrunkState: 'a,
1186 {
1187 let (result, metadata, proof) = <GroveTrunkQueryResult as FromProof<
1188 platform::GetNullifiersTrunkStateRequest,
1189 >>::maybe_from_proof_with_metadata(
1190 request, response, network, platform_version, provider
1191 )?;
1192
1193 Ok((result.map(NullifiersTrunkState), metadata, proof))
1194 }
1195}
1196
1197impl FromProof<platform::GetDataContractRequest> for DataContract {
1198 type Request = platform::GetDataContractRequest;
1199 type Response = platform::GetDataContractResponse;
1200
1201 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1202 request: I,
1203 response: O,
1204 _network: Network,
1205 platform_version: &PlatformVersion,
1206 provider: &'a dyn ContextProvider,
1207 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1208 where
1209 DataContract: 'a,
1210 {
1211 let request: Self::Request = request.into();
1212 let response: Self::Response = response.into();
1213
1214 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1216
1217 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1218
1219 let id = match request.version.ok_or(Error::EmptyVersion)? {
1220 get_data_contract_request::Version::V0(v0) => {
1221 Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
1222 error: e.to_string(),
1223 })
1224 }
1225 }?;
1226
1227 let (root_hash, maybe_contract) = Drive::verify_contract(
1229 &proof.grovedb_proof,
1230 None,
1231 false,
1232 false,
1233 id.into_buffer(),
1234 platform_version,
1235 )
1236 .map_drive_error(proof, mtd)?;
1237
1238 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1239
1240 Ok((maybe_contract, mtd.clone(), proof.clone()))
1241 }
1242}
1243
1244impl FromProof<platform::GetDataContractRequest> for (DataContract, Vec<u8>) {
1245 type Request = platform::GetDataContractRequest;
1246 type Response = platform::GetDataContractResponse;
1247
1248 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1249 request: I,
1250 response: O,
1251 _network: Network,
1252 platform_version: &PlatformVersion,
1253 provider: &'a dyn ContextProvider,
1254 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1255 where
1256 DataContract: 'a,
1257 {
1258 let request: Self::Request = request.into();
1259 let response: Self::Response = response.into();
1260
1261 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1263
1264 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1265
1266 let id = match request.version.ok_or(Error::EmptyVersion)? {
1267 get_data_contract_request::Version::V0(v0) => {
1268 Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
1269 error: e.to_string(),
1270 })
1271 }
1272 }?;
1273
1274 let (root_hash, maybe_contract) = Drive::verify_contract_return_serialization(
1276 &proof.grovedb_proof,
1277 None,
1278 false,
1279 false,
1280 id.into_buffer(),
1281 platform_version,
1282 )
1283 .map_drive_error(proof, mtd)?;
1284
1285 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1286
1287 Ok((maybe_contract, mtd.clone(), proof.clone()))
1288 }
1289}
1290
1291impl FromProof<platform::GetDataContractsRequest> for DataContracts {
1292 type Request = platform::GetDataContractsRequest;
1293 type Response = platform::GetDataContractsResponse;
1294
1295 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1296 request: I,
1297 response: O,
1298 _network: Network,
1299 platform_version: &PlatformVersion,
1300 provider: &'a dyn ContextProvider,
1301 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1302 where
1303 DataContracts: 'a,
1304 {
1305 let request: Self::Request = request.into();
1306 let response: Self::Response = response.into();
1307
1308 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1310
1311 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1312
1313 let ids = match request.version.ok_or(Error::EmptyVersion)? {
1314 get_data_contracts_request::Version::V0(v0) => v0.ids,
1315 };
1316
1317 let ids = ids
1318 .iter()
1319 .map(|id| {
1320 id.clone().try_into().map_err(|_e| Error::RequestError {
1321 error: format!("wrong id size: expected: {}, got: {}", 32, id.len()),
1322 })
1323 })
1324 .collect::<Result<Vec<[u8; 32]>, Error>>()?;
1325
1326 let (root_hash, contracts) = Drive::verify_contracts(
1328 &proof.grovedb_proof,
1329 false,
1330 ids.as_slice(),
1331 platform_version,
1332 )
1333 .map_drive_error(proof, mtd)?;
1334
1335 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1336 let contracts = contracts
1337 .into_iter()
1338 .map(|(k, v)| {
1339 Identifier::from_bytes(&k).map(|id| (id, v)).map_err(|e| {
1340 Error::ResultEncodingError {
1341 error: e.to_string(),
1342 }
1343 })
1344 })
1345 .collect::<Result<DataContracts, Error>>()?;
1346
1347 let maybe_contracts = if contracts.is_empty() {
1348 None
1349 } else {
1350 Some(contracts)
1351 };
1352
1353 Ok((maybe_contracts, mtd.clone(), proof.clone()))
1354 }
1355}
1356
1357impl FromProof<platform::GetDataContractHistoryRequest> for DataContractHistory {
1358 type Request = platform::GetDataContractHistoryRequest;
1359 type Response = platform::GetDataContractHistoryResponse;
1360
1361 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1362 request: I,
1363 response: O,
1364 _network: Network,
1365 platform_version: &PlatformVersion,
1366 provider: &'a dyn ContextProvider,
1367 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1368 where
1369 Self: Sized + 'a,
1370 {
1371 let request: Self::Request = request.into();
1372 let response: Self::Response = response.into();
1373
1374 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1376
1377 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1378
1379 let (id, limit, offset, start_at_ms) = match request.version.ok_or(Error::EmptyVersion)? {
1380 get_data_contract_history_request::Version::V0(v0) => {
1381 let id = Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
1382 error: e.to_string(),
1383 })?;
1384 let limit = u32_to_u16_opt(v0.limit.unwrap_or_default())?;
1385 let offset = u32_to_u16_opt(v0.offset.unwrap_or_default())?;
1386 let start_at_ms = v0.start_at_ms;
1387 (id, limit, offset, start_at_ms)
1388 }
1389 };
1390
1391 let (root_hash, maybe_history) = Drive::verify_contract_history(
1393 &proof.grovedb_proof,
1394 id.into_buffer(),
1395 start_at_ms,
1396 limit,
1397 offset,
1398 platform_version,
1399 )
1400 .map_drive_error(proof, mtd)?;
1401
1402 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1403
1404 Ok((
1405 maybe_history.map(IndexMap::from_iter),
1406 mtd.clone(),
1407 proof.clone(),
1408 ))
1409 }
1410}
1411
1412impl FromProof<platform::BroadcastStateTransitionRequest> for StateTransitionProofResult {
1413 type Request = platform::BroadcastStateTransitionRequest;
1414 type Response = platform::WaitForStateTransitionResultResponse;
1415
1416 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1417 request: I,
1418 response: O,
1419 _network: Network,
1420 platform_version: &PlatformVersion,
1421 provider: &'a dyn ContextProvider,
1422 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1423 where
1424 Self: Sized + 'a,
1425 {
1426 let request: Self::Request = request.into();
1427 let response: Self::Response = response.into();
1428
1429 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1431
1432 let state_transition = StateTransition::deserialize_from_bytes(&request.state_transition)
1433 .map_err(|e| Error::ProtocolError {
1434 error: e.to_string(),
1435 })?;
1436
1437 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1438
1439 let epoch_u16 = try_u32_to_u16(mtd.epoch).map_err(|_| {
1440 Into::<Error>::into(drive::error::Error::Proof(ProofError::InvalidMetadata(
1441 format!(
1442 "platform returned an epoch {} that was higher than maximum of a 16 bit integer",
1443 mtd.epoch
1444 ),
1445 )))
1446 })?;
1447
1448 let block_info = BlockInfo {
1449 time_ms: mtd.time_ms,
1450 height: mtd.height,
1451 core_height: mtd.core_chain_locked_height,
1452 epoch: epoch_u16.try_into()?,
1453 };
1454
1455 let contracts_provider_fn = provider.as_contract_lookup_fn(platform_version);
1456
1457 let (root_hash, result) = Drive::verify_state_transition_was_executed_with_proof(
1458 &state_transition,
1459 &block_info,
1460 &proof.grovedb_proof,
1461 &contracts_provider_fn,
1462 platform_version,
1463 )
1464 .map_drive_error(proof, mtd)?;
1465
1466 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1467
1468 Ok((Some(result), mtd.clone(), proof.clone()))
1469 }
1470}
1471
1472impl FromProof<platform::GetEpochsInfoRequest> for ExtendedEpochInfo {
1473 type Request = platform::GetEpochsInfoRequest;
1474 type Response = platform::GetEpochsInfoResponse;
1475
1476 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1477 request: I,
1478 response: O,
1479 network: Network,
1480 platform_version: &PlatformVersion,
1481 provider: &'a dyn ContextProvider,
1482 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1483 where
1484 Self: Sized + 'a,
1485 {
1486 let epochs = ExtendedEpochInfos::maybe_from_proof_with_metadata(
1487 request,
1488 response,
1489 network,
1490 platform_version,
1491 provider,
1492 )?;
1493
1494 if let Some(e) = epochs.0 {
1495 if e.len() != 1 {
1496 return Err(Error::RequestError {
1497 error: format!("expected 1 epoch, got {}", e.len()),
1498 });
1499 }
1500 let epoch = e.into_iter().next().and_then(|v| v.1);
1501 Ok((epoch, epochs.1, epochs.2))
1502 } else {
1503 Ok((None, epochs.1, epochs.2))
1504 }
1505 }
1506}
1507
1508impl FromProof<platform::GetEpochsInfoRequest> for ExtendedEpochInfos {
1509 type Request = platform::GetEpochsInfoRequest;
1510 type Response = platform::GetEpochsInfoResponse;
1511
1512 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1513 request: I,
1514 response: O,
1515 _network: Network,
1516 platform_version: &PlatformVersion,
1517 provider: &'a dyn ContextProvider,
1518 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1519 where
1520 Self: Sized + 'a,
1521 {
1522 let request: Self::Request = request.into();
1523 let response: Self::Response = response.into();
1524 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1526
1527 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1528
1529 let (start_epoch, count, ascending) = match request.version.ok_or(Error::EmptyVersion)? {
1530 get_epochs_info_request::Version::V0(v0) => (v0.start_epoch, v0.count, v0.ascending),
1531 };
1532
1533 let current_epoch: EpochIndex = try_u32_to_u16(mtd.epoch)?;
1534 let start_epoch: Option<EpochIndex> = if let Some(epoch) = start_epoch {
1535 Some(try_u32_to_u16(epoch)?)
1536 } else {
1537 None
1538 };
1539 let count = try_u32_to_u16(count)?;
1540
1541 let (root_hash, epoch_info) = Drive::verify_epoch_infos(
1542 &proof.grovedb_proof,
1543 current_epoch,
1544 start_epoch,
1545 count,
1546 ascending,
1547 platform_version,
1548 )
1549 .map_drive_error(proof, mtd)?;
1550
1551 let epoch_info = epoch_info
1552 .into_iter()
1553 .map(|v| {
1554 #[allow(clippy::infallible_destructuring_match)]
1555 let info = match &v {
1556 ExtendedEpochInfo::V0(i) => i,
1557 };
1558
1559 (info.index, Some(v))
1560 })
1561 .collect::<ExtendedEpochInfos>();
1562
1563 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1564
1565 Ok((epoch_info.into_option(), mtd.clone(), proof.clone()))
1566 }
1567}
1568
1569impl FromProof<platform::GetFinalizedEpochInfosRequest> for FinalizedEpochInfos {
1570 type Request = platform::GetFinalizedEpochInfosRequest;
1571 type Response = platform::GetFinalizedEpochInfosResponse;
1572
1573 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1574 request: I,
1575 response: O,
1576 _network: Network,
1577 platform_version: &PlatformVersion,
1578 provider: &'a dyn ContextProvider,
1579 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1580 where
1581 Self: Sized + 'a,
1582 {
1583 let request: Self::Request = request.into();
1584 let response: Self::Response = response.into();
1585 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1587
1588 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1589
1590 let (
1591 start_epoch_index,
1592 start_epoch_index_included,
1593 end_epoch_index,
1594 end_epoch_index_included,
1595 ) = match request.version.ok_or(Error::EmptyVersion)? {
1596 get_finalized_epoch_infos_request::Version::V0(v0) => (
1597 v0.start_epoch_index,
1598 v0.start_epoch_index_included,
1599 v0.end_epoch_index,
1600 v0.end_epoch_index_included,
1601 ),
1602 };
1603
1604 let start_epoch_index: EpochIndex = try_u32_to_u16(start_epoch_index)?;
1605 let end_epoch_index: EpochIndex = try_u32_to_u16(end_epoch_index)?;
1606
1607 let (root_hash, epoch_info) = Drive::verify_finalized_epoch_infos(
1608 &proof.grovedb_proof,
1609 start_epoch_index,
1610 start_epoch_index_included,
1611 end_epoch_index,
1612 end_epoch_index_included,
1613 platform_version,
1614 )
1615 .map_drive_error(proof, mtd)?;
1616
1617 let epoch_info = epoch_info
1618 .into_iter()
1619 .map(|(epoch_index, finalized_epoch_info)| (epoch_index, Some(finalized_epoch_info)))
1620 .collect::<FinalizedEpochInfos>();
1621
1622 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1623
1624 Ok((epoch_info.into_option(), mtd.clone(), proof.clone()))
1625 }
1626}
1627
1628fn try_u32_to_u16(i: u32) -> Result<u16, Error> {
1629 i.try_into()
1630 .map_err(|e: TryFromIntError| Error::RequestError {
1631 error: e.to_string(),
1632 })
1633}
1634
1635impl FromProof<GetProtocolVersionUpgradeStateRequest> for ProtocolVersionUpgrades {
1636 type Request = GetProtocolVersionUpgradeStateRequest;
1637 type Response = GetProtocolVersionUpgradeStateResponse;
1638
1639 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1640 _request: I,
1641 response: O,
1642 _network: Network,
1643 platform_version: &PlatformVersion,
1644 provider: &'a dyn ContextProvider,
1645 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1646 where
1647 Self: Sized + 'a,
1648 {
1649 let response: Self::Response = response.into();
1650 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1652 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1653
1654 let (root_hash, objects) =
1655 Drive::verify_upgrade_state(&proof.grovedb_proof, platform_version)
1656 .map_drive_error(proof, mtd)?;
1657
1658 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1659
1660 let response: Self = objects.into_iter().map(|(k, v)| (k, Some(v))).collect();
1662
1663 Ok((response.into_option(), mtd.clone(), proof.clone()))
1664 }
1665}
1666
1667impl FromProof<GetProtocolVersionUpgradeVoteStatusRequest> for MasternodeProtocolVotes {
1668 type Request = GetProtocolVersionUpgradeVoteStatusRequest;
1669 type Response = GetProtocolVersionUpgradeVoteStatusResponse;
1670
1671 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1672 request: I,
1673 response: O,
1674 _network: Network,
1675 platform_version: &PlatformVersion,
1676 provider: &'a dyn ContextProvider,
1677 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1678 where
1679 Self: Sized + 'a,
1680 {
1681 let request = request.into();
1682 let response: Self::Response = response.into();
1683 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1685 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1686
1687 let request_v0: GetProtocolVersionUpgradeVoteStatusRequestV0 = match request.version {
1688 Some(get_protocol_version_upgrade_vote_status_request::Version::V0(v0)) => v0,
1689 None => return Err(Error::EmptyVersion),
1690 };
1691
1692 let start_pro_tx_hash: Option<[u8; 32]> =
1693 if request_v0.start_pro_tx_hash.is_empty() {
1694 None
1695 } else {
1696 Some(request_v0.start_pro_tx_hash[..].try_into().map_err(
1697 |e: TryFromSliceError| Error::RequestError {
1698 error: e.to_string(),
1699 },
1700 )?)
1701 };
1702
1703 let (root_hash, objects) = Drive::verify_upgrade_vote_status(
1704 &proof.grovedb_proof,
1705 start_pro_tx_hash,
1706 try_u32_to_u16(request_v0.count)?,
1707 platform_version,
1708 )
1709 .map_drive_error(proof, mtd)?;
1710
1711 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1712
1713 if objects.is_empty() {
1714 return Ok((None, mtd.clone(), proof.clone()));
1715 }
1716 let votes: MasternodeProtocolVotes = objects
1717 .into_iter()
1718 .map(|(key, value)| {
1719 ProTxHash::from_slice(&key)
1720 .map(|pro_tx_hash| {
1721 (
1722 pro_tx_hash,
1723 Some(MasternodeProtocolVote {
1724 pro_tx_hash,
1725 voted_version: value,
1726 }),
1727 )
1728 })
1729 .map_err(|e| Error::ResultEncodingError {
1730 error: e.to_string(),
1731 })
1732 })
1733 .collect::<Result<MasternodeProtocolVotes, Error>>()?;
1734
1735 Ok((votes.into_option(), mtd.clone(), proof.clone()))
1736 }
1737}
1738
1739impl FromProof<GetPathElementsRequest> for Elements {
1740 type Request = GetPathElementsRequest;
1741 type Response = GetPathElementsResponse;
1742
1743 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1744 request: I,
1745 response: O,
1746 _network: Network,
1747 platform_version: &PlatformVersion,
1748 provider: &'a dyn ContextProvider,
1749 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1750 where
1751 Self: Sized + 'a,
1752 {
1753 let request = request.into();
1754 let response: Self::Response = response.into();
1755 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1757 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1758
1759 let request_v0: GetPathElementsRequestV0 = match request.version {
1760 Some(get_path_elements_request::Version::V0(v0)) => v0,
1761 None => return Err(Error::EmptyVersion),
1762 };
1763
1764 let path = request_v0.path;
1765 let keys = request_v0.keys;
1766
1767 let (root_hash, objects) =
1768 Drive::verify_elements(&proof.grovedb_proof, path, keys, platform_version)?;
1769 let elements: Elements = Elements::from_iter(objects);
1770
1771 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1772
1773 Ok((elements.into_option(), mtd.clone(), proof.clone()))
1774 }
1775}
1776
1777impl<'dq, Q> FromProof<Q> for Documents
1778where
1779 Q: TryInto<DriveDocumentQuery<'dq>> + Clone + 'dq,
1780 Q::Error: std::fmt::Display,
1781{
1782 type Request = Q;
1783 type Response = platform::GetDocumentsResponse;
1784
1785 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1786 request: I,
1787 response: O,
1788 _network: Network,
1789 platform_version: &PlatformVersion,
1790 provider: &'a dyn ContextProvider,
1791 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1792 where
1793 Self: 'a,
1794 {
1795 let request: Self::Request = request.into();
1796 let response: Self::Response = response.into();
1797
1798 let request: DriveDocumentQuery<'dq> =
1799 request
1800 .clone()
1801 .try_into()
1802 .map_err(|e: Q::Error| Error::RequestError {
1803 error: e.to_string(),
1804 })?;
1805
1806 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1808
1809 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1810
1811 let (root_hash, documents) = request
1812 .verify_proof(&proof.grovedb_proof, platform_version)
1813 .map_drive_error(proof, mtd)?;
1814
1815 let documents = documents
1816 .into_iter()
1817 .map(|d| (d.id(), Some(d)))
1818 .collect::<Documents>();
1819
1820 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1821
1822 Ok((documents.into_option(), mtd.clone(), proof.clone()))
1823 }
1824}
1825
1826impl FromProof<platform::GetIdentitiesContractKeysRequest> for IdentitiesContractKeys {
1827 type Request = platform::GetIdentitiesContractKeysRequest;
1828 type Response = platform::GetIdentitiesContractKeysResponse;
1829
1830 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1831 request: I,
1832 response: O,
1833 _network: Network,
1834 platform_version: &PlatformVersion,
1835 provider: &'a dyn ContextProvider,
1836 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1837 where
1838 Self: 'a,
1839 {
1840 let request: Self::Request = request.into();
1841 let response: Self::Response = response.into();
1842
1843 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1845
1846 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1847
1848 let (identities_ids, contract_id, document_type_name, purposes) =
1849 match request.version.ok_or(Error::EmptyVersion)? {
1850 get_identities_contract_keys_request::Version::V0(v0) => {
1851 let GetIdentitiesContractKeysRequestV0 {
1852 identities_ids,
1853 contract_id,
1854 document_type_name,
1855 purposes,
1856 ..
1857 } = v0;
1858 let identifiers = identities_ids
1859 .into_iter()
1860 .map(|identity_id_vec| {
1861 let identifier = Identifier::from_vec(identity_id_vec)?;
1862 Ok(identifier.to_buffer())
1863 })
1864 .collect::<Result<Vec<[u8; 32]>, platform_value::Error>>()
1865 .map_err(|e| Error::ProtocolError {
1866 error: e.to_string(),
1867 })?;
1868 let contract_id = Identifier::from_vec(contract_id)
1869 .map_err(|e| Error::ProtocolError {
1870 error: e.to_string(),
1871 })?
1872 .into_buffer();
1873 let purposes = purposes
1874 .into_iter()
1875 .map(|purpose| {
1876 Purpose::try_from(purpose).map_err(|e| Error::ProtocolError {
1877 error: e.to_string(),
1878 })
1879 })
1880 .collect::<Result<Vec<Purpose>, Error>>()?;
1881 (identifiers, contract_id, document_type_name, purposes)
1882 }
1883 };
1884
1885 let (root_hash, identities_contract_keys) = Drive::verify_identities_contract_keys(
1887 &proof.grovedb_proof,
1888 identities_ids.as_slice(),
1889 &contract_id,
1890 document_type_name,
1891 purposes,
1892 false,
1893 platform_version,
1894 )
1895 .map_drive_error(proof, mtd)?;
1896
1897 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1898
1899 if identities_contract_keys.is_empty() {
1900 return Ok((None, mtd.clone(), proof.clone()));
1901 }
1902
1903 Ok((Some(identities_contract_keys), mtd.clone(), proof.clone()))
1904 }
1905}
1906
1907impl FromProof<platform::GetContestedResourcesRequest> for ContestedResources {
1908 type Request = platform::GetContestedResourcesRequest;
1909 type Response = platform::GetContestedResourcesResponse;
1910
1911 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1912 request: I,
1913 response: O,
1914 _network: Network,
1915 platform_version: &PlatformVersion,
1916 provider: &'a dyn ContextProvider,
1917 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1918 where
1919 Self: Sized + 'a,
1920 {
1921 let request: Self::Request = request.into();
1922 let response: Self::Response = response.into();
1923
1924 let drive_query = VotePollsByDocumentTypeQuery::try_from_request(request)?;
1926 let resolved_request = drive_query.resolve_with_known_contracts_provider(
1927 &provider.as_contract_lookup_fn(platform_version),
1928 )?;
1929
1930 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1932 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1933
1934 let (root_hash, items) = resolved_request
1935 .verify_contests_proof(&proof.grovedb_proof, platform_version)
1936 .map_drive_error(proof, mtd)?;
1937
1938 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1939
1940 let resources: ContestedResources = items.into_iter().map(ContestedResource).collect();
1941
1942 Ok((resources.into_option(), mtd.clone(), proof.clone()))
1943 }
1944}
1945
1946impl FromProof<platform::GetContestedResourceVoteStateRequest> for Contenders {
1948 type Request = platform::GetContestedResourceVoteStateRequest;
1949 type Response = platform::GetContestedResourceVoteStateResponse;
1950
1951 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1952 request: I,
1953 response: O,
1954 _network: Network,
1955 platform_version: &PlatformVersion,
1956 provider: &'a dyn ContextProvider,
1957 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1958 where
1959 Self: 'a,
1960 {
1961 let request: Self::Request = request.into();
1962 let response: Self::Response = response.into();
1963
1964 let drive_query = ContestedDocumentVotePollDriveQuery::try_from_request(request)?;
1966
1967 let contracts_provider = provider.as_contract_lookup_fn(platform_version);
1969 let resolved_request =
1970 drive_query.resolve_with_known_contracts_provider(&contracts_provider)?;
1971
1972 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1974 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1975
1976 let (root_hash, contested_resource_vote_state) = resolved_request
1977 .verify_vote_poll_vote_state_proof(&proof.grovedb_proof, platform_version)
1978 .map_drive_error(proof, mtd)?;
1979
1980 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1981
1982 let contenders = contested_resource_vote_state
1983 .contenders
1984 .into_iter()
1985 .map(|v| (v.identity_id(), v))
1986 .collect();
1987
1988 let response = Contenders {
1989 winner: contested_resource_vote_state.winner,
1990 contenders,
1991 abstain_vote_tally: contested_resource_vote_state.abstaining_vote_tally,
1992 lock_vote_tally: contested_resource_vote_state.locked_vote_tally,
1993 };
1994 Ok((response.into_option(), mtd.clone(), proof.clone()))
1995 }
1996}
1997
1998impl FromProof<GetContestedResourceVotersForIdentityRequest> for Voters {
1999 type Request = GetContestedResourceVotersForIdentityRequest;
2000 type Response = GetContestedResourceVotersForIdentityResponse;
2001
2002 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2003 request: I,
2004 response: O,
2005 _network: Network,
2006 platform_version: &PlatformVersion,
2007 provider: &'a dyn ContextProvider,
2008 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2009 where
2010 Self: Sized + 'a,
2011 {
2012 let request: Self::Request = request.into();
2013 let response: Self::Response = response.into();
2014
2015 let drive_query = ContestedDocumentVotePollVotesDriveQuery::try_from_request(request)?;
2017
2018 let contracts_provider = provider.as_contract_lookup_fn(platform_version);
2020
2021 let resolved_request =
2022 drive_query.resolve_with_known_contracts_provider(&contracts_provider)?;
2023
2024 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2026 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2027
2028 let (root_hash, voters) = resolved_request
2029 .verify_vote_poll_votes_proof(&proof.grovedb_proof, platform_version)
2030 .map_drive_error(proof, mtd)?;
2031
2032 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2033
2034 if voters.is_empty() {
2035 return Ok((None, mtd.clone(), proof.clone()));
2036 }
2037 let result: Voters = voters.into_iter().map(Voter::from).collect();
2038
2039 Ok((result.into_option(), mtd.clone(), proof.clone()))
2040 }
2041}
2042
2043impl FromProof<platform::GetContestedResourceIdentityVotesRequest> for ResourceVotesByIdentity {
2044 type Request = platform::GetContestedResourceIdentityVotesRequest;
2045 type Response = platform::GetContestedResourceIdentityVotesResponse;
2046
2047 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2048 request: I,
2049 response: O,
2050 _network: Network,
2051 platform_version: &PlatformVersion,
2052 provider: &'a dyn ContextProvider,
2053 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2054 where
2055 Self: Sized + 'a,
2056 {
2057 let request: Self::Request = request.into();
2058 let response: Self::Response = response.into();
2059
2060 let drive_query = ContestedResourceVotesGivenByIdentityQuery::try_from_request(request)?;
2062
2063 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2065 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2066
2067 let contract_provider_fn = provider.as_contract_lookup_fn(platform_version);
2068 let (root_hash, voters) = drive_query
2069 .verify_identity_votes_given_proof::<Vec<_>>(
2070 &proof.grovedb_proof,
2071 &contract_provider_fn,
2072 platform_version,
2073 )
2074 .map_drive_error(proof, mtd)?;
2075
2076 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2077
2078 let response: ResourceVotesByIdentity = voters
2079 .into_iter()
2080 .map(|(id, vote)| (id, Some(vote)))
2081 .collect();
2082
2083 Ok((response.into_option(), mtd.clone(), proof.clone()))
2084 }
2085}
2086
2087impl FromProof<platform::GetVotePollsByEndDateRequest> for VotePollsGroupedByTimestamp {
2088 type Request = platform::GetVotePollsByEndDateRequest;
2089 type Response = platform::GetVotePollsByEndDateResponse;
2090
2091 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2092 request: I,
2093 response: O,
2094 _network: Network,
2095 platform_version: &PlatformVersion,
2096 provider: &'a dyn ContextProvider,
2097 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2098 where
2099 Self: Sized + 'a,
2100 {
2101 let request: Self::Request = request.into();
2102 let response: Self::Response = response.into();
2103
2104 let drive_query = VotePollsByEndDateDriveQuery::try_from_request(request)?;
2106
2107 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2109 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2110
2111 let (root_hash, vote_polls) = drive_query
2112 .verify_vote_polls_by_end_date_proof::<Vec<(_, _)>>(
2113 &proof.grovedb_proof,
2114 platform_version,
2115 )
2116 .map_drive_error(proof, mtd)?;
2117
2118 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2119
2120 let response = VotePollsGroupedByTimestamp(vote_polls).sorted(drive_query.order_ascending);
2121
2122 Ok((response.into_option(), mtd.clone(), proof.clone()))
2123 }
2124}
2125
2126impl FromProof<platform::GetPrefundedSpecializedBalanceRequest> for PrefundedSpecializedBalance {
2127 type Request = platform::GetPrefundedSpecializedBalanceRequest;
2128 type Response = platform::GetPrefundedSpecializedBalanceResponse;
2129
2130 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2131 request: I,
2132 response: O,
2133 _network: Network,
2134 platform_version: &PlatformVersion,
2135 provider: &'a dyn ContextProvider,
2136 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2137 where
2138 Self: Sized + 'a,
2139 {
2140 let request: Self::Request = request.into();
2141 let response: Self::Response = response.into();
2142
2143 let balance_id = match request.version.ok_or(Error::EmptyVersion)? {
2144 get_prefunded_specialized_balance_request::Version::V0(v0) => {
2145 Identifier::from_vec(v0.id).map_err(|e| Error::RequestError {
2146 error: e.to_string(),
2147 })?
2148 }
2149 };
2150
2151 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2152
2153 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2154
2155 let (root_hash, balance) = Drive::verify_specialized_balance(
2156 &proof.grovedb_proof,
2157 balance_id.into_buffer(),
2158 false,
2159 platform_version,
2160 )
2161 .map_drive_error(proof, mtd)?;
2162
2163 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2164
2165 Ok((balance.map(|v| v.into()), mtd.clone(), proof.clone()))
2166 }
2167}
2168
2169impl FromProof<platform::GetContestedResourceIdentityVotesRequest> for Vote {
2170 type Request = platform::GetContestedResourceIdentityVotesRequest;
2171 type Response = platform::GetContestedResourceIdentityVotesResponse;
2172
2173 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2174 request: I,
2175 response: O,
2176 network: Network,
2177 platform_version: &PlatformVersion,
2178 provider: &'a dyn ContextProvider,
2179 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2180 where
2181 Self: Sized + 'a,
2182 {
2183 let request = request.into();
2184 let id_in_request = match request.version.as_ref().ok_or(Error::EmptyVersion)? {
2185 get_contested_resource_identity_votes_request::Version::V0(v0) => {
2186 Identifier::from_bytes(&v0.identity_id).map_err(|e| Error::RequestError {
2187 error: e.to_string(),
2188 })?
2189 }
2190 };
2191
2192 let (maybe_votes, mtd, proof) = ResourceVotesByIdentity::maybe_from_proof_with_metadata(
2193 request,
2194 response,
2195 network,
2196 platform_version,
2197 provider,
2198 )?;
2199
2200 let (id, vote) = match maybe_votes {
2201 Some(v) if v.len() > 1 => {
2202 return Err(Error::ResponseDecodeError {
2203 error: format!("expected 1 vote, got {}", v.len()),
2204 })
2205 }
2206 Some(v) if v.is_empty() => return Ok((None, mtd, proof)),
2207 Some(v) => v
2208 .into_iter()
2209 .next()
2210 .expect("is_empty() must detect empty map"),
2211 None => return Ok((None, mtd, proof)),
2212 };
2213
2214 if id != id_in_request {
2215 return Err(Error::ResponseDecodeError {
2216 error: format!(
2217 "expected vote for identity {}, got vote for identity {}",
2218 id_in_request, id
2219 ),
2220 });
2221 }
2222
2223 Ok((vote.map(Vote::ResourceVote), mtd, proof))
2224 }
2225}
2226
2227impl FromProof<platform::GetTotalCreditsInPlatformRequest> for TotalCreditsInPlatform {
2228 type Request = platform::GetTotalCreditsInPlatformRequest;
2229 type Response = platform::GetTotalCreditsInPlatformResponse;
2230
2231 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2232 _request: I,
2233 response: O,
2234 network: Network,
2235 platform_version: &PlatformVersion,
2236 provider: &'a dyn ContextProvider,
2237 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2238 where
2239 Self: Sized + 'a,
2240 {
2241 let response: Self::Response = response.into();
2242 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2244 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2245
2246 let core_subsidy_halving_interval = network.core_subsidy_halving_interval();
2247
2248 let (root_hash, credits) = Drive::verify_total_credits_in_system(
2249 &proof.grovedb_proof,
2250 core_subsidy_halving_interval,
2251 || {
2252 provider.get_platform_activation_height().map_err(|e| {
2253 drive::error::Error::Proof(ProofError::MissingContextRequirement(e.to_string()))
2254 })
2255 },
2256 mtd.core_chain_locked_height,
2257 platform_version,
2258 )
2259 .map_drive_error(proof, mtd)?;
2260
2261 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2262
2263 Ok((
2264 Some(TotalCreditsInPlatform(credits)),
2265 mtd.clone(),
2266 proof.clone(),
2267 ))
2268 }
2269}
2270impl FromProof<platform::GetEvonodesProposedEpochBlocksByIdsRequest> for ProposerBlockCounts {
2271 type Request = platform::GetEvonodesProposedEpochBlocksByIdsRequest;
2272 type Response = platform::GetEvonodesProposedEpochBlocksResponse;
2273
2274 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2275 request: I,
2276 response: O,
2277 _network: Network,
2278 platform_version: &PlatformVersion,
2279 provider: &'a dyn ContextProvider,
2280 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2281 where
2282 Self: Sized + 'a,
2283 {
2284 let request: Self::Request = request.into();
2285 let response: Self::Response = response.into();
2286 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2288 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2289
2290 let (ids, epoch) = match request.version.ok_or(Error::EmptyVersion)? {
2291 get_evonodes_proposed_epoch_blocks_by_ids_request::Version::V0(v0) => {
2292 (v0.ids, v0.epoch)
2293 }
2294 };
2295
2296 let epoch_index = match epoch {
2297 Some(index) => try_u32_to_u16(index)?,
2298 None => try_u32_to_u16(mtd.epoch)?,
2299 };
2300
2301 let (root_hash, proposer_block_counts) = Drive::verify_epoch_proposers(
2302 &proof.grovedb_proof,
2303 epoch_index,
2304 ProposerQueryType::ByIds(ids),
2305 platform_version,
2306 )
2307 .map_drive_error(proof, mtd)?;
2308
2309 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2310
2311 Ok((
2312 Some(ProposerBlockCounts(proposer_block_counts)),
2313 mtd.clone(),
2314 proof.clone(),
2315 ))
2316 }
2317}
2318
2319impl FromProof<platform::GetEvonodesProposedEpochBlocksByRangeRequest> for ProposerBlockCounts {
2320 type Request = platform::GetEvonodesProposedEpochBlocksByRangeRequest;
2321 type Response = platform::GetEvonodesProposedEpochBlocksResponse;
2322
2323 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2324 request: I,
2325 response: O,
2326 _network: Network,
2327 platform_version: &PlatformVersion,
2328 provider: &'a dyn ContextProvider,
2329 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2330 where
2331 Self: Sized + 'a,
2332 {
2333 let request: Self::Request = request.into();
2334 let response: Self::Response = response.into();
2335 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2337 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2338
2339 let (epoch, limit, start) = match request.version.ok_or(Error::EmptyVersion)? {
2340 get_evonodes_proposed_epoch_blocks_by_range_request::Version::V0(v0) => {
2341 (v0.epoch, v0.limit, v0.start)
2342 }
2343 };
2344
2345 let formatted_start = match start {
2346 None => None,
2347 Some(Start::StartAfter(after)) => {
2348 let id: [u8; 32] = after.try_into().map_err(|_| Error::DriveError {
2349 error: "Invalid public key hash length".to_string(),
2350 })?;
2351 Some((id, false))
2352 }
2353 Some(Start::StartAt(at)) => {
2354 let id: [u8; 32] = at.try_into().map_err(|_| Error::DriveError {
2355 error: "Invalid public key hash length".to_string(),
2356 })?;
2357 Some((id, true))
2358 }
2359 };
2360
2361 let epoch_index = match epoch {
2362 Some(index) => try_u32_to_u16(index)?,
2363 None => try_u32_to_u16(mtd.epoch)?,
2364 };
2365 let checked_limit = limit.map(try_u32_to_u16).transpose()?;
2366
2367 let (root_hash, proposer_block_counts) = Drive::verify_epoch_proposers(
2368 &proof.grovedb_proof,
2369 epoch_index,
2370 ProposerQueryType::ByRange(checked_limit, formatted_start),
2371 platform_version,
2372 )
2373 .map_drive_error(proof, mtd)?;
2374
2375 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2376
2377 Ok((
2378 Some(ProposerBlockCounts(proposer_block_counts)),
2379 mtd.clone(),
2380 proof.clone(),
2381 ))
2382 }
2383}
2384
2385fn u32_to_u16_opt(i: u32) -> Result<Option<u16>, Error> {
2388 let i: Option<u16> = if i != 0 {
2389 let i: u16 = i
2390 .try_into()
2391 .map_err(|e: TryFromIntError| Error::RequestError {
2392 error: format!("value {} out of range: {}", i, e),
2393 })?;
2394 Some(i)
2395 } else {
2396 None
2397 };
2398
2399 Ok(i)
2400}
2401
2402impl FromProof<platform::GetShieldedPoolStateRequest> for ShieldedPoolState {
2405 type Request = platform::GetShieldedPoolStateRequest;
2406 type Response = platform::GetShieldedPoolStateResponse;
2407
2408 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2409 _request: I,
2410 response: O,
2411 _network: Network,
2412 platform_version: &PlatformVersion,
2413 provider: &'a dyn ContextProvider,
2414 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2415 where
2416 Self: Sized + 'a,
2417 {
2418 let response: Self::Response = response.into();
2419 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2420 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2421
2422 let (root_hash, maybe_balance) =
2423 Drive::verify_shielded_pool_state(&proof.grovedb_proof, false, platform_version)
2424 .map_drive_error(proof, mtd)?;
2425
2426 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2427
2428 Ok((
2429 maybe_balance.map(ShieldedPoolState),
2430 mtd.clone(),
2431 proof.clone(),
2432 ))
2433 }
2434}
2435
2436impl FromProof<platform::GetShieldedAnchorsRequest> for ShieldedAnchors {
2437 type Request = platform::GetShieldedAnchorsRequest;
2438 type Response = platform::GetShieldedAnchorsResponse;
2439
2440 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2441 _request: I,
2442 response: O,
2443 _network: Network,
2444 platform_version: &PlatformVersion,
2445 provider: &'a dyn ContextProvider,
2446 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2447 where
2448 Self: Sized + 'a,
2449 {
2450 let response: Self::Response = response.into();
2451 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2452 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2453
2454 let (root_hash, anchors) =
2455 Drive::verify_shielded_anchors(&proof.grovedb_proof, false, platform_version)
2456 .map_drive_error(proof, mtd)?;
2457
2458 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2459
2460 let result = if anchors.is_empty() {
2461 None
2462 } else {
2463 Some(ShieldedAnchors(anchors))
2464 };
2465
2466 Ok((result, mtd.clone(), proof.clone()))
2467 }
2468}
2469
2470impl FromProof<platform::GetMostRecentShieldedAnchorRequest> for MostRecentShieldedAnchor {
2471 type Request = platform::GetMostRecentShieldedAnchorRequest;
2472 type Response = platform::GetMostRecentShieldedAnchorResponse;
2473
2474 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2475 _request: I,
2476 response: O,
2477 _network: Network,
2478 platform_version: &PlatformVersion,
2479 provider: &'a dyn ContextProvider,
2480 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2481 where
2482 Self: Sized + 'a,
2483 {
2484 let response: Self::Response = response.into();
2485 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2486 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2487
2488 let (root_hash, maybe_anchor) = Drive::verify_most_recent_shielded_anchor(
2489 &proof.grovedb_proof,
2490 false,
2491 platform_version,
2492 )
2493 .map_drive_error(proof, mtd)?;
2494
2495 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2496
2497 Ok((
2498 maybe_anchor.map(MostRecentShieldedAnchor),
2499 mtd.clone(),
2500 proof.clone(),
2501 ))
2502 }
2503}
2504
2505impl FromProof<platform::GetShieldedEncryptedNotesRequest> for ShieldedEncryptedNotes {
2506 type Request = platform::GetShieldedEncryptedNotesRequest;
2507 type Response = platform::GetShieldedEncryptedNotesResponse;
2508
2509 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2510 request: I,
2511 response: O,
2512 _network: Network,
2513 platform_version: &PlatformVersion,
2514 provider: &'a dyn ContextProvider,
2515 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2516 where
2517 Self: Sized + 'a,
2518 {
2519 use dapi_grpc::platform::v0::get_shielded_encrypted_notes_request;
2520
2521 let request: Self::Request = request.into();
2522 let response: Self::Response = response.into();
2523 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2524 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2525
2526 let (start_index, count) = match request.version.ok_or(Error::EmptyVersion)? {
2527 get_shielded_encrypted_notes_request::Version::V0(v0) => (v0.start_index, v0.count),
2528 };
2529
2530 let max_elements = platform_version
2531 .drive_abci
2532 .query
2533 .shielded_queries
2534 .max_encrypted_notes_per_query as u32;
2535
2536 let (root_hash, notes) = Drive::verify_shielded_encrypted_notes(
2537 &proof.grovedb_proof,
2538 start_index,
2539 count,
2540 max_elements,
2541 false,
2542 platform_version,
2543 )
2544 .map_drive_error(proof, mtd)?;
2545
2546 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2547
2548 let result = if notes.is_empty() {
2549 None
2550 } else {
2551 Some(ShieldedEncryptedNotes(
2552 notes
2553 .into_iter()
2554 .map(|(cmx, nullifier, encrypted_note)| ShieldedEncryptedNote {
2555 cmx,
2556 nullifier,
2557 encrypted_note,
2558 })
2559 .collect(),
2560 ))
2561 };
2562
2563 Ok((result, mtd.clone(), proof.clone()))
2564 }
2565}
2566
2567impl FromProof<platform::GetShieldedNullifiersRequest> for ShieldedNullifierStatuses {
2568 type Request = platform::GetShieldedNullifiersRequest;
2569 type Response = platform::GetShieldedNullifiersResponse;
2570
2571 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2572 request: I,
2573 response: O,
2574 _network: Network,
2575 platform_version: &PlatformVersion,
2576 provider: &'a dyn ContextProvider,
2577 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2578 where
2579 Self: Sized + 'a,
2580 {
2581 use dapi_grpc::platform::v0::get_shielded_nullifiers_request;
2582
2583 let request: Self::Request = request.into();
2584 let response: Self::Response = response.into();
2585 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2586 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2587
2588 let nullifiers = match request.version.ok_or(Error::EmptyVersion)? {
2589 get_shielded_nullifiers_request::Version::V0(v0) => v0.nullifiers,
2590 };
2591
2592 let (root_hash, statuses) = Drive::verify_shielded_nullifiers(
2593 &proof.grovedb_proof,
2594 &nullifiers,
2595 false,
2596 platform_version,
2597 )
2598 .map_drive_error(proof, mtd)?;
2599
2600 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2601
2602 let result = if statuses.is_empty() {
2603 None
2604 } else {
2605 Some(ShieldedNullifierStatuses(
2606 statuses
2607 .into_iter()
2608 .map(|(nullifier, is_spent)| {
2609 let nullifier: [u8; 32] =
2610 nullifier
2611 .try_into()
2612 .map_err(|_| Error::ResultEncodingError {
2613 error: "nullifier from Drive proof is not 32 bytes".to_string(),
2614 })?;
2615 Ok(ShieldedNullifierStatus {
2616 nullifier,
2617 is_spent,
2618 })
2619 })
2620 .collect::<Result<Vec<_>, Error>>()?,
2621 ))
2622 };
2623
2624 Ok((result, mtd.clone(), proof.clone()))
2625 }
2626}
2627
2628impl FromProof<platform::GetRecentNullifierChangesRequest> for RecentNullifierChanges {
2629 type Request = platform::GetRecentNullifierChangesRequest;
2630 type Response = platform::GetRecentNullifierChangesResponse;
2631
2632 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2633 request: I,
2634 response: O,
2635 _network: Network,
2636 platform_version: &PlatformVersion,
2637 provider: &'a dyn ContextProvider,
2638 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2639 where
2640 RecentNullifierChanges: 'a,
2641 {
2642 use dapi_grpc::platform::v0::get_recent_nullifier_changes_request;
2643
2644 let request: Self::Request = request.into();
2645 let response: Self::Response = response.into();
2646
2647 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2648 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2649
2650 let start_height = match request.version.ok_or(Error::EmptyVersion)? {
2651 get_recent_nullifier_changes_request::Version::V0(v0) => v0.start_height,
2652 };
2653
2654 let limit = Some(100u16); let (root_hash, verified_changes) = Drive::verify_recent_nullifier_changes(
2657 &proof.grovedb_proof,
2658 start_height,
2659 limit,
2660 false,
2661 platform_version,
2662 )
2663 .map_drive_error(proof, mtd)?;
2664
2665 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2666
2667 let result = RecentNullifierChanges(
2668 verified_changes
2669 .into_iter()
2670 .map(|change| BlockNullifierChanges {
2671 block_height: change.block_height,
2672 nullifiers: change.nullifiers.into_inner(),
2673 })
2674 .collect(),
2675 );
2676
2677 Ok((Some(result), mtd.clone(), proof.clone()))
2678 }
2679}
2680
2681impl FromProof<platform::GetRecentCompactedNullifierChangesRequest>
2682 for RecentCompactedNullifierChanges
2683{
2684 type Request = platform::GetRecentCompactedNullifierChangesRequest;
2685 type Response = platform::GetRecentCompactedNullifierChangesResponse;
2686
2687 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2688 request: I,
2689 response: O,
2690 _network: Network,
2691 platform_version: &PlatformVersion,
2692 provider: &'a dyn ContextProvider,
2693 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2694 where
2695 RecentCompactedNullifierChanges: 'a,
2696 {
2697 use dapi_grpc::platform::v0::get_recent_compacted_nullifier_changes_request;
2698
2699 let request: Self::Request = request.into();
2700 let response: Self::Response = response.into();
2701
2702 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2703 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2704
2705 let start_block_height = match request.version.ok_or(Error::EmptyVersion)? {
2706 get_recent_compacted_nullifier_changes_request::Version::V0(v0) => {
2707 v0.start_block_height
2708 }
2709 };
2710
2711 let limit = Some(25u16); let (root_hash, verified_changes) = Drive::verify_compacted_nullifier_changes(
2714 &proof.grovedb_proof,
2715 start_block_height,
2716 limit,
2717 platform_version,
2718 )
2719 .map_drive_error(proof, mtd)?;
2720
2721 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2722
2723 let result = RecentCompactedNullifierChanges(
2724 verified_changes
2725 .into_iter()
2726 .map(|change| CompactedBlockNullifierChanges {
2727 start_block_height: change.start_block,
2728 end_block_height: change.end_block,
2729 nullifiers: change.nullifiers.into_inner(),
2730 })
2731 .collect(),
2732 );
2733
2734 Ok((Some(result), mtd.clone(), proof.clone()))
2735 }
2736}
2737
2738pub trait Length {
2740 fn count_some(&self) -> usize;
2742 fn count(&self) -> usize;
2744}
2745
2746impl<T: Length> Length for Option<T> {
2747 fn count_some(&self) -> usize {
2748 match self {
2749 None => 0,
2750 Some(i) => i.count_some(),
2751 }
2752 }
2753 fn count(&self) -> usize {
2754 match self {
2755 None => 0,
2756 Some(i) => i.count(),
2757 }
2758 }
2759}
2760
2761impl<T> Length for Vec<Option<T>> {
2762 fn count_some(&self) -> usize {
2763 self.iter().filter(|v| v.is_some()).count()
2764 }
2765
2766 fn count(&self) -> usize {
2767 self.len()
2768 }
2769}
2770
2771impl<K, T> Length for Vec<(K, Option<T>)> {
2772 fn count_some(&self) -> usize {
2773 self.iter().filter(|(_, v)| v.is_some()).count()
2774 }
2775
2776 fn count(&self) -> usize {
2777 self.len()
2778 }
2779}
2780
2781impl<K, T> Length for BTreeMap<K, Option<T>> {
2782 fn count_some(&self) -> usize {
2783 self.values().filter(|v| v.is_some()).count()
2784 }
2785
2786 fn count(&self) -> usize {
2787 self.len()
2788 }
2789}
2790
2791impl<K, T> Length for IndexMap<K, Option<T>> {
2792 fn count_some(&self) -> usize {
2793 self.values().filter(|v| v.is_some()).count()
2794 }
2795
2796 fn count(&self) -> usize {
2797 self.len()
2798 }
2799}
2800
2801macro_rules! define_length {
2808 ($object:ty,$some:expr,$counter:expr) => {
2809 impl Length for $object {
2810 fn count_some(&self) -> usize {
2811 #[allow(clippy::redundant_closure_call)]
2812 $some(self)
2813 }
2814
2815 fn count(&self) -> usize {
2816 #[allow(clippy::redundant_closure_call)]
2817 $counter(self)
2818 }
2819 }
2820 };
2821 ($object:ty,$some:expr) => {
2822 define_length!($object, $some, $some);
2823 };
2824 ($object:ty) => {
2825 define_length!($object, |_| 1, |_| 1);
2826 };
2827}
2828
2829define_length!(DataContract);
2830define_length!(DataContractHistory, |d: &DataContractHistory| d.len());
2831define_length!(Document);
2832define_length!(Identity);
2833define_length!(IdentityBalance);
2834define_length!(IdentityBalanceAndRevision);
2835define_length!(
2836 IdentitiesContractKeys,
2837 |x: &IdentitiesContractKeys| x.values().map(|v| v.count_some()).sum(),
2838 |x: &IdentitiesContractKeys| x.len()
2839);
2840define_length!(ContestedResources, |x: &ContestedResources| x.0.len());
2841define_length!(Contenders, |x: &Contenders| x.contenders.len());
2842define_length!(Voters, |x: &Voters| x.0.len());
2843define_length!(
2844 VotePollsGroupedByTimestamp,
2845 |x: &VotePollsGroupedByTimestamp| x.0.iter().map(|v| v.1.len()).sum(),
2846 |x: &VotePollsGroupedByTimestamp| x.0.len()
2847);
2848
2849trait IntoOption
2851where
2852 Self: Sized,
2853{
2854 fn into_option(self) -> Option<Self>;
2860}
2861
2862impl<L: Length> IntoOption for L {
2863 fn into_option(self) -> Option<Self>
2864 where
2865 Self: Sized,
2866 {
2867 if self.count() == 0 {
2868 None
2869 } else {
2870 Some(self)
2871 }
2872 }
2873}
2874
2875#[cfg(test)]
2876mod tests {
2877 use super::*;
2878
2879 #[test]
2880 fn try_u32_to_u16_succeeds_for_valid_values() {
2881 assert_eq!(try_u32_to_u16(0).unwrap(), 0u16);
2882 assert_eq!(try_u32_to_u16(1).unwrap(), 1u16);
2883 assert_eq!(try_u32_to_u16(42).unwrap(), 42u16);
2884 assert_eq!(try_u32_to_u16(u16::MAX as u32).unwrap(), u16::MAX);
2885 }
2886
2887 #[test]
2888 fn try_u32_to_u16_errors_on_overflow() {
2889 let result = try_u32_to_u16(65536);
2893 assert!(
2894 result.is_err(),
2895 "epoch 65536 must not silently truncate to 0"
2896 );
2897
2898 let result = try_u32_to_u16(u32::MAX);
2899 assert!(result.is_err(), "epoch u32::MAX must not silently truncate");
2900
2901 let result = try_u32_to_u16(100_000);
2902 assert!(result.is_err(), "epoch 100000 must not silently truncate");
2903 }
2904
2905 #[test]
2906 fn u32_to_u16_opt_succeeds_for_valid_values() {
2907 assert_eq!(u32_to_u16_opt(0).unwrap(), None);
2908 assert_eq!(u32_to_u16_opt(1).unwrap(), Some(1u16));
2909 assert_eq!(u32_to_u16_opt(u16::MAX as u32).unwrap(), Some(u16::MAX));
2910 }
2911
2912 #[test]
2913 fn u32_to_u16_opt_errors_on_overflow() {
2914 let result = u32_to_u16_opt(65536);
2915 assert!(
2916 result.is_err(),
2917 "value 65536 must not silently truncate to 0"
2918 );
2919
2920 let result = u32_to_u16_opt(u32::MAX);
2921 assert!(result.is_err(), "value u32::MAX must not silently truncate");
2922 }
2923}