1pub mod chained_document;
5pub mod composite_document;
9pub mod contract_groups;
10pub mod contract_moderation;
11pub mod data_contracts_by_range;
12pub mod data_contracts_latest_versions;
13pub mod document_average;
18pub mod document_count;
19pub mod document_having;
24pub mod document_ranked;
29pub mod document_split_average;
33pub mod document_split_count;
34pub mod document_split_sum;
38pub mod document_sum;
42pub mod groups;
43pub mod identity_keys_remaining_budgets;
44pub mod identity_token_balance;
45pub mod token_contract_info;
46pub mod token_direct_purchase;
47pub mod token_info;
48pub mod token_perpetual_distribution_last_claim;
49pub mod token_pre_programmed_distributions;
50pub mod token_status;
51pub mod token_total_supply;
52
53use crate::from_request::TryFromRequest;
54use crate::verify::{
55 document_query_proof_bytes, supported_grovedb_proof_bytes, require_supported_grovedb_proof_bytes, verify_page_drive_proves, verify_tenderdash_proof, verify_tenderdash_signature,
56};
57use crate::{types::*, ContextProvider, DataContractProvider, Error};
58use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::get_evonodes_proposed_epoch_blocks_by_range_request_v0::Start;
59use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0;
60use dapi_grpc::platform::v0::get_identity_by_non_unique_public_key_hash_response::{
61 get_identity_by_non_unique_public_key_hash_response_v0::Result as NonUniqueLookupV0Result,
62 get_identity_by_non_unique_public_key_hash_response_v1::Result as NonUniqueLookupV1Result,
63 Version as NonUniqueLookupVersion,
64};
65use dapi_grpc::platform::v0::get_path_elements_request::GetPathElementsRequestV0;
66use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_request::{
67 self, GetProtocolVersionUpgradeVoteStatusRequestV0,
68};
69use dapi_grpc::platform::v0::security_level_map::KeyKindRequestType as GrpcKeyKind;
70use dapi_grpc::platform::v0::{
71 get_address_info_request, get_addresses_infos_request,
72 get_contested_resource_identity_votes_request, get_data_contract_history_request, get_data_contract_request, get_data_contracts_request, get_document_history_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,
73 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
74};
75use dapi_grpc::platform::{
76 v0::{self as platform, key_request_type, KeyRequestType as GrpcKeyType},
77 VersionedGrpcResponse,
78};
79use dpp::address_funds::PlatformAddress;
80use dpp::block::block_info::BlockInfo;
81use dpp::block::epoch::EpochIndex;
82use dpp::block::extended_epoch_info::ExtendedEpochInfo;
83use dpp::core_subsidy::NetworkCoreSubsidy;
84use dpp::data_contract::accessors::v0::DataContractV0Getters;
85use dpp::dashcore::hashes::Hash;
86use dpp::dashcore::{Network, ProTxHash};
87use dpp::document::{Document, DocumentV0Getters};
88use dpp::fee::Credits;
89use dpp::identity::identities_contract_keys::IdentitiesContractKeys;
90use dpp::identity::Purpose;
91use dpp::platform_value::{self};
92use dpp::prelude::{AddressNonce, DataContract, Identifier, Identity};
93use dpp::serialization::PlatformDeserializableUntrusted;
94use dpp::state_transition::proof_result::StateTransitionProofOutcome;
95use dpp::state_transition::StateTransition;
96use dpp::version::{PlatformVersion, LATEST_VERSION};
97use dpp::voting::votes::Vote;
98use drive::drive::identity::key::fetch::{
99 IdentityKeysRequest, KeyKindRequestType, KeyRequestType, PurposeU8, SecurityLevelU8,
100};
101use drive::drive::Drive;
102use drive::error::proof::ProofError;
103use drive::grovedb::GroveTrunkQueryResult;
104use drive::query::contested_resource_votes_given_by_identity_query::ContestedResourceVotesGivenByIdentityQuery;
105use drive::query::proposer_block_count_query::ProposerQueryType;
106use drive::query::vote_poll_contestant_votes_query::{
107 ContestedDocumentVotePollVotesDriveQuery, ResolvedContestedDocumentVotePollVotesDriveQuery,
108};
109use drive::query::vote_poll_vote_state_query::{
110 ContestedDocumentVotePollDriveQuery, ResolvedContestedDocumentVotePollDriveQuery,
111};
112use drive::query::vote_polls_by_document_type_query::{
113 ResolvedVotePollsByDocumentTypeQuery, VotePollsByDocumentTypeQuery,
114};
115use drive::query::{DriveDocumentQuery, VotePollsByEndDateDriveQuery};
116use indexmap::IndexMap;
117use std::array::TryFromSliceError;
118use std::collections::BTreeMap;
119use std::num::TryFromIntError;
120use crate::error::MapGroveDbError;
121
122pub trait FromProof<Req> {
136 type Request;
138 type Response;
140
141 fn maybe_from_proof<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
158 request: I,
159 response: O,
160 network: Network,
161 platform_version: &PlatformVersion,
162 provider: &'a dyn ContextProvider,
163 ) -> Result<Option<Self>, Error>
164 where
165 Self: Sized + 'a,
166 {
167 Self::maybe_from_proof_with_metadata(request, response, network, platform_version, provider)
168 .map(|maybe_result| maybe_result.0)
169 }
170
171 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
188 request: I,
189 response: O,
190 network: Network,
191 platform_version: &PlatformVersion,
192 provider: &'a dyn ContextProvider,
193 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
194 where
195 Self: Sized + 'a;
196
197 fn check_request(
220 _request: &Self::Request,
221 _platform_version: &PlatformVersion,
222 ) -> Result<(), Error>
223 where
224 Self: Sized,
225 {
226 Ok(())
227 }
228
229 fn from_proof<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
250 request: I,
251 response: O,
252 network: Network,
253 platform_version: &PlatformVersion,
254 provider: &'a dyn ContextProvider,
255 ) -> Result<Self, Error>
256 where
257 Self: Sized + 'a,
258 {
259 Self::maybe_from_proof(request, response, network, platform_version, provider)?
260 .ok_or(Error::NotFound)
261 }
262
263 fn from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
284 request: I,
285 response: O,
286 network: Network,
287 platform_version: &PlatformVersion,
288 provider: &'a dyn ContextProvider,
289 ) -> Result<(Self, ResponseMetadata), Error>
290 where
291 Self: Sized + 'a,
292 {
293 let (main_item, response_metadata, _) = Self::maybe_from_proof_with_metadata(
294 request,
295 response,
296 network,
297 platform_version,
298 provider,
299 )?;
300 Ok((main_item.ok_or(Error::NotFound)?, response_metadata))
301 }
302
303 fn from_proof_with_metadata_and_proof<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
324 request: I,
325 response: O,
326 network: Network,
327 platform_version: &PlatformVersion,
328 provider: &'a dyn ContextProvider,
329 ) -> Result<(Self, ResponseMetadata, Proof), Error>
330 where
331 Self: Sized + 'a,
332 {
333 let (main_item, response_metadata, proof) = Self::maybe_from_proof_with_metadata(
334 request,
335 response,
336 network,
337 platform_version,
338 provider,
339 )?;
340 Ok((main_item.ok_or(Error::NotFound)?, response_metadata, proof))
341 }
342}
343
344impl FromProof<platform::GetIdentityRequest> for Identity {
345 type Request = platform::GetIdentityRequest;
346 type Response = platform::GetIdentityResponse;
347
348 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
349 request: I,
350 response: O,
351 _network: Network,
352 platform_version: &PlatformVersion,
353 provider: &'a dyn ContextProvider,
354 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
355 where
356 Identity: Sized + 'a,
357 {
358 let request: platform::GetIdentityRequest = request.into();
359 let response: Self::Response = response.into();
360
361 let proof = response.proof().or(Err(Error::NoProofInResult))?;
363 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
364
365 let id = match request.version.ok_or(Error::EmptyVersion)? {
366 get_identity_request::Version::V0(v0) => {
367 Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
368 error: e.to_string(),
369 })?
370 }
371 };
372
373 let (root_hash, maybe_identity) = Drive::verify_full_identity_by_identity_id(
375 supported_grovedb_proof_bytes(proof)?,
376 false,
377 id.into_buffer(),
378 platform_version,
379 )
380 .map_drive_error(proof, mtd)?;
381
382 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
383
384 Ok((maybe_identity, mtd.clone(), proof.clone()))
385 }
386}
387
388impl FromProof<platform::GetIdentityByPublicKeyHashRequest> for Identity {
390 type Request = platform::GetIdentityByPublicKeyHashRequest;
391 type Response = platform::GetIdentityByPublicKeyHashResponse;
392
393 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
394 request: I,
395 response: O,
396 _network: Network,
397 platform_version: &PlatformVersion,
398 provider: &'a dyn ContextProvider,
399 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
400 where
401 Identity: 'a,
402 {
403 let request = request.into();
404 let response = response.into();
405 let proof = response.proof().or(Err(Error::NoProofInResult))?;
407
408 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
409
410 let public_key_hash = match request.version.ok_or(Error::EmptyVersion)? {
411 get_identity_by_public_key_hash_request::Version::V0(v0) => {
412 let public_key_hash: [u8; 20] =
413 v0.public_key_hash
414 .try_into()
415 .map_err(|_| Error::DriveError {
416 error: "Invalid public key hash length".to_string(),
417 })?;
418 public_key_hash
419 }
420 };
421
422 let (root_hash, maybe_identity) = Drive::verify_full_identity_by_unique_public_key_hash(
424 supported_grovedb_proof_bytes(proof)?,
425 public_key_hash,
426 platform_version,
427 )
428 .map_drive_error(proof, mtd)?;
429
430 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
431
432 Ok((maybe_identity, mtd.clone(), proof.clone()))
433 }
434}
435
436fn proof_query_platform_version(
450 metadata: &ResponseMetadata,
451) -> Result<&'static PlatformVersion, Error> {
452 if metadata.protocol_version > LATEST_VERSION {
453 return Ok(PlatformVersion::latest());
454 }
455 PlatformVersion::get(metadata.protocol_version).map_err(|_| Error::ResponseDecodeError {
456 error: format!(
457 "unsupported proof query protocol version {}",
458 metadata.protocol_version
459 ),
460 })
461}
462
463impl FromProof<platform::GetIdentityByNonUniquePublicKeyHashRequest> for Identity {
464 type Request = platform::GetIdentityByNonUniquePublicKeyHashRequest;
465 type Response = platform::GetIdentityByNonUniquePublicKeyHashResponse;
466 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
467 request: I,
468 response: O,
469 _network: Network,
470 platform_version: &PlatformVersion,
471 provider: &'a dyn ContextProvider,
472 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
473 where
474 Self: Sized + 'a,
475 {
476 let request = request.into();
477 let response = response.into();
478 let (proof, identity_proof, mtd, answered_with_two_proofs) = match &response.version {
481 Some(NonUniqueLookupVersion::V0(v0)) => {
482 let Some(NonUniqueLookupV0Result::Proof(proved)) = &v0.result else {
483 return Err(Error::NoProofInResult);
484 };
485 (
486 proved
487 .grovedb_identity_public_key_hash_proof
488 .as_ref()
489 .ok_or(Error::NoProofInResult)?,
490 proved.identity_proof_bytes.as_deref(),
491 v0.metadata.as_ref(),
492 true,
493 )
494 }
495 Some(NonUniqueLookupVersion::V1(v1)) => {
496 let Some(NonUniqueLookupV1Result::Proof(proof)) = &v1.result else {
497 return Err(Error::NoProofInResult);
498 };
499 (proof, None, v1.metadata.as_ref(), false)
500 }
501 None => return Err(Error::NoProofInResult),
502 };
503 let mtd = mtd.ok_or(Error::EmptyResponseMetadata)?;
504 let (public_key_hash, start_after, two_proofs_requested) =
505 match request.version.ok_or(Error::EmptyVersion)? {
506 get_identity_by_non_unique_public_key_hash_request::Version::V0(v0) => {
507 (v0.public_key_hash, v0.start_after, true)
508 }
509 get_identity_by_non_unique_public_key_hash_request::Version::V1(v1) => {
510 (v1.public_key_hash, v1.start_after, false)
511 }
512 };
513 let public_key_hash = public_key_hash
514 .try_into()
515 .map_err(|_| Error::RequestError {
516 error: "Invalid public key hash length".to_string(),
517 })?;
518 let after_identity = start_after
519 .map(|a| {
520 a.try_into().map_err(|_| Error::RequestError {
521 error: "Invalid start_after length".to_string(),
522 })
523 })
524 .transpose()?;
525
526 if two_proofs_requested != answered_with_two_proofs {
530 return Err(Error::ResponseDecodeError {
531 error: "non-unique identity response version does not match request version"
532 .to_string(),
533 });
534 }
535
536 let query_platform_version = proof_query_platform_version(mtd)?;
537 let bytes = supported_grovedb_proof_bytes(proof)?;
538 let verified = if answered_with_two_proofs {
539 Drive::verify_full_identity_by_non_unique_public_key_hash_two_proofs(
540 bytes,
541 identity_proof,
542 public_key_hash,
543 after_identity,
544 query_platform_version,
545 platform_version,
546 )
547 } else {
548 Drive::verify_full_identity_by_non_unique_public_key_hash(
549 bytes,
550 public_key_hash,
551 after_identity,
552 query_platform_version,
553 platform_version,
554 )
555 };
556 let (root_hash, maybe_identity) = verified.map_drive_error(proof, mtd)?;
557 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
558 Ok((maybe_identity, mtd.clone(), proof.clone()))
559 }
560}
561
562impl FromProof<platform::GetIdentityKeysRequest> for IdentityPublicKeys {
563 type Request = platform::GetIdentityKeysRequest;
564 type Response = platform::GetIdentityKeysResponse;
565
566 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
567 request: I,
568 response: O,
569 _network: Network,
570 platform_version: &PlatformVersion,
571 provider: &'a dyn ContextProvider,
572 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
573 where
574 IdentityPublicKeys: 'a,
575 {
576 let request: Self::Request = request.into();
577 let response: Self::Response = response.into();
578
579 let proof = response.proof().or(Err(Error::NoProofInResult))?;
581
582 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
583
584 let (request_type, identity_id, limit, offset) =
585 match request.version.ok_or(Error::EmptyVersion)? {
586 get_identity_keys_request::Version::V0(v0) => {
587 let request_type = v0.request_type;
588 let identity_id = Identifier::from_bytes(&v0.identity_id)
589 .map_err(|e| Error::ProtocolError {
590 error: e.to_string(),
591 })?
592 .into_buffer();
593 let limit = v0.limit.map(try_u32_to_u16).transpose()?;
594 let offset = v0.offset.map(try_u32_to_u16).transpose()?;
595 (request_type, identity_id, limit, offset)
596 }
597 };
598
599 let request_type = parse_key_request_type(&request_type)?;
600
601 let key_request = IdentityKeysRequest {
602 identity_id,
603 request_type,
604 limit,
605 offset,
606 };
607
608 tracing::debug!(?identity_id, "checking proof of identity keys");
609
610 let (root_hash, maybe_identity) = Drive::verify_identity_keys_by_identity_id(
612 supported_grovedb_proof_bytes(proof)?,
613 key_request,
614 false,
615 false,
616 false,
617 platform_version,
618 )
619 .map_drive_error(proof, mtd)?;
620
621 let maybe_keys: Option<IdentityPublicKeys> = if let Some(identity) = maybe_identity {
622 if identity.loaded_public_keys.is_empty() {
623 None
624 } else {
625 let mut keys = identity
626 .loaded_public_keys
627 .into_iter()
628 .map(|(k, v)| (k, Some(v.clone())))
629 .collect::<IdentityPublicKeys>();
630
631 let mut not_found = identity
632 .not_found_public_keys
633 .into_iter()
634 .map(|k| (k, None))
635 .collect::<IdentityPublicKeys>();
636
637 keys.append(&mut not_found);
638
639 Some(keys)
640 }
641 } else {
642 None
643 };
644
645 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
646
647 Ok((maybe_keys, mtd.clone(), proof.clone()))
648 }
649}
650
651fn parse_key_request_type(request: &Option<GrpcKeyType>) -> Result<KeyRequestType, Error> {
652 let key_request_type = request
653 .to_owned()
654 .ok_or(Error::RequestError {
655 error: "missing key request type".to_string(),
656 })?
657 .request
658 .ok_or(Error::RequestError {
659 error: "empty request field in key request type".to_string(),
660 })?;
661
662 let request_type = match key_request_type {
663 key_request_type::Request::AllKeys(_) => KeyRequestType::AllKeys,
664 key_request_type::Request::SpecificKeys(specific_keys) => {
665 KeyRequestType::SpecificKeys(specific_keys.key_ids)
666 }
667 key_request_type::Request::SearchKey(search_key) => {
668 let purpose = search_key
669 .purpose_map
670 .iter()
671 .map(|(k, v)| {
672 let v = v.security_level_map
673 .iter()
674 .map(|(level, &kind)| {
675 let kt = match GrpcKeyKind::try_from(kind) {
676 Ok(GrpcKeyKind::CurrentKeyOfKindRequest) => {
677 Ok(KeyKindRequestType::CurrentKeyOfKindRequest)
678 }
679 Ok(GrpcKeyKind::AllKeysOfKindRequest) => {
680 Ok(KeyKindRequestType::AllKeysOfKindRequest)
681 }
682 _ => Err(Error::RequestError {
683 error: format!("missing requested key type: {}", kind),
684 }),
685 };
686 match kt {
687 Err(e) => Err(e),
688 Ok(d) => Ok((*level as u8, d))
689 }
690 })
691 .collect::<Result<BTreeMap<SecurityLevelU8,KeyKindRequestType>,Error>>();
692
693 match v {
694 Err(e) =>Err(e),
695 Ok(d) => Ok((*k as u8,d)),
696 }
697 })
698 .collect::<Result<BTreeMap<PurposeU8, BTreeMap<SecurityLevelU8, KeyKindRequestType>>,Error>>()?;
699
700 KeyRequestType::SearchKey(purpose)
701 }
702 };
703
704 Ok(request_type)
705}
706
707impl FromProof<platform::GetIdentityNonceRequest> for IdentityNonceFetcher {
708 type Request = platform::GetIdentityNonceRequest;
709 type Response = platform::GetIdentityNonceResponse;
710
711 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
712 request: I,
713 response: O,
714 _network: Network,
715 platform_version: &PlatformVersion,
716 provider: &'a dyn ContextProvider,
717 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
718 where
719 IdentityNonceFetcher: 'a,
720 {
721 let request: Self::Request = request.into();
722 let response: Self::Response = response.into();
723
724 let proof = response.proof().or(Err(Error::NoProofInResult))?;
726
727 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
728
729 let identity_id =
730 match request.version.ok_or(Error::EmptyVersion)? {
731 get_identity_nonce_request::Version::V0(v0) => Ok::<Identifier, Error>(
732 Identifier::from_bytes(&v0.identity_id).map_err(|e| Error::ProtocolError {
733 error: e.to_string(),
734 })?,
735 ),
736 }?;
737
738 let (root_hash, maybe_nonce) = Drive::verify_identity_nonce(
740 supported_grovedb_proof_bytes(proof)?,
741 identity_id.into_buffer(),
742 false,
743 platform_version,
744 )
745 .map_drive_error(proof, mtd)?;
746
747 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
748
749 Ok((
750 maybe_nonce.map(IdentityNonceFetcher),
751 mtd.clone(),
752 proof.clone(),
753 ))
754 }
755}
756
757impl FromProof<platform::GetIdentityContractNonceRequest> for IdentityContractNonceFetcher {
758 type Request = platform::GetIdentityContractNonceRequest;
759 type Response = platform::GetIdentityContractNonceResponse;
760
761 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
762 request: I,
763 response: O,
764 _network: Network,
765 platform_version: &PlatformVersion,
766 provider: &'a dyn ContextProvider,
767 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
768 where
769 IdentityContractNonceFetcher: 'a,
770 {
771 let request: Self::Request = request.into();
772 let response: Self::Response = response.into();
773
774 let proof = response.proof().or(Err(Error::NoProofInResult))?;
776
777 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
778
779 let (identity_id, contract_id) = match request.version.ok_or(Error::EmptyVersion)? {
780 get_identity_contract_nonce_request::Version::V0(v0) => {
781 Ok::<(Identifier, Identifier), Error>((
782 Identifier::from_bytes(&v0.identity_id).map_err(|e| Error::ProtocolError {
783 error: e.to_string(),
784 })?,
785 Identifier::from_bytes(&v0.contract_id).map_err(|e| Error::ProtocolError {
786 error: e.to_string(),
787 })?,
788 ))
789 }
790 }?;
791
792 let (root_hash, maybe_identity) = Drive::verify_identity_contract_nonce(
794 supported_grovedb_proof_bytes(proof)?,
795 identity_id.into_buffer(),
796 contract_id.into_buffer(),
797 false,
798 platform_version,
799 )
800 .map_drive_error(proof, mtd)?;
801
802 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
803
804 Ok((
805 maybe_identity.map(IdentityContractNonceFetcher),
806 mtd.clone(),
807 proof.clone(),
808 ))
809 }
810}
811
812impl FromProof<platform::GetIdentityBalanceRequest> for IdentityBalance {
813 type Request = platform::GetIdentityBalanceRequest;
814 type Response = platform::GetIdentityBalanceResponse;
815
816 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
817 request: I,
818 response: O,
819 _network: Network,
820 platform_version: &PlatformVersion,
821 provider: &'a dyn ContextProvider,
822 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
823 where
824 IdentityBalance: 'a,
825 {
826 let request: Self::Request = request.into();
827 let response: Self::Response = response.into();
828
829 let proof = response.proof().or(Err(Error::NoProofInResult))?;
831
832 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
833
834 let id = match request.version.ok_or(Error::EmptyVersion)? {
835 get_identity_balance_request::Version::V0(v0) => Identifier::from_bytes(&v0.id)
836 .map_err(|e| Error::ProtocolError {
837 error: e.to_string(),
838 }),
839 }?;
840
841 let (root_hash, maybe_identity) = Drive::verify_identity_balance_for_identity_id(
843 supported_grovedb_proof_bytes(proof)?,
844 id.into_buffer(),
845 false,
846 platform_version,
847 )
848 .map_drive_error(proof, mtd)?;
849
850 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
851
852 Ok((maybe_identity, mtd.clone(), proof.clone()))
853 }
854}
855
856impl FromProof<platform::GetIdentitiesBalancesRequest> for IdentityBalances {
857 type Request = platform::GetIdentitiesBalancesRequest;
858 type Response = platform::GetIdentitiesBalancesResponse;
859
860 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
861 request: I,
862 response: O,
863 _network: Network,
864 platform_version: &PlatformVersion,
865 provider: &'a dyn ContextProvider,
866 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
867 where
868 IdentityBalances: 'a,
869 {
870 let request: Self::Request = request.into();
871 let response: Self::Response = response.into();
872 let proof = response.proof().or(Err(Error::NoProofInResult))?;
874
875 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
876
877 let identities_ids = match request.version.ok_or(Error::EmptyVersion)? {
878 get_identities_balances_request::Version::V0(v0) => v0.ids,
879 };
880
881 let identity_ids = identities_ids
882 .into_iter()
883 .map(|identity_bytes| {
884 Identifier::from_bytes(&identity_bytes)
885 .map(|identifier| identifier.into_buffer())
886 .map_err(|e| Error::RequestError {
887 error: format!("identities must be all 32 bytes {}", e),
888 })
889 })
890 .collect::<Result<Vec<[u8; 32]>, Error>>()?;
891 let (root_hash, balances) = Drive::verify_identity_balances_for_identity_ids(
892 supported_grovedb_proof_bytes(proof)?,
893 false,
894 &identity_ids,
895 platform_version,
896 )
897 .map_drive_error(proof, mtd)?;
898
899 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
900
901 Ok((Some(balances), mtd.clone(), proof.clone()))
902 }
903}
904
905impl FromProof<platform::GetIdentityBalanceAndRevisionRequest> for IdentityBalanceAndRevision {
906 type Request = platform::GetIdentityBalanceAndRevisionRequest;
907 type Response = platform::GetIdentityBalanceAndRevisionResponse;
908
909 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
910 request: I,
911 response: O,
912 _network: Network,
913 platform_version: &PlatformVersion,
914 provider: &'a dyn ContextProvider,
915 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
916 where
917 IdentityBalanceAndRevision: 'a,
918 {
919 let request: Self::Request = request.into();
920 let response: Self::Response = response.into();
921
922 let proof = response.proof().or(Err(Error::NoProofInResult))?;
924
925 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
926
927 let id = match request.version.ok_or(Error::EmptyVersion)? {
928 get_identity_balance_and_revision_request::Version::V0(v0) => {
929 Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
930 error: e.to_string(),
931 })
932 }
933 }?;
934
935 let (root_hash, maybe_identity) =
937 Drive::verify_identity_balance_and_revision_for_identity_id(
938 supported_grovedb_proof_bytes(proof)?,
939 id.into_buffer(),
940 false,
941 platform_version,
942 )
943 .map_drive_error(proof, mtd)?;
944
945 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
946
947 Ok((maybe_identity, mtd.clone(), proof.clone()))
948 }
949}
950
951impl FromProof<platform::GetAddressInfoRequest> for AddressInfo {
952 type Request = platform::GetAddressInfoRequest;
953 type Response = platform::GetAddressInfoResponse;
954
955 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
956 request: I,
957 response: O,
958 _network: Network,
959 platform_version: &PlatformVersion,
960 provider: &'a dyn ContextProvider,
961 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
962 where
963 AddressInfo: 'a,
964 {
965 let request: Self::Request = request.into();
966 let response: Self::Response = response.into();
967
968 let proof = response.proof().or(Err(Error::NoProofInResult))?;
969 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
970
971 let address = match request.version.ok_or(Error::EmptyVersion)? {
972 get_address_info_request::Version::V0(v0) => PlatformAddress::from_bytes(&v0.address)
973 .map_err(|e| Error::RequestError {
974 error: format!("invalid address: {}", e),
975 })?,
976 };
977
978 let (root_hash, maybe_info) = Drive::verify_address_info(
979 supported_grovedb_proof_bytes(proof)?,
980 &address,
981 false,
982 platform_version,
983 )
984 .map_drive_error(proof, mtd)?;
985
986 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
987
988 let info = maybe_info.map(|(nonce, balance)| AddressInfo {
989 address,
990 nonce,
991 balance,
992 });
993
994 Ok((info, mtd.clone(), proof.clone()))
995 }
996}
997
998impl FromProof<platform::GetAddressesInfosRequest> for AddressInfos {
999 type Request = platform::GetAddressesInfosRequest;
1000 type Response = platform::GetAddressesInfosResponse;
1001
1002 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1003 request: I,
1004 response: O,
1005 _network: Network,
1006 platform_version: &PlatformVersion,
1007 provider: &'a dyn ContextProvider,
1008 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1009 where
1010 AddressInfos: 'a,
1011 {
1012 let request: Self::Request = request.into();
1013 let response: Self::Response = response.into();
1014
1015 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1016 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1017
1018 let addresses_bytes = match request.version.ok_or(Error::EmptyVersion)? {
1019 get_addresses_infos_request::Version::V0(v0) => v0.addresses,
1020 };
1021
1022 let addresses: Vec<PlatformAddress> = addresses_bytes
1023 .into_iter()
1024 .map(|bytes| {
1025 PlatformAddress::from_bytes(&bytes).map_err(|e| Error::RequestError {
1026 error: format!("invalid address: {}", e),
1027 })
1028 })
1029 .collect::<Result<_, _>>()?;
1030
1031 let (root_hash, entries) = Drive::verify_addresses_infos::<
1032 _,
1033 Vec<(PlatformAddress, Option<(AddressNonce, Credits)>)>,
1034 >(
1035 supported_grovedb_proof_bytes(proof)?,
1036 addresses.iter(),
1037 false,
1038 platform_version,
1039 )
1040 .map_drive_error(proof, mtd)?;
1041
1042 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1043
1044 let infos = entries
1045 .into_iter()
1046 .map(|(address, maybe_info)| {
1047 let info = maybe_info.map(|(nonce, balance)| AddressInfo {
1048 address,
1049 nonce,
1050 balance,
1051 });
1052 (address, info)
1053 })
1054 .collect::<AddressInfos>();
1055
1056 Ok((Some(infos), mtd.clone(), proof.clone()))
1057 }
1058}
1059
1060impl FromProof<platform::GetRecentAddressBalanceChangesRequest> for RecentAddressBalanceChanges {
1061 type Request = platform::GetRecentAddressBalanceChangesRequest;
1062 type Response = platform::GetRecentAddressBalanceChangesResponse;
1063
1064 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1065 request: I,
1066 response: O,
1067 _network: Network,
1068 platform_version: &PlatformVersion,
1069 provider: &'a dyn ContextProvider,
1070 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1071 where
1072 RecentAddressBalanceChanges: 'a,
1073 {
1074 use dapi_grpc::platform::v0::get_recent_address_balance_changes_request;
1075
1076 let request: Self::Request = request.into();
1077 let response: Self::Response = response.into();
1078
1079 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1080 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1081
1082 let (start_height, start_height_exclusive) =
1083 match request.version.ok_or(Error::EmptyVersion)? {
1084 get_recent_address_balance_changes_request::Version::V0(v0) => {
1085 (v0.start_height, v0.start_height_exclusive)
1086 }
1087 };
1088
1089 let limit = Some(100u16); let (root_hash, verified_changes) = if start_height_exclusive {
1092 Drive::verify_recent_address_balance_changes_after(
1093 supported_grovedb_proof_bytes(proof)?,
1094 start_height,
1095 limit,
1096 false,
1097 platform_version,
1098 )
1099 .map_drive_error(proof, mtd)?
1100 } else {
1101 Drive::verify_recent_address_balance_changes(
1102 supported_grovedb_proof_bytes(proof)?,
1103 start_height,
1104 limit,
1105 false,
1106 platform_version,
1107 )
1108 .map_drive_error(proof, mtd)?
1109 };
1110
1111 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1112
1113 let result = RecentAddressBalanceChanges(
1114 verified_changes
1115 .into_iter()
1116 .map(|(block_height, changes)| BlockAddressBalanceChanges {
1117 block_height,
1118 changes,
1119 })
1120 .collect(),
1121 );
1122
1123 Ok((Some(result), mtd.clone(), proof.clone()))
1124 }
1125}
1126
1127impl FromProof<platform::GetRecentCompactedAddressBalanceChangesRequest>
1128 for RecentCompactedAddressBalanceChanges
1129{
1130 type Request = platform::GetRecentCompactedAddressBalanceChangesRequest;
1131 type Response = platform::GetRecentCompactedAddressBalanceChangesResponse;
1132
1133 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1134 request: I,
1135 response: O,
1136 _network: Network,
1137 platform_version: &PlatformVersion,
1138 provider: &'a dyn ContextProvider,
1139 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1140 where
1141 RecentCompactedAddressBalanceChanges: 'a,
1142 {
1143 use dapi_grpc::platform::v0::get_recent_compacted_address_balance_changes_request;
1144
1145 let request: Self::Request = request.into();
1146 let response: Self::Response = response.into();
1147
1148 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1149 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1150
1151 let start_block_height = match request.version.ok_or(Error::EmptyVersion)? {
1152 get_recent_compacted_address_balance_changes_request::Version::V0(v0) => {
1153 v0.start_block_height
1154 }
1155 };
1156
1157 let limit = Some(25u16);
1160
1161 if platform_version
1162 .drive
1163 .methods
1164 .verify
1165 .address_funds
1166 .verify_compacted_address_balance_changes
1167 == 0
1168 {
1169 require_supported_grovedb_proof_bytes(&proof.grovedb_proof)?;
1170 }
1171
1172 let (root_hash, verified_changes) = Drive::verify_compacted_address_balance_changes(
1173 &proof.grovedb_proof,
1174 start_block_height,
1175 limit,
1176 platform_version,
1177 )
1178 .map_drive_error(proof, mtd)?;
1179
1180 verify_tenderdash_signature(proof, mtd, &root_hash, provider)?;
1181
1182 let result = RecentCompactedAddressBalanceChanges(
1183 verified_changes
1184 .into_iter()
1185 .map(|(start_block_height, end_block_height, changes)| {
1186 CompactedBlockAddressBalanceChanges {
1187 start_block_height,
1188 end_block_height,
1189 changes,
1190 }
1191 })
1192 .collect(),
1193 );
1194
1195 Ok((Some(result), mtd.clone(), proof.clone()))
1196 }
1197}
1198
1199impl FromProof<platform::GetAddressesTrunkStateRequest> for GroveTrunkQueryResult {
1200 type Request = platform::GetAddressesTrunkStateRequest;
1201 type Response = platform::GetAddressesTrunkStateResponse;
1202
1203 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1204 _request: I,
1205 response: O,
1206 _network: Network,
1207 platform_version: &PlatformVersion,
1208 provider: &'a dyn ContextProvider,
1209 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1210 where
1211 GroveTrunkQueryResult: 'a,
1212 {
1213 let response: Self::Response = response.into();
1214
1215 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1216 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1217
1218 let (root_hash, trunk_result) = Drive::verify_address_funds_trunk_query(
1219 supported_grovedb_proof_bytes(proof)?,
1220 platform_version,
1221 )
1222 .map_drive_error(proof, mtd)?;
1223
1224 verify_tenderdash_signature(proof, mtd, &root_hash, provider)?;
1225
1226 Ok((Some(trunk_result), mtd.clone(), proof.clone()))
1227 }
1228}
1229
1230impl FromProof<platform::GetAddressesTrunkStateRequest> for PlatformAddressTrunkState {
1231 type Request = platform::GetAddressesTrunkStateRequest;
1232 type Response = platform::GetAddressesTrunkStateResponse;
1233
1234 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1235 request: I,
1236 response: O,
1237 network: Network,
1238 platform_version: &PlatformVersion,
1239 provider: &'a dyn ContextProvider,
1240 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1241 where
1242 PlatformAddressTrunkState: 'a,
1243 {
1244 let (result, metadata, proof) = <GroveTrunkQueryResult as FromProof<
1245 platform::GetAddressesTrunkStateRequest,
1246 >>::maybe_from_proof_with_metadata(
1247 request, response, network, platform_version, provider
1248 )?;
1249
1250 Ok((result.map(PlatformAddressTrunkState), metadata, proof))
1251 }
1252}
1253
1254impl FromProof<platform::GetDataContractRequest> for DataContract {
1255 type Request = platform::GetDataContractRequest;
1256 type Response = platform::GetDataContractResponse;
1257
1258 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1259 request: I,
1260 response: O,
1261 _network: Network,
1262 platform_version: &PlatformVersion,
1263 provider: &'a dyn ContextProvider,
1264 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1265 where
1266 DataContract: 'a,
1267 {
1268 let request: Self::Request = request.into();
1269 let response: Self::Response = response.into();
1270
1271 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1273
1274 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1275
1276 let id = match request.version.ok_or(Error::EmptyVersion)? {
1277 get_data_contract_request::Version::V0(v0) => {
1278 Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
1279 error: e.to_string(),
1280 })
1281 }
1282 }?;
1283
1284 let (root_hash, maybe_contract) = Drive::verify_contract(
1286 supported_grovedb_proof_bytes(proof)?,
1287 None,
1288 false,
1289 false,
1290 id.into_buffer(),
1291 platform_version,
1292 )
1293 .map_drive_error(proof, mtd)?;
1294
1295 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1296
1297 Ok((maybe_contract, mtd.clone(), proof.clone()))
1298 }
1299}
1300
1301impl FromProof<platform::GetDataContractRequest> for (DataContract, Vec<u8>) {
1302 type Request = platform::GetDataContractRequest;
1303 type Response = platform::GetDataContractResponse;
1304
1305 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1306 request: I,
1307 response: O,
1308 _network: Network,
1309 platform_version: &PlatformVersion,
1310 provider: &'a dyn ContextProvider,
1311 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1312 where
1313 DataContract: 'a,
1314 {
1315 let request: Self::Request = request.into();
1316 let response: Self::Response = response.into();
1317
1318 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1320
1321 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1322
1323 let id = match request.version.ok_or(Error::EmptyVersion)? {
1324 get_data_contract_request::Version::V0(v0) => {
1325 Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
1326 error: e.to_string(),
1327 })
1328 }
1329 }?;
1330
1331 let (root_hash, maybe_contract) = Drive::verify_contract_return_serialization(
1333 supported_grovedb_proof_bytes(proof)?,
1334 None,
1335 false,
1336 false,
1337 id.into_buffer(),
1338 platform_version,
1339 )
1340 .map_drive_error(proof, mtd)?;
1341
1342 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1343
1344 Ok((maybe_contract, mtd.clone(), proof.clone()))
1345 }
1346}
1347
1348impl FromProof<platform::GetDataContractsRequest> for DataContracts {
1349 type Request = platform::GetDataContractsRequest;
1350 type Response = platform::GetDataContractsResponse;
1351
1352 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1353 request: I,
1354 response: O,
1355 _network: Network,
1356 platform_version: &PlatformVersion,
1357 provider: &'a dyn ContextProvider,
1358 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1359 where
1360 DataContracts: 'a,
1361 {
1362 let request: Self::Request = request.into();
1363 let response: Self::Response = response.into();
1364
1365 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1367
1368 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1369
1370 let ids = match request.version.ok_or(Error::EmptyVersion)? {
1371 get_data_contracts_request::Version::V0(v0) => v0.ids,
1372 };
1373
1374 let ids = ids
1375 .iter()
1376 .map(|id| {
1377 id.clone().try_into().map_err(|_e| Error::RequestError {
1378 error: format!("wrong id size: expected: {}, got: {}", 32, id.len()),
1379 })
1380 })
1381 .collect::<Result<Vec<[u8; 32]>, Error>>()?;
1382
1383 let (root_hash, contracts) = Drive::verify_contracts(
1385 supported_grovedb_proof_bytes(proof)?,
1386 false,
1387 ids.as_slice(),
1388 platform_version,
1389 )
1390 .map_drive_error(proof, mtd)?;
1391
1392 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1393 let contracts = contracts
1394 .into_iter()
1395 .map(|(k, v)| {
1396 Identifier::from_bytes(&k).map(|id| (id, v)).map_err(|e| {
1397 Error::ResultEncodingError {
1398 error: e.to_string(),
1399 }
1400 })
1401 })
1402 .collect::<Result<DataContracts, Error>>()?;
1403
1404 let maybe_contracts = if contracts.is_empty() {
1405 None
1406 } else {
1407 Some(contracts)
1408 };
1409
1410 Ok((maybe_contracts, mtd.clone(), proof.clone()))
1411 }
1412}
1413
1414impl FromProof<platform::GetDataContractHistoryRequest> for DataContractHistory {
1415 type Request = platform::GetDataContractHistoryRequest;
1416 type Response = platform::GetDataContractHistoryResponse;
1417
1418 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1419 request: I,
1420 response: O,
1421 _network: Network,
1422 platform_version: &PlatformVersion,
1423 provider: &'a dyn ContextProvider,
1424 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1425 where
1426 Self: Sized + 'a,
1427 {
1428 let request: Self::Request = request.into();
1429 let response: Self::Response = response.into();
1430
1431 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1433
1434 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1435
1436 let (id, limit, offset, start_at_ms) = match request.version.ok_or(Error::EmptyVersion)? {
1437 get_data_contract_history_request::Version::V0(v0) => {
1438 let id = Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
1439 error: e.to_string(),
1440 })?;
1441 let limit = u32_to_u16_opt(v0.limit.unwrap_or_default())?;
1442 let offset = u32_to_u16_opt(v0.offset.unwrap_or_default())?;
1443 let start_at_ms = v0.start_at_ms;
1444 (id, limit, offset, start_at_ms)
1445 }
1446 };
1447
1448 let (root_hash, maybe_history) = Drive::verify_contract_history(
1450 supported_grovedb_proof_bytes(proof)?,
1451 id.into_buffer(),
1452 start_at_ms,
1453 limit,
1454 offset,
1455 platform_version,
1456 )
1457 .map_drive_error(proof, mtd)?;
1458
1459 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1460
1461 Ok((
1462 maybe_history.map(IndexMap::from_iter),
1463 mtd.clone(),
1464 proof.clone(),
1465 ))
1466 }
1467}
1468
1469impl FromProof<platform::GetDocumentHistoryRequest> for DocumentHistory {
1470 type Request = platform::GetDocumentHistoryRequest;
1471 type Response = platform::GetDocumentHistoryResponse;
1472
1473 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1474 request: I,
1475 response: O,
1476 _network: Network,
1477 platform_version: &PlatformVersion,
1478 provider: &'a dyn ContextProvider,
1479 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1480 where
1481 Self: Sized + 'a,
1482 {
1483 let request: Self::Request = request.into();
1484 let response: Self::Response = response.into();
1485
1486 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1487 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1488
1489 let (contract_id, document_type_name, document_id, limit, offset, start_at_ms) =
1490 match request.version.ok_or(Error::EmptyVersion)? {
1491 get_document_history_request::Version::V0(v0) => {
1492 let contract_id =
1493 Identifier::from_bytes(&v0.data_contract_id).map_err(|e| {
1494 Error::ProtocolError {
1495 error: e.to_string(),
1496 }
1497 })?;
1498 let document_id = Identifier::from_bytes(&v0.document_id).map_err(|e| {
1499 Error::ProtocolError {
1500 error: e.to_string(),
1501 }
1502 })?;
1503 let limit = u32_to_u16_opt(v0.limit.unwrap_or_default())?;
1504 let offset = u32_to_u16_opt(v0.offset.unwrap_or_default())?;
1505 (
1506 contract_id,
1507 v0.document_type_name,
1508 document_id,
1509 limit,
1510 offset,
1511 v0.start_at_ms,
1512 )
1513 }
1514 };
1515
1516 let data_contract = provider
1517 .get_data_contract(&contract_id, platform_version)?
1518 .ok_or(Error::NotFound)?;
1519 let document_type = data_contract
1520 .document_type_for_name(&document_type_name)
1521 .map_err(|e| Error::ProtocolError {
1522 error: e.to_string(),
1523 })?;
1524
1525 let (root_hash, maybe_history) = Drive::verify_document_history(
1526 supported_grovedb_proof_bytes(proof)?,
1527 contract_id.into_buffer(),
1528 &document_type_name,
1529 document_type,
1530 document_id.into_buffer(),
1531 start_at_ms,
1532 limit,
1533 offset,
1534 platform_version,
1535 )
1536 .map_drive_error(proof, mtd)?;
1537
1538 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1539
1540 Ok((
1545 maybe_history.map(IndexMap::from_iter),
1546 mtd.clone(),
1547 proof.clone(),
1548 ))
1549 }
1550}
1551
1552impl FromProof<platform::BroadcastStateTransitionRequest> for StateTransitionProofOutcome {
1553 type Request = platform::BroadcastStateTransitionRequest;
1554 type Response = platform::WaitForStateTransitionResultResponse;
1555
1556 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1557 request: I,
1558 response: O,
1559 _network: Network,
1560 platform_version: &PlatformVersion,
1561 provider: &'a dyn ContextProvider,
1562 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1563 where
1564 Self: Sized + 'a,
1565 {
1566 let request: Self::Request = request.into();
1567 let response: Self::Response = response.into();
1568
1569 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1571
1572 let state_transition = StateTransition::deserialize_from_bytes_untrusted(
1573 &request.state_transition,
1574 )
1575 .map_err(|e| Error::ProtocolError {
1576 error: e.to_string(),
1577 })?;
1578
1579 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1580
1581 let block_info = BlockInfo {
1582 time_ms: mtd.time_ms,
1583 height: mtd.height,
1584 core_height: mtd.core_chain_locked_height,
1585 epoch: Default::default(),
1589 };
1590
1591 let query_platform_version = proof_query_platform_version(mtd)?;
1592
1593 let contracts_provider_fn = provider.as_contract_lookup_fn(platform_version);
1594
1595 let (root_hash, outcome) =
1604 Drive::verify_state_transition_was_executed_with_proof_for_query_version(
1605 &state_transition,
1606 &block_info,
1607 supported_grovedb_proof_bytes(proof)?,
1608 &contracts_provider_fn,
1609 query_platform_version,
1610 platform_version,
1611 )
1612 .map_drive_error(proof, mtd)?;
1613
1614 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1615
1616 Ok((Some(outcome), mtd.clone(), proof.clone()))
1617 }
1618}
1619
1620impl FromProof<platform::GetEpochsInfoRequest> for ExtendedEpochInfo {
1621 type Request = platform::GetEpochsInfoRequest;
1622 type Response = platform::GetEpochsInfoResponse;
1623
1624 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1625 request: I,
1626 response: O,
1627 network: Network,
1628 platform_version: &PlatformVersion,
1629 provider: &'a dyn ContextProvider,
1630 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1631 where
1632 Self: Sized + 'a,
1633 {
1634 let epochs = ExtendedEpochInfos::maybe_from_proof_with_metadata(
1635 request,
1636 response,
1637 network,
1638 platform_version,
1639 provider,
1640 )?;
1641
1642 if let Some(e) = epochs.0 {
1643 if e.len() != 1 {
1644 return Err(Error::RequestError {
1645 error: format!("expected 1 epoch, got {}", e.len()),
1646 });
1647 }
1648 let epoch = e.into_iter().next().and_then(|v| v.1);
1649 Ok((epoch, epochs.1, epochs.2))
1650 } else {
1651 Ok((None, epochs.1, epochs.2))
1652 }
1653 }
1654}
1655
1656impl FromProof<platform::GetEpochsInfoRequest> for ExtendedEpochInfos {
1657 type Request = platform::GetEpochsInfoRequest;
1658 type Response = platform::GetEpochsInfoResponse;
1659
1660 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1661 request: I,
1662 response: O,
1663 _network: Network,
1664 platform_version: &PlatformVersion,
1665 provider: &'a dyn ContextProvider,
1666 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1667 where
1668 Self: Sized + 'a,
1669 {
1670 let request: Self::Request = request.into();
1671 let response: Self::Response = response.into();
1672 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1674
1675 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1676
1677 let (start_epoch, count, ascending) = match request.version.ok_or(Error::EmptyVersion)? {
1678 get_epochs_info_request::Version::V0(v0) => (v0.start_epoch, v0.count, v0.ascending),
1679 };
1680
1681 let start_epoch: Option<EpochIndex> = if let Some(epoch) = start_epoch {
1682 Some(try_u32_to_u16(epoch)?)
1683 } else {
1684 None
1685 };
1686 if start_epoch.is_none() && !ascending {
1687 return Err(Error::RequestError {
1688 error: "proved descending epoch queries require an explicit start epoch"
1689 .to_string(),
1690 });
1691 }
1692 let current_epoch: EpochIndex = 0;
1695 let count = try_u32_to_u16(count)?;
1696
1697 let (root_hash, epoch_info) = Drive::verify_epoch_infos(
1698 supported_grovedb_proof_bytes(proof)?,
1699 current_epoch,
1700 start_epoch,
1701 count,
1702 ascending,
1703 platform_version,
1704 )
1705 .map_drive_error(proof, mtd)?;
1706
1707 let epoch_info = epoch_info
1708 .into_iter()
1709 .map(|v| {
1710 #[allow(clippy::infallible_destructuring_match)]
1711 let info = match &v {
1712 ExtendedEpochInfo::V0(i) => i,
1713 };
1714
1715 (info.index, Some(v))
1716 })
1717 .collect::<ExtendedEpochInfos>();
1718
1719 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1720
1721 Ok((epoch_info.into_option(), mtd.clone(), proof.clone()))
1722 }
1723}
1724
1725impl FromProof<platform::GetFinalizedEpochInfosRequest> for FinalizedEpochInfos {
1726 type Request = platform::GetFinalizedEpochInfosRequest;
1727 type Response = platform::GetFinalizedEpochInfosResponse;
1728
1729 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1730 request: I,
1731 response: O,
1732 _network: Network,
1733 platform_version: &PlatformVersion,
1734 provider: &'a dyn ContextProvider,
1735 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1736 where
1737 Self: Sized + 'a,
1738 {
1739 let request: Self::Request = request.into();
1740 let response: Self::Response = response.into();
1741 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1743
1744 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1745
1746 let (
1747 start_epoch_index,
1748 start_epoch_index_included,
1749 end_epoch_index,
1750 end_epoch_index_included,
1751 ) = match request.version.ok_or(Error::EmptyVersion)? {
1752 get_finalized_epoch_infos_request::Version::V0(v0) => (
1753 v0.start_epoch_index,
1754 v0.start_epoch_index_included,
1755 v0.end_epoch_index,
1756 v0.end_epoch_index_included,
1757 ),
1758 };
1759
1760 let start_epoch_index: EpochIndex = try_u32_to_u16(start_epoch_index)?;
1761 let end_epoch_index: EpochIndex = try_u32_to_u16(end_epoch_index)?;
1762
1763 let (root_hash, epoch_info) = Drive::verify_finalized_epoch_infos(
1764 supported_grovedb_proof_bytes(proof)?,
1765 start_epoch_index,
1766 start_epoch_index_included,
1767 end_epoch_index,
1768 end_epoch_index_included,
1769 platform_version,
1770 )
1771 .map_drive_error(proof, mtd)?;
1772
1773 let epoch_info = epoch_info
1774 .into_iter()
1775 .map(|(epoch_index, finalized_epoch_info)| (epoch_index, Some(finalized_epoch_info)))
1776 .collect::<FinalizedEpochInfos>();
1777
1778 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1779
1780 Ok((epoch_info.into_option(), mtd.clone(), proof.clone()))
1781 }
1782}
1783
1784fn try_u32_to_u16(i: u32) -> Result<u16, Error> {
1785 i.try_into()
1786 .map_err(|e: TryFromIntError| Error::RequestError {
1787 error: e.to_string(),
1788 })
1789}
1790
1791impl FromProof<GetProtocolVersionUpgradeStateRequest> for ProtocolVersionUpgrades {
1792 type Request = GetProtocolVersionUpgradeStateRequest;
1793 type Response = GetProtocolVersionUpgradeStateResponse;
1794
1795 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1796 _request: I,
1797 response: O,
1798 _network: Network,
1799 platform_version: &PlatformVersion,
1800 provider: &'a dyn ContextProvider,
1801 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1802 where
1803 Self: Sized + 'a,
1804 {
1805 let response: Self::Response = response.into();
1806 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1808 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1809
1810 let (root_hash, objects) =
1811 Drive::verify_upgrade_state(supported_grovedb_proof_bytes(proof)?, platform_version)
1812 .map_drive_error(proof, mtd)?;
1813
1814 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1815
1816 let response: Self = objects.into_iter().map(|(k, v)| (k, Some(v))).collect();
1818
1819 Ok((response.into_option(), mtd.clone(), proof.clone()))
1820 }
1821}
1822
1823impl FromProof<GetProtocolVersionUpgradeVoteStatusRequest> for MasternodeProtocolVotes {
1824 type Request = GetProtocolVersionUpgradeVoteStatusRequest;
1825 type Response = GetProtocolVersionUpgradeVoteStatusResponse;
1826
1827 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1828 request: I,
1829 response: O,
1830 _network: Network,
1831 platform_version: &PlatformVersion,
1832 provider: &'a dyn ContextProvider,
1833 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1834 where
1835 Self: Sized + 'a,
1836 {
1837 let request = request.into();
1838 let response: Self::Response = response.into();
1839 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1841 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1842
1843 let request_v0: GetProtocolVersionUpgradeVoteStatusRequestV0 = match request.version {
1844 Some(get_protocol_version_upgrade_vote_status_request::Version::V0(v0)) => v0,
1845 None => return Err(Error::EmptyVersion),
1846 };
1847
1848 let start_pro_tx_hash: Option<[u8; 32]> =
1849 if request_v0.start_pro_tx_hash.is_empty() {
1850 None
1851 } else {
1852 Some(request_v0.start_pro_tx_hash[..].try_into().map_err(
1853 |e: TryFromSliceError| Error::RequestError {
1854 error: e.to_string(),
1855 },
1856 )?)
1857 };
1858 let count = try_u32_to_u16(request_v0.count)?;
1859
1860 let (root_hash, objects) = Drive::verify_upgrade_vote_status(
1861 supported_grovedb_proof_bytes(proof)?,
1862 start_pro_tx_hash,
1863 count,
1864 platform_version,
1865 )
1866 .map_drive_error(proof, mtd)?;
1867
1868 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1869
1870 if objects.is_empty() {
1871 return Ok((None, mtd.clone(), proof.clone()));
1872 }
1873 let votes: MasternodeProtocolVotes = objects
1874 .into_iter()
1875 .map(|(key, value)| {
1876 ProTxHash::from_slice(&key)
1877 .map(|pro_tx_hash| {
1878 (
1879 pro_tx_hash,
1880 Some(MasternodeProtocolVote {
1881 pro_tx_hash,
1882 voted_version: value,
1883 }),
1884 )
1885 })
1886 .map_err(|e| Error::ResultEncodingError {
1887 error: e.to_string(),
1888 })
1889 })
1890 .collect::<Result<MasternodeProtocolVotes, Error>>()?;
1891
1892 Ok((votes.into_option(), mtd.clone(), proof.clone()))
1893 }
1894}
1895
1896impl FromProof<GetPathElementsRequest> for Elements {
1897 type Request = GetPathElementsRequest;
1898 type Response = GetPathElementsResponse;
1899
1900 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1901 request: I,
1902 response: O,
1903 _network: Network,
1904 platform_version: &PlatformVersion,
1905 provider: &'a dyn ContextProvider,
1906 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1907 where
1908 Self: Sized + 'a,
1909 {
1910 let request = request.into();
1911 let response: Self::Response = response.into();
1912 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1914 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1915
1916 let request_v0: GetPathElementsRequestV0 = match request.version {
1917 Some(get_path_elements_request::Version::V0(v0)) => v0,
1918 None => return Err(Error::EmptyVersion),
1919 };
1920
1921 let path = request_v0.path;
1922 let keys = request_v0.keys;
1923
1924 let (root_hash, objects) = Drive::verify_elements(
1925 supported_grovedb_proof_bytes(proof)?,
1926 path,
1927 keys,
1928 platform_version,
1929 )?;
1930 let elements: Elements = Elements::from_iter(objects);
1931
1932 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1933
1934 Ok((elements.into_option(), mtd.clone(), proof.clone()))
1935 }
1936}
1937
1938impl<'dq, Q> FromProof<Q> for Documents
1939where
1940 Q: TryInto<DriveDocumentQuery<'dq>> + Clone + 'dq,
1941 Q::Error: std::fmt::Display,
1942{
1943 type Request = Q;
1944 type Response = platform::GetDocumentsResponse;
1945
1946 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1947 request: I,
1948 response: O,
1949 _network: Network,
1950 platform_version: &PlatformVersion,
1951 provider: &'a dyn ContextProvider,
1952 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1953 where
1954 Self: 'a,
1955 {
1956 let request: Self::Request = request.into();
1957 let response: Self::Response = response.into();
1958
1959 let request: DriveDocumentQuery<'dq> =
1960 request
1961 .clone()
1962 .try_into()
1963 .map_err(|e: Q::Error| Error::RequestError {
1964 error: e.to_string(),
1965 })?;
1966
1967 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1969
1970 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1971
1972 let (root_hash, documents) = request
1973 .verify_proof(
1974 document_query_proof_bytes(proof, mtd, platform_version)?,
1975 platform_version,
1976 )
1977 .map_drive_error(proof, mtd)?;
1978
1979 let documents = documents
1980 .into_iter()
1981 .map(|d| (d.id(), Some(d)))
1982 .collect::<Documents>();
1983
1984 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1985
1986 Ok((documents.into_option(), mtd.clone(), proof.clone()))
1987 }
1988}
1989
1990impl FromProof<platform::GetIdentitiesContractKeysRequest> for IdentitiesContractKeys {
1991 type Request = platform::GetIdentitiesContractKeysRequest;
1992 type Response = platform::GetIdentitiesContractKeysResponse;
1993
1994 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1995 request: I,
1996 response: O,
1997 _network: Network,
1998 platform_version: &PlatformVersion,
1999 provider: &'a dyn ContextProvider,
2000 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2001 where
2002 Self: 'a,
2003 {
2004 let request: Self::Request = request.into();
2005 let response: Self::Response = response.into();
2006
2007 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2009
2010 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2011
2012 let (identities_ids, contract_id, document_type_name, purposes) =
2013 match request.version.ok_or(Error::EmptyVersion)? {
2014 get_identities_contract_keys_request::Version::V0(v0) => {
2015 let GetIdentitiesContractKeysRequestV0 {
2016 identities_ids,
2017 contract_id,
2018 document_type_name,
2019 purposes,
2020 ..
2021 } = v0;
2022 let identifiers = identities_ids
2023 .into_iter()
2024 .map(|identity_id_vec| {
2025 let identifier = Identifier::from_vec(identity_id_vec)?;
2026 Ok(identifier.to_buffer())
2027 })
2028 .collect::<Result<Vec<[u8; 32]>, platform_value::Error>>()
2029 .map_err(|e| Error::ProtocolError {
2030 error: e.to_string(),
2031 })?;
2032 let contract_id = Identifier::from_vec(contract_id)
2033 .map_err(|e| Error::ProtocolError {
2034 error: e.to_string(),
2035 })?
2036 .into_buffer();
2037 let purposes = purposes
2038 .into_iter()
2039 .map(|purpose| {
2040 Purpose::try_from(purpose).map_err(|e| Error::ProtocolError {
2041 error: e.to_string(),
2042 })
2043 })
2044 .collect::<Result<Vec<Purpose>, Error>>()?;
2045 (identifiers, contract_id, document_type_name, purposes)
2046 }
2047 };
2048
2049 let (root_hash, identities_contract_keys) = Drive::verify_identities_contract_keys(
2051 supported_grovedb_proof_bytes(proof)?,
2052 identities_ids.as_slice(),
2053 &contract_id,
2054 document_type_name,
2055 purposes,
2056 false,
2057 platform_version,
2058 )
2059 .map_drive_error(proof, mtd)?;
2060
2061 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2062
2063 if identities_contract_keys.is_empty() {
2064 return Ok((None, mtd.clone(), proof.clone()));
2065 }
2066
2067 Ok((Some(identities_contract_keys), mtd.clone(), proof.clone()))
2068 }
2069}
2070
2071impl FromProof<platform::GetContestedResourcesRequest> for ContestedResources {
2072 type Request = platform::GetContestedResourcesRequest;
2073 type Response = platform::GetContestedResourcesResponse;
2074
2075 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2076 request: I,
2077 response: O,
2078 _network: Network,
2079 platform_version: &PlatformVersion,
2080 provider: &'a dyn ContextProvider,
2081 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2082 where
2083 Self: Sized + 'a,
2084 {
2085 let request: Self::Request = request.into();
2086 let response: Self::Response = response.into();
2087
2088 let drive_query = VotePollsByDocumentTypeQuery::try_from_request(request)?;
2090 let resolved_request = drive_query.resolve_with_known_contracts_provider(
2091 &provider.as_contract_lookup_fn(platform_version),
2092 )?;
2093
2094 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2096 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2097 let grovedb_proof = supported_grovedb_proof_bytes(proof)?;
2098
2099 let (root_hash, items) = verify_page_drive_proves(resolved_request.limit, |limit| {
2100 ResolvedVotePollsByDocumentTypeQuery {
2101 limit,
2102 ..resolved_request.clone()
2103 }
2104 .verify_contests_proof(grovedb_proof, platform_version)
2105 })
2106 .map_drive_error(proof, mtd)?;
2107
2108 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2109
2110 let resources: ContestedResources = items.into_iter().map(ContestedResource).collect();
2111
2112 Ok((resources.into_option(), mtd.clone(), proof.clone()))
2113 }
2114}
2115
2116impl FromProof<platform::GetContestedResourceVoteStateRequest> for Contenders {
2118 type Request = platform::GetContestedResourceVoteStateRequest;
2119 type Response = platform::GetContestedResourceVoteStateResponse;
2120
2121 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2122 request: I,
2123 response: O,
2124 _network: Network,
2125 platform_version: &PlatformVersion,
2126 provider: &'a dyn ContextProvider,
2127 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2128 where
2129 Self: 'a,
2130 {
2131 let request: Self::Request = request.into();
2132 let response: Self::Response = response.into();
2133
2134 let drive_query = ContestedDocumentVotePollDriveQuery::try_from_request(request)?;
2136
2137 let contracts_provider = provider.as_contract_lookup_fn(platform_version);
2139 let resolved_request =
2140 drive_query.resolve_with_known_contracts_provider(&contracts_provider)?;
2141
2142 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2144 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2145 let grovedb_proof = supported_grovedb_proof_bytes(proof)?;
2146
2147 let (root_hash, contested_resource_vote_state) =
2148 verify_page_drive_proves(resolved_request.limit, |limit| {
2149 ResolvedContestedDocumentVotePollDriveQuery {
2150 limit,
2151 ..resolved_request.clone()
2152 }
2153 .verify_vote_poll_vote_state_proof(grovedb_proof, platform_version)
2154 })
2155 .map_drive_error(proof, mtd)?;
2156
2157 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2158
2159 let contenders = contested_resource_vote_state
2160 .contenders
2161 .into_iter()
2162 .map(|v| (v.identity_id(), v))
2163 .collect();
2164
2165 let response = Contenders {
2166 winner: contested_resource_vote_state.winner,
2167 contenders,
2168 abstain_vote_tally: contested_resource_vote_state.abstaining_vote_tally,
2169 lock_vote_tally: contested_resource_vote_state.locked_vote_tally,
2170 };
2171 Ok((response.into_option(), mtd.clone(), proof.clone()))
2172 }
2173}
2174
2175impl FromProof<GetContestedResourceVotersForIdentityRequest> for Voters {
2176 type Request = GetContestedResourceVotersForIdentityRequest;
2177 type Response = GetContestedResourceVotersForIdentityResponse;
2178
2179 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2180 request: I,
2181 response: O,
2182 _network: Network,
2183 platform_version: &PlatformVersion,
2184 provider: &'a dyn ContextProvider,
2185 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2186 where
2187 Self: Sized + 'a,
2188 {
2189 let request: Self::Request = request.into();
2190 let response: Self::Response = response.into();
2191
2192 let drive_query = ContestedDocumentVotePollVotesDriveQuery::try_from_request(request)?;
2194
2195 let contracts_provider = provider.as_contract_lookup_fn(platform_version);
2197
2198 let resolved_request =
2199 drive_query.resolve_with_known_contracts_provider(&contracts_provider)?;
2200
2201 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2203 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2204 let grovedb_proof = supported_grovedb_proof_bytes(proof)?;
2205
2206 let (root_hash, voters) = verify_page_drive_proves(resolved_request.limit, |limit| {
2207 ResolvedContestedDocumentVotePollVotesDriveQuery {
2208 limit,
2209 ..resolved_request.clone()
2210 }
2211 .verify_vote_poll_votes_proof(grovedb_proof, platform_version)
2212 })
2213 .map_drive_error(proof, mtd)?;
2214
2215 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2216
2217 if voters.is_empty() {
2218 return Ok((None, mtd.clone(), proof.clone()));
2219 }
2220 let result: Voters = voters.into_iter().map(Voter::from).collect();
2221
2222 Ok((result.into_option(), mtd.clone(), proof.clone()))
2223 }
2224}
2225
2226impl FromProof<platform::GetContestedResourceIdentityVotesRequest> for ResourceVotesByIdentity {
2227 type Request = platform::GetContestedResourceIdentityVotesRequest;
2228 type Response = platform::GetContestedResourceIdentityVotesResponse;
2229
2230 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2231 request: I,
2232 response: O,
2233 _network: Network,
2234 platform_version: &PlatformVersion,
2235 provider: &'a dyn ContextProvider,
2236 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2237 where
2238 Self: Sized + 'a,
2239 {
2240 let request: Self::Request = request.into();
2241 let response: Self::Response = response.into();
2242
2243 let drive_query = ContestedResourceVotesGivenByIdentityQuery::try_from_request(request)?;
2245
2246 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2248 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2249
2250 let grovedb_proof = supported_grovedb_proof_bytes(proof)?;
2251
2252 let contract_provider_fn = provider.as_contract_lookup_fn(platform_version);
2253 let (root_hash, voters) = verify_page_drive_proves(drive_query.limit, |limit| {
2254 ContestedResourceVotesGivenByIdentityQuery {
2255 limit,
2256 ..drive_query.clone()
2257 }
2258 .verify_identity_votes_given_proof::<Vec<_>>(
2259 grovedb_proof,
2260 &contract_provider_fn,
2261 platform_version,
2262 )
2263 })
2264 .map_drive_error(proof, mtd)?;
2265
2266 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2267
2268 let response: ResourceVotesByIdentity = voters
2269 .into_iter()
2270 .map(|(id, vote)| (id, Some(vote)))
2271 .collect();
2272
2273 Ok((response.into_option(), mtd.clone(), proof.clone()))
2274 }
2275}
2276
2277impl FromProof<platform::GetVotePollsByEndDateRequest> for VotePollsGroupedByTimestamp {
2278 type Request = platform::GetVotePollsByEndDateRequest;
2279 type Response = platform::GetVotePollsByEndDateResponse;
2280
2281 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2282 request: I,
2283 response: O,
2284 _network: Network,
2285 platform_version: &PlatformVersion,
2286 provider: &'a dyn ContextProvider,
2287 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2288 where
2289 Self: Sized + 'a,
2290 {
2291 let request: Self::Request = request.into();
2292 let response: Self::Response = response.into();
2293
2294 let drive_query = VotePollsByEndDateDriveQuery::try_from_request(request)?;
2296
2297 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2299 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2300
2301 let grovedb_proof = supported_grovedb_proof_bytes(proof)?;
2302
2303 let (root_hash, vote_polls) = verify_page_drive_proves(drive_query.limit, |limit| {
2304 VotePollsByEndDateDriveQuery {
2305 limit,
2306 ..drive_query.clone()
2307 }
2308 .verify_vote_polls_by_end_date_proof::<Vec<(_, _)>>(grovedb_proof, platform_version)
2309 })
2310 .map_drive_error(proof, mtd)?;
2311
2312 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2313
2314 let response = VotePollsGroupedByTimestamp(vote_polls).sorted(drive_query.order_ascending);
2315
2316 Ok((response.into_option(), mtd.clone(), proof.clone()))
2317 }
2318}
2319
2320impl FromProof<platform::GetPrefundedSpecializedBalanceRequest> for PrefundedSpecializedBalance {
2321 type Request = platform::GetPrefundedSpecializedBalanceRequest;
2322 type Response = platform::GetPrefundedSpecializedBalanceResponse;
2323
2324 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2325 request: I,
2326 response: O,
2327 _network: Network,
2328 platform_version: &PlatformVersion,
2329 provider: &'a dyn ContextProvider,
2330 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2331 where
2332 Self: Sized + 'a,
2333 {
2334 let request: Self::Request = request.into();
2335 let response: Self::Response = response.into();
2336
2337 let balance_id = match request.version.ok_or(Error::EmptyVersion)? {
2338 get_prefunded_specialized_balance_request::Version::V0(v0) => {
2339 Identifier::from_vec(v0.id).map_err(|e| Error::RequestError {
2340 error: e.to_string(),
2341 })?
2342 }
2343 };
2344
2345 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2346
2347 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2348
2349 let (root_hash, balance) = Drive::verify_specialized_balance(
2350 supported_grovedb_proof_bytes(proof)?,
2351 balance_id.into_buffer(),
2352 false,
2353 platform_version,
2354 )
2355 .map_drive_error(proof, mtd)?;
2356
2357 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2358
2359 Ok((balance.map(|v| v.into()), mtd.clone(), proof.clone()))
2360 }
2361}
2362
2363fn requested_vote_poll_id(
2368 request: &platform::GetContestedResourceIdentityVotesRequest,
2369) -> Result<Identifier, Error> {
2370 match request.version.as_ref().ok_or(Error::EmptyVersion)? {
2371 get_contested_resource_identity_votes_request::Version::V0(v0) => {
2372 match &v0.start_at_vote_poll_id_info {
2373 Some(start) if start.start_poll_identifier_included => {
2374 Identifier::from_bytes(&start.start_at_poll_identifier).map_err(|e| {
2375 Error::RequestError {
2376 error: e.to_string(),
2377 }
2378 })
2379 }
2380 _ => Err(Error::RequestError {
2381 error: "a vote request must start at the vote poll of the vote, including it"
2382 .to_string(),
2383 }),
2384 }
2385 }
2386 }
2387}
2388
2389impl FromProof<platform::GetContestedResourceIdentityVotesRequest> for Vote {
2390 type Request = platform::GetContestedResourceIdentityVotesRequest;
2391 type Response = platform::GetContestedResourceIdentityVotesResponse;
2392
2393 fn check_request(
2394 request: &Self::Request,
2395 _platform_version: &PlatformVersion,
2396 ) -> Result<(), Error> {
2397 requested_vote_poll_id(request).map(|_| ())
2398 }
2399
2400 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2401 request: I,
2402 response: O,
2403 network: Network,
2404 platform_version: &PlatformVersion,
2405 provider: &'a dyn ContextProvider,
2406 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2407 where
2408 Self: Sized + 'a,
2409 {
2410 let request = request.into();
2411 let vote_poll_id = requested_vote_poll_id(&request)?;
2412
2413 let (maybe_votes, mtd, proof) = ResourceVotesByIdentity::maybe_from_proof_with_metadata(
2414 request,
2415 response,
2416 network,
2417 platform_version,
2418 provider,
2419 )?;
2420
2421 let vote = maybe_votes
2425 .and_then(|mut votes| votes.shift_remove(&vote_poll_id))
2426 .flatten()
2427 .map(Vote::ResourceVote);
2428
2429 Ok((vote, mtd, proof))
2430 }
2431}
2432
2433impl FromProof<platform::GetTotalCreditsInPlatformRequest> for TotalCreditsInPlatform {
2434 type Request = platform::GetTotalCreditsInPlatformRequest;
2435 type Response = platform::GetTotalCreditsInPlatformResponse;
2436
2437 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2438 _request: I,
2439 response: O,
2440 network: Network,
2441 platform_version: &PlatformVersion,
2442 provider: &'a dyn ContextProvider,
2443 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2444 where
2445 Self: Sized + 'a,
2446 {
2447 let response: Self::Response = response.into();
2448 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2450 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2451
2452 let core_subsidy_halving_interval = network.core_subsidy_halving_interval();
2453
2454 let (root_hash, credits) = Drive::verify_total_credits_in_system(
2455 supported_grovedb_proof_bytes(proof)?,
2456 core_subsidy_halving_interval,
2457 || {
2458 provider.get_platform_activation_height().map_err(|e| {
2459 drive::error::Error::Proof(ProofError::MissingContextRequirement(e.to_string()))
2460 })
2461 },
2462 mtd.core_chain_locked_height,
2463 platform_version,
2464 )
2465 .map_drive_error(proof, mtd)?;
2466
2467 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2468
2469 Ok((
2470 Some(TotalCreditsInPlatform(credits)),
2471 mtd.clone(),
2472 proof.clone(),
2473 ))
2474 }
2475}
2476impl FromProof<platform::GetEvonodesProposedEpochBlocksByIdsRequest> for ProposerBlockCounts {
2477 type Request = platform::GetEvonodesProposedEpochBlocksByIdsRequest;
2478 type Response = platform::GetEvonodesProposedEpochBlocksResponse;
2479
2480 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2481 request: I,
2482 response: O,
2483 _network: Network,
2484 platform_version: &PlatformVersion,
2485 provider: &'a dyn ContextProvider,
2486 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2487 where
2488 Self: Sized + 'a,
2489 {
2490 let request: Self::Request = request.into();
2491 let response: Self::Response = response.into();
2492 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2494 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2495
2496 let (ids, epoch) = match request.version.ok_or(Error::EmptyVersion)? {
2497 get_evonodes_proposed_epoch_blocks_by_ids_request::Version::V0(v0) => {
2498 (v0.ids, v0.epoch)
2499 }
2500 };
2501
2502 let epoch_index = match epoch {
2503 Some(index) => try_u32_to_u16(index)?,
2504 None => {
2505 return Err(Error::RequestError {
2506 error: "proved proposer queries require an explicit epoch".to_string(),
2507 })
2508 }
2509 };
2510
2511 let (root_hash, proposer_block_counts) = Drive::verify_epoch_proposers(
2512 supported_grovedb_proof_bytes(proof)?,
2513 epoch_index,
2514 ProposerQueryType::ByIds(ids),
2515 platform_version,
2516 )
2517 .map_drive_error(proof, mtd)?;
2518
2519 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2520
2521 Ok((
2522 Some(ProposerBlockCounts(proposer_block_counts)),
2523 mtd.clone(),
2524 proof.clone(),
2525 ))
2526 }
2527}
2528
2529impl FromProof<platform::GetEvonodesProposedEpochBlocksByRangeRequest> for ProposerBlockCounts {
2530 type Request = platform::GetEvonodesProposedEpochBlocksByRangeRequest;
2531 type Response = platform::GetEvonodesProposedEpochBlocksResponse;
2532
2533 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2534 request: I,
2535 response: O,
2536 _network: Network,
2537 platform_version: &PlatformVersion,
2538 provider: &'a dyn ContextProvider,
2539 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2540 where
2541 Self: Sized + 'a,
2542 {
2543 let request: Self::Request = request.into();
2544 let response: Self::Response = response.into();
2545 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2547 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2548
2549 let (epoch, limit, start) = match request.version.ok_or(Error::EmptyVersion)? {
2550 get_evonodes_proposed_epoch_blocks_by_range_request::Version::V0(v0) => {
2551 (v0.epoch, v0.limit, v0.start)
2552 }
2553 };
2554
2555 let formatted_start = match start {
2556 None => None,
2557 Some(Start::StartAfter(after)) => {
2558 let id: [u8; 32] = after.try_into().map_err(|_| Error::DriveError {
2559 error: "Invalid public key hash length".to_string(),
2560 })?;
2561 Some((id, false))
2562 }
2563 Some(Start::StartAt(at)) => {
2564 let id: [u8; 32] = at.try_into().map_err(|_| Error::DriveError {
2565 error: "Invalid public key hash length".to_string(),
2566 })?;
2567 Some((id, true))
2568 }
2569 };
2570
2571 let epoch_index = match epoch {
2572 Some(index) => try_u32_to_u16(index)?,
2573 None => {
2574 return Err(Error::RequestError {
2575 error: "proved proposer queries require an explicit epoch".to_string(),
2576 })
2577 }
2578 };
2579 let checked_limit = limit.map(try_u32_to_u16).transpose()?;
2580 let grovedb_proof = supported_grovedb_proof_bytes(proof)?;
2581
2582 let (root_hash, proposer_block_counts) = verify_page_drive_proves(checked_limit, |limit| {
2583 Drive::verify_epoch_proposers(
2584 grovedb_proof,
2585 epoch_index,
2586 ProposerQueryType::ByRange(limit, formatted_start),
2587 platform_version,
2588 )
2589 })
2590 .map_drive_error(proof, mtd)?;
2591
2592 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2593
2594 Ok((
2595 Some(ProposerBlockCounts(proposer_block_counts)),
2596 mtd.clone(),
2597 proof.clone(),
2598 ))
2599 }
2600}
2601
2602fn u32_to_u16_opt(i: u32) -> Result<Option<u16>, Error> {
2605 let i: Option<u16> = if i != 0 {
2606 let i: u16 = i
2607 .try_into()
2608 .map_err(|e: TryFromIntError| Error::RequestError {
2609 error: format!("value {} out of range: {}", i, e),
2610 })?;
2611 Some(i)
2612 } else {
2613 None
2614 };
2615
2616 Ok(i)
2617}
2618
2619fn shielded_pool_token_id(token_id: Option<Vec<u8>>) -> Result<Option<[u8; 32]>, Error> {
2625 token_id
2626 .map(|token_id| {
2627 token_id
2628 .try_into()
2629 .map_err(|token_id: Vec<u8>| Error::RequestError {
2630 error: format!("token_id must be 32 bytes, got {}", token_id.len()),
2631 })
2632 })
2633 .transpose()
2634}
2635
2636impl FromProof<platform::GetShieldedPoolStateRequest> for ShieldedPoolState {
2637 type Request = platform::GetShieldedPoolStateRequest;
2638 type Response = platform::GetShieldedPoolStateResponse;
2639
2640 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2641 request: I,
2642 response: O,
2643 _network: Network,
2644 platform_version: &PlatformVersion,
2645 provider: &'a dyn ContextProvider,
2646 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2647 where
2648 Self: Sized + 'a,
2649 {
2650 use dapi_grpc::platform::v0::get_shielded_pool_state_request;
2651
2652 let request: Self::Request = request.into();
2653 let response: Self::Response = response.into();
2654 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2655 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2656
2657 let token_id = match request.version.ok_or(Error::EmptyVersion)? {
2658 get_shielded_pool_state_request::Version::V0(v0) => {
2659 shielded_pool_token_id(v0.token_id)?
2660 }
2661 };
2662
2663 let proof_bytes = supported_grovedb_proof_bytes(proof)?;
2664 let (root_hash, maybe_balance) = match token_id {
2665 None => Drive::verify_shielded_pool_state(proof_bytes, false, platform_version),
2666 Some(token_id) => Drive::verify_token_shielded_pool_state(
2667 proof_bytes,
2668 token_id,
2669 false,
2670 platform_version,
2671 ),
2672 }
2673 .map_drive_error(proof, mtd)?;
2674
2675 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2676
2677 Ok((
2678 maybe_balance.map(ShieldedPoolState),
2679 mtd.clone(),
2680 proof.clone(),
2681 ))
2682 }
2683}
2684
2685impl FromProof<platform::GetShieldedNotesCountRequest> for ShieldedNotesCount {
2686 type Request = platform::GetShieldedNotesCountRequest;
2687 type Response = platform::GetShieldedNotesCountResponse;
2688
2689 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2690 request: I,
2691 response: O,
2692 _network: Network,
2693 platform_version: &PlatformVersion,
2694 provider: &'a dyn ContextProvider,
2695 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2696 where
2697 Self: Sized + 'a,
2698 {
2699 use dapi_grpc::platform::v0::get_shielded_notes_count_request;
2700
2701 let request: Self::Request = request.into();
2702 let response: Self::Response = response.into();
2703 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2704 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2705
2706 let token_id = match request.version.ok_or(Error::EmptyVersion)? {
2707 get_shielded_notes_count_request::Version::V0(v0) => {
2708 shielded_pool_token_id(v0.token_id)?
2709 }
2710 };
2711
2712 let proof_bytes = supported_grovedb_proof_bytes(proof)?;
2717 let (root_hash, maybe_count) = match token_id {
2718 None => Drive::verify_shielded_notes_count(proof_bytes, false, platform_version),
2719 Some(token_id) => Drive::verify_token_shielded_pool_notes_count(
2720 proof_bytes,
2721 token_id,
2722 false,
2723 platform_version,
2724 ),
2725 }
2726 .map_drive_error(proof, mtd)?;
2727
2728 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2729
2730 Ok((
2731 maybe_count.map(ShieldedNotesCount),
2732 mtd.clone(),
2733 proof.clone(),
2734 ))
2735 }
2736}
2737
2738impl FromProof<platform::GetShieldedAnchorsRequest> for ShieldedAnchors {
2739 type Request = platform::GetShieldedAnchorsRequest;
2740 type Response = platform::GetShieldedAnchorsResponse;
2741
2742 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2743 request: I,
2744 response: O,
2745 _network: Network,
2746 platform_version: &PlatformVersion,
2747 provider: &'a dyn ContextProvider,
2748 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2749 where
2750 Self: Sized + 'a,
2751 {
2752 use dapi_grpc::platform::v0::get_shielded_anchors_request;
2753
2754 let request: Self::Request = request.into();
2755 let response: Self::Response = response.into();
2756 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2757 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2758
2759 let token_id = match request.version.ok_or(Error::EmptyVersion)? {
2760 get_shielded_anchors_request::Version::V0(v0) => shielded_pool_token_id(v0.token_id)?,
2761 };
2762
2763 let proof_bytes = supported_grovedb_proof_bytes(proof)?;
2764 let (root_hash, anchors) = match token_id {
2765 None => Drive::verify_shielded_anchors(proof_bytes, false, platform_version),
2766 Some(token_id) => Drive::verify_token_shielded_pool_anchors(
2767 proof_bytes,
2768 token_id,
2769 false,
2770 platform_version,
2771 ),
2772 }
2773 .map_drive_error(proof, mtd)?;
2774
2775 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2776
2777 let result = if anchors.is_empty() {
2778 None
2779 } else {
2780 Some(ShieldedAnchors(anchors))
2781 };
2782
2783 Ok((result, mtd.clone(), proof.clone()))
2784 }
2785}
2786
2787impl FromProof<platform::GetMostRecentShieldedAnchorRequest> for MostRecentShieldedAnchor {
2788 type Request = platform::GetMostRecentShieldedAnchorRequest;
2789 type Response = platform::GetMostRecentShieldedAnchorResponse;
2790
2791 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2792 request: I,
2793 response: O,
2794 _network: Network,
2795 platform_version: &PlatformVersion,
2796 provider: &'a dyn ContextProvider,
2797 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2798 where
2799 Self: Sized + 'a,
2800 {
2801 use dapi_grpc::platform::v0::get_most_recent_shielded_anchor_request;
2802
2803 let request: Self::Request = request.into();
2804 let response: Self::Response = response.into();
2805 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2806 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2807
2808 let token_id = match request.version.ok_or(Error::EmptyVersion)? {
2809 get_most_recent_shielded_anchor_request::Version::V0(v0) => {
2810 shielded_pool_token_id(v0.token_id)?
2811 }
2812 };
2813
2814 let proof_bytes = supported_grovedb_proof_bytes(proof)?;
2815 let (root_hash, maybe_anchor) = match token_id {
2816 None => Drive::verify_most_recent_shielded_anchor(proof_bytes, false, platform_version),
2817 Some(token_id) => Drive::verify_most_recent_token_shielded_pool_anchor(
2818 proof_bytes,
2819 token_id,
2820 false,
2821 platform_version,
2822 ),
2823 }
2824 .map_drive_error(proof, mtd)?;
2825
2826 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2827
2828 Ok((
2829 maybe_anchor.map(MostRecentShieldedAnchor),
2830 mtd.clone(),
2831 proof.clone(),
2832 ))
2833 }
2834}
2835
2836impl FromProof<platform::GetShieldedEncryptedNotesRequest> for ShieldedEncryptedNotes {
2837 type Request = platform::GetShieldedEncryptedNotesRequest;
2838 type Response = platform::GetShieldedEncryptedNotesResponse;
2839
2840 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2841 request: I,
2842 response: O,
2843 _network: Network,
2844 platform_version: &PlatformVersion,
2845 provider: &'a dyn ContextProvider,
2846 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2847 where
2848 Self: Sized + 'a,
2849 {
2850 use dapi_grpc::platform::v0::get_shielded_encrypted_notes_request;
2851
2852 let request: Self::Request = request.into();
2853 let response: Self::Response = response.into();
2854 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2855 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2856
2857 let (start_index, count, token_id) = match request.version.ok_or(Error::EmptyVersion)? {
2858 get_shielded_encrypted_notes_request::Version::V0(v0) => (
2859 v0.start_index,
2860 v0.count,
2861 shielded_pool_token_id(v0.token_id)?,
2862 ),
2863 };
2864
2865 let max_elements = platform_version
2866 .drive_abci
2867 .query
2868 .shielded_queries
2869 .max_query_chunks as u32
2870 * (1u32 << drive::drive::shielded::paths::SHIELDED_NOTES_CHUNK_POWER);
2871
2872 let proof_bytes = supported_grovedb_proof_bytes(proof)?;
2873 let (root_hash, notes, total_count) = match token_id {
2874 None => Drive::verify_shielded_encrypted_notes(
2875 proof_bytes,
2876 start_index,
2877 count,
2878 max_elements,
2879 false,
2880 platform_version,
2881 ),
2882 Some(token_id) => Drive::verify_token_shielded_pool_encrypted_notes(
2883 proof_bytes,
2884 token_id,
2885 start_index,
2886 count,
2887 max_elements,
2888 false,
2889 platform_version,
2890 ),
2891 }
2892 .map_drive_error(proof, mtd)?;
2893
2894 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2895
2896 let result = Some(ShieldedEncryptedNotes {
2902 notes: notes
2903 .into_iter()
2904 .map(|n| ShieldedEncryptedNote {
2905 cmx: n.cmx.to_vec(),
2906 nullifier: n.nullifier.to_vec(),
2907 cv_net: n.cv_net.to_vec(),
2908 encrypted_note: n.encrypted_note.to_vec(),
2909 })
2910 .collect(),
2911 total_count,
2912 });
2913
2914 Ok((result, mtd.clone(), proof.clone()))
2915 }
2916}
2917
2918impl FromProof<platform::GetShieldedNullifiersRequest> for ShieldedNullifierStatuses {
2919 type Request = platform::GetShieldedNullifiersRequest;
2920 type Response = platform::GetShieldedNullifiersResponse;
2921
2922 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2923 request: I,
2924 response: O,
2925 _network: Network,
2926 platform_version: &PlatformVersion,
2927 provider: &'a dyn ContextProvider,
2928 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2929 where
2930 Self: Sized + 'a,
2931 {
2932 use dapi_grpc::platform::v0::get_shielded_nullifiers_request;
2933
2934 let request: Self::Request = request.into();
2935 let response: Self::Response = response.into();
2936 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2937 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2938
2939 let (nullifiers, token_id) = match request.version.ok_or(Error::EmptyVersion)? {
2940 get_shielded_nullifiers_request::Version::V0(v0) => {
2941 (v0.nullifiers, shielded_pool_token_id(v0.token_id)?)
2942 }
2943 };
2944
2945 let proof_bytes = supported_grovedb_proof_bytes(proof)?;
2946 let (root_hash, statuses) = match token_id {
2947 None => {
2948 Drive::verify_shielded_nullifiers(proof_bytes, &nullifiers, false, platform_version)
2949 }
2950 Some(token_id) => Drive::verify_token_shielded_pool_nullifiers(
2951 proof_bytes,
2952 token_id,
2953 &nullifiers,
2954 false,
2955 platform_version,
2956 ),
2957 }
2958 .map_drive_error(proof, mtd)?;
2959
2960 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2961
2962 let result = if statuses.is_empty() {
2963 None
2964 } else {
2965 Some(ShieldedNullifierStatuses(
2966 statuses
2967 .into_iter()
2968 .map(|(nullifier, is_spent)| {
2969 let nullifier: [u8; 32] =
2970 nullifier
2971 .try_into()
2972 .map_err(|_| Error::ResultEncodingError {
2973 error: "nullifier from Drive proof is not 32 bytes".to_string(),
2974 })?;
2975 Ok(ShieldedNullifierStatus {
2976 nullifier,
2977 is_spent,
2978 })
2979 })
2980 .collect::<Result<Vec<_>, Error>>()?,
2981 ))
2982 };
2983
2984 Ok((result, mtd.clone(), proof.clone()))
2985 }
2986}
2987
2988pub trait Length {
2990 fn count_some(&self) -> usize;
2992 fn count(&self) -> usize;
2994}
2995
2996impl<T: Length> Length for Option<T> {
2997 fn count_some(&self) -> usize {
2998 match self {
2999 None => 0,
3000 Some(i) => i.count_some(),
3001 }
3002 }
3003 fn count(&self) -> usize {
3004 match self {
3005 None => 0,
3006 Some(i) => i.count(),
3007 }
3008 }
3009}
3010
3011impl<T> Length for Vec<Option<T>> {
3012 fn count_some(&self) -> usize {
3013 self.iter().filter(|v| v.is_some()).count()
3014 }
3015
3016 fn count(&self) -> usize {
3017 self.len()
3018 }
3019}
3020
3021impl<K, T> Length for Vec<(K, Option<T>)> {
3022 fn count_some(&self) -> usize {
3023 self.iter().filter(|(_, v)| v.is_some()).count()
3024 }
3025
3026 fn count(&self) -> usize {
3027 self.len()
3028 }
3029}
3030
3031impl<K, T> Length for BTreeMap<K, Option<T>> {
3032 fn count_some(&self) -> usize {
3033 self.values().filter(|v| v.is_some()).count()
3034 }
3035
3036 fn count(&self) -> usize {
3037 self.len()
3038 }
3039}
3040
3041impl<K, T> Length for IndexMap<K, Option<T>> {
3042 fn count_some(&self) -> usize {
3043 self.values().filter(|v| v.is_some()).count()
3044 }
3045
3046 fn count(&self) -> usize {
3047 self.len()
3048 }
3049}
3050
3051macro_rules! define_length {
3058 ($object:ty,$some:expr,$counter:expr) => {
3059 impl Length for $object {
3060 fn count_some(&self) -> usize {
3061 #[allow(clippy::redundant_closure_call)]
3062 $some(self)
3063 }
3064
3065 fn count(&self) -> usize {
3066 #[allow(clippy::redundant_closure_call)]
3067 $counter(self)
3068 }
3069 }
3070 };
3071 ($object:ty,$some:expr) => {
3072 define_length!($object, $some, $some);
3073 };
3074 ($object:ty) => {
3075 define_length!($object, |_| 1, |_| 1);
3076 };
3077}
3078
3079define_length!(DataContract);
3080define_length!(DataContractHistory, |d: &DataContractHistory| d.len());
3081define_length!(DocumentHistory, |d: &DocumentHistory| d.len());
3082define_length!(Document);
3083define_length!(Identity);
3084define_length!(IdentityBalance);
3085define_length!(IdentityBalanceAndRevision);
3086define_length!(
3087 IdentitiesContractKeys,
3088 |x: &IdentitiesContractKeys| x.values().map(|v| v.count_some()).sum(),
3089 |x: &IdentitiesContractKeys| x.len()
3090);
3091define_length!(ContestedResources, |x: &ContestedResources| x.0.len());
3092define_length!(Contenders, |x: &Contenders| x.contenders.len());
3093define_length!(Voters, |x: &Voters| x.0.len());
3094define_length!(
3095 VotePollsGroupedByTimestamp,
3096 |x: &VotePollsGroupedByTimestamp| x.0.iter().map(|v| v.1.len()).sum(),
3097 |x: &VotePollsGroupedByTimestamp| x.0.len()
3098);
3099
3100trait IntoOption
3102where
3103 Self: Sized,
3104{
3105 fn into_option(self) -> Option<Self>;
3111}
3112
3113impl<L: Length> IntoOption for L {
3114 fn into_option(self) -> Option<Self>
3115 where
3116 Self: Sized,
3117 {
3118 if self.count() == 0 {
3119 None
3120 } else {
3121 Some(self)
3122 }
3123 }
3124}
3125
3126#[cfg(test)]
3127mod tests {
3128 use super::*;
3129
3130 #[test]
3131 fn try_u32_to_u16_succeeds_for_valid_values() {
3132 assert_eq!(try_u32_to_u16(0).unwrap(), 0u16);
3133 assert_eq!(try_u32_to_u16(1).unwrap(), 1u16);
3134 assert_eq!(try_u32_to_u16(42).unwrap(), 42u16);
3135 assert_eq!(try_u32_to_u16(u16::MAX as u32).unwrap(), u16::MAX);
3136 }
3137
3138 #[test]
3139 fn try_u32_to_u16_errors_on_overflow() {
3140 let result = try_u32_to_u16(65536);
3144 assert!(
3145 result.is_err(),
3146 "epoch 65536 must not silently truncate to 0"
3147 );
3148
3149 let result = try_u32_to_u16(u32::MAX);
3150 assert!(result.is_err(), "epoch u32::MAX must not silently truncate");
3151
3152 let result = try_u32_to_u16(100_000);
3153 assert!(result.is_err(), "epoch 100000 must not silently truncate");
3154 }
3155
3156 #[test]
3157 fn u32_to_u16_opt_succeeds_for_valid_values() {
3158 assert_eq!(u32_to_u16_opt(0).unwrap(), None);
3159 assert_eq!(u32_to_u16_opt(1).unwrap(), Some(1u16));
3160 assert_eq!(u32_to_u16_opt(u16::MAX as u32).unwrap(), Some(u16::MAX));
3161 }
3162
3163 #[test]
3164 fn u32_to_u16_opt_errors_on_overflow() {
3165 let result = u32_to_u16_opt(65536);
3166 assert!(
3167 result.is_err(),
3168 "value 65536 must not silently truncate to 0"
3169 );
3170
3171 let result = u32_to_u16_opt(u32::MAX);
3172 assert!(result.is_err(), "value u32::MAX must not silently truncate");
3173 }
3174
3175 #[test]
3180 fn length_vec_option_counts_some_and_total() {
3181 let v: Vec<Option<u32>> = vec![Some(1), None, Some(2), None, Some(3)];
3182 assert_eq!(v.count(), 5);
3183 assert_eq!(v.count_some(), 3);
3184
3185 let empty: Vec<Option<u32>> = vec![];
3186 assert_eq!(empty.count(), 0);
3187 assert_eq!(empty.count_some(), 0);
3188 }
3189
3190 #[test]
3191 fn length_option_of_length_delegates() {
3192 let inner: Vec<Option<u32>> = vec![Some(1), None];
3193 let some_inner: Option<Vec<Option<u32>>> = Some(inner);
3194 assert_eq!(some_inner.count(), 2);
3195 assert_eq!(some_inner.count_some(), 1);
3196
3197 let none_inner: Option<Vec<Option<u32>>> = None;
3198 assert_eq!(none_inner.count(), 0);
3199 assert_eq!(none_inner.count_some(), 0);
3200 }
3201
3202 #[test]
3203 fn length_vec_of_key_option_pair() {
3204 let v: Vec<(u8, Option<u32>)> = vec![(1, Some(10)), (2, None), (3, Some(30)), (4, None)];
3205 assert_eq!(v.count(), 4);
3206 assert_eq!(v.count_some(), 2);
3207 }
3208
3209 #[test]
3210 fn length_btreemap_of_option() {
3211 let mut m: BTreeMap<u8, Option<u32>> = BTreeMap::new();
3212 m.insert(1, Some(10));
3213 m.insert(2, None);
3214 m.insert(3, Some(30));
3215 assert_eq!(m.count(), 3);
3216 assert_eq!(m.count_some(), 2);
3217 }
3218
3219 #[test]
3220 fn length_indexmap_of_option() {
3221 let mut m: IndexMap<u8, Option<u32>> = IndexMap::new();
3222 m.insert(1, Some(10));
3223 m.insert(2, None);
3224 m.insert(3, Some(30));
3225 m.insert(4, None);
3226 assert_eq!(m.count(), 4);
3227 assert_eq!(m.count_some(), 2);
3228 }
3229
3230 #[test]
3231 fn into_option_returns_none_for_empty_and_some_for_nonempty() {
3232 let empty: Vec<Option<u32>> = vec![];
3234 assert!(empty.into_option().is_none());
3235
3236 let all_none: Vec<Option<u32>> = vec![None, None];
3238 let wrapped = all_none.into_option();
3239 assert!(wrapped.is_some());
3240 assert_eq!(wrapped.unwrap().len(), 2);
3241
3242 let mixed: Vec<Option<u32>> = vec![Some(1), None];
3244 assert!(mixed.into_option().is_some());
3245 }
3246
3247 #[test]
3248 fn into_option_for_indexmap() {
3249 let empty: IndexMap<u8, Option<u32>> = IndexMap::new();
3250 assert!(empty.into_option().is_none());
3251
3252 let mut m: IndexMap<u8, Option<u32>> = IndexMap::new();
3253 m.insert(1, None); let wrapped = m.into_option();
3255 assert!(
3256 wrapped.is_some(),
3257 "IntoOption must preserve maps that carry absence markers"
3258 );
3259 }
3260
3261 #[test]
3266 fn parse_key_request_type_missing_outer_request() {
3267 let err = parse_key_request_type(&None)
3268 .err()
3269 .expect("None input must error");
3270 match err {
3271 Error::RequestError { error } => {
3272 assert!(
3273 error.contains("missing key request type"),
3274 "unexpected error message: {error}"
3275 );
3276 }
3277 other => panic!("expected RequestError, got: {other:?}"),
3278 }
3279 }
3280
3281 #[test]
3282 fn parse_key_request_type_missing_inner_request_field() {
3283 let outer = Some(GrpcKeyType { request: None });
3285 let err = parse_key_request_type(&outer)
3286 .err()
3287 .expect("missing request must error");
3288 match err {
3289 Error::RequestError { error } => {
3290 assert!(
3291 error.contains("empty request field"),
3292 "unexpected error message: {error}"
3293 );
3294 }
3295 other => panic!("expected RequestError, got: {other:?}"),
3296 }
3297 }
3298
3299 #[test]
3300 fn parse_key_request_type_all_keys_variant() {
3301 use dapi_grpc::platform::v0::AllKeys;
3302 let outer = Some(GrpcKeyType {
3303 request: Some(key_request_type::Request::AllKeys(AllKeys {})),
3304 });
3305 let parsed = parse_key_request_type(&outer).unwrap();
3306 assert!(matches!(parsed, KeyRequestType::AllKeys));
3307 }
3308
3309 #[test]
3310 fn parse_key_request_type_specific_keys_variant() {
3311 use dapi_grpc::platform::v0::SpecificKeys;
3312 let outer = Some(GrpcKeyType {
3313 request: Some(key_request_type::Request::SpecificKeys(SpecificKeys {
3314 key_ids: vec![1, 2, 3],
3315 })),
3316 });
3317 let parsed = parse_key_request_type(&outer).unwrap();
3318 match parsed {
3319 KeyRequestType::SpecificKeys(ids) => assert_eq!(ids, vec![1, 2, 3]),
3320 _ => panic!("expected SpecificKeys variant"),
3321 }
3322 }
3323
3324 #[test]
3325 fn parse_key_request_type_search_key_rejects_invalid_kind() {
3326 use dapi_grpc::platform::v0::{SearchKey, SecurityLevelMap};
3327 let mut sec_map: std::collections::HashMap<u32, i32> = std::collections::HashMap::new();
3328 sec_map.insert(0, 99);
3330
3331 let mut purpose_map = std::collections::HashMap::new();
3332 purpose_map.insert(
3333 0u32,
3334 SecurityLevelMap {
3335 security_level_map: sec_map,
3336 },
3337 );
3338
3339 let outer = Some(GrpcKeyType {
3340 request: Some(key_request_type::Request::SearchKey(SearchKey {
3341 purpose_map,
3342 })),
3343 });
3344
3345 let err = parse_key_request_type(&outer)
3346 .err()
3347 .expect("bad key kind must error");
3348 match err {
3349 Error::RequestError { error } => assert!(
3350 error.contains("missing requested key type"),
3351 "unexpected error: {error}"
3352 ),
3353 other => panic!("expected RequestError for bad key kind, got: {other:?}"),
3354 }
3355 }
3356
3357 #[test]
3358 fn parse_key_request_type_search_key_accepts_valid_kinds() {
3359 use dapi_grpc::platform::v0::{SearchKey, SecurityLevelMap};
3360 let mut sec_map: std::collections::HashMap<u32, i32> = std::collections::HashMap::new();
3361 sec_map.insert(0, GrpcKeyKind::CurrentKeyOfKindRequest as i32);
3362 sec_map.insert(1, GrpcKeyKind::AllKeysOfKindRequest as i32);
3363
3364 let mut purpose_map = std::collections::HashMap::new();
3365 purpose_map.insert(
3366 0u32,
3367 SecurityLevelMap {
3368 security_level_map: sec_map,
3369 },
3370 );
3371
3372 let outer = Some(GrpcKeyType {
3373 request: Some(key_request_type::Request::SearchKey(SearchKey {
3374 purpose_map,
3375 })),
3376 });
3377
3378 let parsed = parse_key_request_type(&outer).unwrap();
3379 match parsed {
3380 KeyRequestType::SearchKey(purposes) => {
3381 let inner = purposes.get(&0u8).expect("purpose 0 parsed");
3382 assert_eq!(inner.len(), 2);
3383 assert!(matches!(
3384 inner.get(&0u8),
3385 Some(KeyKindRequestType::CurrentKeyOfKindRequest)
3386 ));
3387 assert!(matches!(
3388 inner.get(&1u8),
3389 Some(KeyKindRequestType::AllKeysOfKindRequest)
3390 ));
3391 }
3392 _ => panic!("expected SearchKey variant"),
3393 }
3394 }
3395
3396 struct UnreachableContextProvider;
3408
3409 impl dash_context_provider::ContextProvider for UnreachableContextProvider {
3410 fn get_data_contract(
3411 &self,
3412 _id: &dpp::prelude::Identifier,
3413 _platform_version: &PlatformVersion,
3414 ) -> Result<Option<std::sync::Arc<DataContract>>, dash_context_provider::ContextProviderError>
3415 {
3416 panic!("context provider should not be called on decode-error test")
3417 }
3418
3419 fn get_token_configuration(
3420 &self,
3421 _token_id: &dpp::prelude::Identifier,
3422 ) -> Result<
3423 Option<dpp::data_contract::TokenConfiguration>,
3424 dash_context_provider::ContextProviderError,
3425 > {
3426 panic!("context provider should not be called on decode-error test")
3427 }
3428
3429 fn get_quorum_public_key(
3430 &self,
3431 _quorum_type: u32,
3432 _quorum_hash: [u8; 32],
3433 _core_chain_locked_height: u32,
3434 ) -> Result<[u8; 48], dash_context_provider::ContextProviderError> {
3435 panic!("context provider should not be called on decode-error test")
3436 }
3437
3438 fn get_platform_activation_height(
3439 &self,
3440 ) -> Result<dpp::prelude::CoreBlockHeight, dash_context_provider::ContextProviderError>
3441 {
3442 panic!("context provider should not be called on decode-error test")
3443 }
3444 }
3445
3446 fn unreachable_provider() -> UnreachableContextProvider {
3447 UnreachableContextProvider
3448 }
3449
3450 fn default_platform_version() -> &'static PlatformVersion {
3451 PlatformVersion::latest()
3452 }
3453
3454 struct NoDataContractProvider;
3455
3456 impl dash_context_provider::ContextProvider for NoDataContractProvider {
3457 fn get_data_contract(
3458 &self,
3459 _id: &dpp::prelude::Identifier,
3460 _platform_version: &PlatformVersion,
3461 ) -> Result<Option<std::sync::Arc<DataContract>>, dash_context_provider::ContextProviderError>
3462 {
3463 Ok(None)
3464 }
3465
3466 fn get_token_configuration(
3467 &self,
3468 _token_id: &dpp::prelude::Identifier,
3469 ) -> Result<
3470 Option<dpp::data_contract::TokenConfiguration>,
3471 dash_context_provider::ContextProviderError,
3472 > {
3473 panic!("token configuration should not be requested")
3474 }
3475
3476 fn get_quorum_public_key(
3477 &self,
3478 _quorum_type: u32,
3479 _quorum_hash: [u8; 32],
3480 _core_chain_locked_height: u32,
3481 ) -> Result<[u8; 48], dash_context_provider::ContextProviderError> {
3482 panic!("quorum public key should not be requested")
3483 }
3484
3485 fn get_platform_activation_height(
3486 &self,
3487 ) -> Result<dpp::prelude::CoreBlockHeight, dash_context_provider::ContextProviderError>
3488 {
3489 panic!("platform activation height should not be requested")
3490 }
3491 }
3492
3493 struct StaticDataContractProvider {
3494 data_contract: std::sync::Arc<DataContract>,
3495 }
3496
3497 impl dash_context_provider::ContextProvider for StaticDataContractProvider {
3498 fn get_data_contract(
3499 &self,
3500 id: &dpp::prelude::Identifier,
3501 _platform_version: &PlatformVersion,
3502 ) -> Result<Option<std::sync::Arc<DataContract>>, dash_context_provider::ContextProviderError>
3503 {
3504 if self.data_contract.id() == *id {
3505 Ok(Some(self.data_contract.clone()))
3506 } else {
3507 Ok(None)
3508 }
3509 }
3510
3511 fn get_token_configuration(
3512 &self,
3513 _token_id: &dpp::prelude::Identifier,
3514 ) -> Result<
3515 Option<dpp::data_contract::TokenConfiguration>,
3516 dash_context_provider::ContextProviderError,
3517 > {
3518 panic!("token configuration should not be requested")
3519 }
3520
3521 fn get_quorum_public_key(
3522 &self,
3523 _quorum_type: u32,
3524 _quorum_hash: [u8; 32],
3525 _core_chain_locked_height: u32,
3526 ) -> Result<[u8; 48], dash_context_provider::ContextProviderError> {
3527 panic!("quorum public key should not be requested")
3528 }
3529
3530 fn get_platform_activation_height(
3531 &self,
3532 ) -> Result<dpp::prelude::CoreBlockHeight, dash_context_provider::ContextProviderError>
3533 {
3534 panic!("platform activation height should not be requested")
3535 }
3536 }
3537
3538 fn identity_response_with_proof_and_metadata() -> platform::GetIdentityResponse {
3543 use platform::get_identity_response::{
3544 get_identity_response_v0::Result as V0Result, GetIdentityResponseV0, Version,
3545 };
3546 platform::GetIdentityResponse {
3547 version: Some(Version::V0(GetIdentityResponseV0 {
3548 result: Some(V0Result::Proof(Proof::default())),
3549 metadata: Some(ResponseMetadata::default()),
3550 })),
3551 }
3552 }
3553
3554 fn document_history_response_with_proof_and_metadata() -> platform::GetDocumentHistoryResponse {
3555 use platform::get_document_history_response::{
3556 get_document_history_response_v0::Result as V0Result, GetDocumentHistoryResponseV0,
3557 Version,
3558 };
3559 platform::GetDocumentHistoryResponse {
3560 version: Some(Version::V0(GetDocumentHistoryResponseV0 {
3561 result: Some(V0Result::Proof(Proof::default())),
3562 metadata: Some(ResponseMetadata::default()),
3563 })),
3564 }
3565 }
3566
3567 fn document_history_request(
3568 data_contract_id: Vec<u8>,
3569 document_type_name: &str,
3570 document_id: Vec<u8>,
3571 limit: Option<u32>,
3572 offset: Option<u32>,
3573 ) -> platform::GetDocumentHistoryRequest {
3574 use dapi_grpc::platform::v0::get_document_history_request::GetDocumentHistoryRequestV0;
3575 GetDocumentHistoryRequestV0 {
3576 data_contract_id,
3577 document_type_name: document_type_name.to_string(),
3578 document_id,
3579 limit,
3580 offset,
3581 start_at_ms: 0,
3582 prove: true,
3583 }
3584 .into()
3585 }
3586
3587 fn document_history_error(
3588 request: platform::GetDocumentHistoryRequest,
3589 response: platform::GetDocumentHistoryResponse,
3590 provider: &dyn ContextProvider,
3591 ) -> Error {
3592 <DocumentHistory as FromProof<
3593 platform::GetDocumentHistoryRequest,
3594 >>::maybe_from_proof_with_metadata(
3595 request,
3596 response,
3597 Network::Testnet,
3598 default_platform_version(),
3599 provider,
3600 )
3601 .unwrap_err()
3602 }
3603
3604 #[test]
3605 fn identity_from_proof_no_proof_when_response_empty() {
3606 let request = platform::GetIdentityRequest::default();
3609 let response = platform::GetIdentityResponse::default();
3610
3611 let provider = unreachable_provider();
3612 let err = <Identity as FromProof<platform::GetIdentityRequest>>::maybe_from_proof(
3613 request,
3614 response,
3615 Network::Testnet,
3616 default_platform_version(),
3617 &provider,
3618 )
3619 .unwrap_err();
3620
3621 assert!(
3622 matches!(err, Error::NoProofInResult),
3623 "expected NoProofInResult, got: {err:?}"
3624 );
3625 }
3626
3627 #[test]
3628 fn identity_from_proof_empty_metadata_when_metadata_missing() {
3629 use platform::get_identity_response::{
3630 get_identity_response_v0::Result as V0Result, GetIdentityResponseV0, Version,
3631 };
3632 let response = platform::GetIdentityResponse {
3634 version: Some(Version::V0(GetIdentityResponseV0 {
3635 result: Some(V0Result::Proof(Proof::default())),
3636 metadata: None,
3637 })),
3638 };
3639 let request = platform::GetIdentityRequest::default();
3640 let provider = unreachable_provider();
3641 let err = <Identity as FromProof<platform::GetIdentityRequest>>::maybe_from_proof(
3642 request,
3643 response,
3644 Network::Testnet,
3645 default_platform_version(),
3646 &provider,
3647 )
3648 .unwrap_err();
3649 assert!(matches!(err, Error::EmptyResponseMetadata), "got: {err:?}");
3650 }
3651
3652 #[test]
3653 fn identity_from_proof_empty_version_when_request_has_no_version() {
3654 let response = identity_response_with_proof_and_metadata();
3656 let request = platform::GetIdentityRequest { version: None };
3657 let provider = unreachable_provider();
3658 let err = <Identity as FromProof<platform::GetIdentityRequest>>::maybe_from_proof(
3659 request,
3660 response,
3661 Network::Testnet,
3662 default_platform_version(),
3663 &provider,
3664 )
3665 .unwrap_err();
3666 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
3667 }
3668
3669 #[test]
3670 fn identity_from_proof_protocol_error_on_bad_id_length() {
3671 use dapi_grpc::platform::v0::get_identity_request::GetIdentityRequestV0;
3672 let request: platform::GetIdentityRequest = GetIdentityRequestV0 {
3674 id: vec![0u8; 8],
3675 prove: true,
3676 }
3677 .into();
3678 let response = identity_response_with_proof_and_metadata();
3679 let provider = unreachable_provider();
3680 let err = <Identity as FromProof<platform::GetIdentityRequest>>::maybe_from_proof(
3681 request,
3682 response,
3683 Network::Testnet,
3684 default_platform_version(),
3685 &provider,
3686 )
3687 .unwrap_err();
3688 assert!(
3689 matches!(err, Error::ProtocolError { .. }),
3690 "expected ProtocolError on bad id length, got: {err:?}"
3691 );
3692 }
3693
3694 #[derive(Debug)]
3698 struct MissingFromProof;
3699
3700 impl FromProof<()> for MissingFromProof {
3701 type Request = ();
3702 type Response = ();
3703
3704 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
3705 _request: I,
3706 _response: O,
3707 _network: Network,
3708 _platform_version: &PlatformVersion,
3709 _provider: &'a dyn ContextProvider,
3710 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
3711 where
3712 Self: Sized + 'a,
3713 {
3714 Ok((None, ResponseMetadata::default(), Proof::default()))
3715 }
3716 }
3717
3718 #[test]
3719 fn from_proof_maps_none_to_not_found() {
3720 let provider = unreachable_provider();
3724 let err = <MissingFromProof as FromProof<()>>::from_proof(
3725 (),
3726 (),
3727 Network::Testnet,
3728 default_platform_version(),
3729 &provider,
3730 )
3731 .unwrap_err();
3732 assert!(
3733 matches!(err, Error::NotFound),
3734 "expected NotFound when maybe_from_proof returns None, got: {err:?}"
3735 );
3736 }
3737
3738 #[test]
3739 fn identity_by_public_key_hash_invalid_length_yields_drive_error() {
3740 use dapi_grpc::platform::v0::get_identity_by_public_key_hash_request::GetIdentityByPublicKeyHashRequestV0;
3741
3742 let request: platform::GetIdentityByPublicKeyHashRequest =
3744 GetIdentityByPublicKeyHashRequestV0 {
3745 public_key_hash: vec![0u8; 10],
3746 prove: true,
3747 }
3748 .into();
3749
3750 use platform::get_identity_by_public_key_hash_response::{
3752 get_identity_by_public_key_hash_response_v0::Result as V0Result,
3753 GetIdentityByPublicKeyHashResponseV0, Version,
3754 };
3755 let response = platform::GetIdentityByPublicKeyHashResponse {
3756 version: Some(Version::V0(GetIdentityByPublicKeyHashResponseV0 {
3757 result: Some(V0Result::Proof(Proof::default())),
3758 metadata: Some(ResponseMetadata::default()),
3759 })),
3760 };
3761
3762 let provider = unreachable_provider();
3763 let err =
3764 <Identity as FromProof<platform::GetIdentityByPublicKeyHashRequest>>::maybe_from_proof(
3765 request,
3766 response,
3767 Network::Testnet,
3768 default_platform_version(),
3769 &provider,
3770 )
3771 .unwrap_err();
3772
3773 match err {
3774 Error::DriveError { error } => {
3775 assert!(
3776 error.contains("Invalid public key hash length"),
3777 "unexpected error body: {error}"
3778 );
3779 }
3780 other => panic!("expected DriveError, got: {other:?}"),
3781 }
3782 }
3783
3784 fn non_unique_request(
3786 version: u8,
3787 public_key_hash: Vec<u8>,
3788 start_after: Option<Vec<u8>>,
3789 ) -> platform::GetIdentityByNonUniquePublicKeyHashRequest {
3790 use platform::get_identity_by_non_unique_public_key_hash_request::{
3791 GetIdentityByNonUniquePublicKeyHashRequestV0,
3792 GetIdentityByNonUniquePublicKeyHashRequestV1, Version,
3793 };
3794 platform::GetIdentityByNonUniquePublicKeyHashRequest {
3795 version: Some(match version {
3796 0 => Version::V0(GetIdentityByNonUniquePublicKeyHashRequestV0 {
3797 public_key_hash,
3798 start_after,
3799 prove: true,
3800 }),
3801 _ => Version::V1(GetIdentityByNonUniquePublicKeyHashRequestV1 {
3802 public_key_hash,
3803 start_after,
3804 prove: true,
3805 }),
3806 }),
3807 }
3808 }
3809
3810 fn non_unique_response(
3813 version: u8,
3814 proof: Proof,
3815 metadata: ResponseMetadata,
3816 ) -> platform::GetIdentityByNonUniquePublicKeyHashResponse {
3817 use platform::get_identity_by_non_unique_public_key_hash_response::{
3818 get_identity_by_non_unique_public_key_hash_response_v0::IdentityProvedResponse,
3819 GetIdentityByNonUniquePublicKeyHashResponseV0,
3820 GetIdentityByNonUniquePublicKeyHashResponseV1,
3821 };
3822 platform::GetIdentityByNonUniquePublicKeyHashResponse {
3823 version: Some(match version {
3824 0 => NonUniqueLookupVersion::V0(GetIdentityByNonUniquePublicKeyHashResponseV0 {
3825 result: Some(NonUniqueLookupV0Result::Proof(IdentityProvedResponse {
3826 grovedb_identity_public_key_hash_proof: Some(proof),
3827 identity_proof_bytes: None,
3828 })),
3829 metadata: Some(metadata),
3830 }),
3831 _ => NonUniqueLookupVersion::V1(GetIdentityByNonUniquePublicKeyHashResponseV1 {
3832 result: Some(NonUniqueLookupV1Result::Proof(proof)),
3833 metadata: Some(metadata),
3834 }),
3835 }),
3836 }
3837 }
3838
3839 fn non_unique_lookup_error(
3840 request: platform::GetIdentityByNonUniquePublicKeyHashRequest,
3841 response: platform::GetIdentityByNonUniquePublicKeyHashResponse,
3842 ) -> Error {
3843 <Identity as FromProof<platform::GetIdentityByNonUniquePublicKeyHashRequest>>::maybe_from_proof(
3844 request,
3845 response,
3846 Network::Testnet,
3847 default_platform_version(),
3848 &unreachable_provider(),
3849 )
3850 .unwrap_err()
3851 }
3852
3853 #[test]
3854 fn identity_by_non_unique_public_key_hash_rejects_bad_key_hash_length() {
3855 for version in [0, 1] {
3856 let err = non_unique_lookup_error(
3858 non_unique_request(version, vec![0u8; 3], None),
3859 non_unique_response(version, Proof::default(), ResponseMetadata::default()),
3860 );
3861 assert!(
3862 matches!(&err, Error::RequestError { error } if error.contains("Invalid public key hash length")),
3863 "V{version}: {err:?}"
3864 );
3865 }
3866 }
3867
3868 #[test]
3869 fn identity_by_non_unique_public_key_hash_rejects_bad_start_after_length() {
3870 for version in [0, 1] {
3871 let err = non_unique_lookup_error(
3872 non_unique_request(version, vec![0u8; 20], Some(vec![0u8; 10])),
3873 non_unique_response(version, Proof::default(), ResponseMetadata::default()),
3874 );
3875 assert!(
3876 matches!(&err, Error::RequestError { error } if error.contains("Invalid start_after length")),
3877 "V{version}: {err:?}"
3878 );
3879 }
3880 }
3881
3882 #[test]
3885 fn identity_by_non_unique_public_key_hash_rejects_the_other_response_version() {
3886 for (request_version, response_version) in [(0, 1), (1, 0)] {
3887 let err = non_unique_lookup_error(
3888 non_unique_request(request_version, vec![0u8; 20], None),
3889 non_unique_response(
3890 response_version,
3891 Proof::default(),
3892 ResponseMetadata::default(),
3893 ),
3894 );
3895 assert!(
3896 matches!(&err, Error::ResponseDecodeError { error } if error.contains("does not match request version")),
3897 "V{request_version} request, V{response_version} response: {err:?}"
3898 );
3899 }
3900 }
3901
3902 #[test]
3903 fn identity_by_non_unique_public_key_hash_rejects_v0_complete_proof() {
3904 for version in [0, 1] {
3905 let proof = bincode::encode_to_vec(0u32, bincode::config::standard().with_big_endian())
3906 .expect("V0 envelope discriminant");
3907 let err = non_unique_lookup_error(
3908 non_unique_request(version, vec![0u8; 20], None),
3909 non_unique_response(
3910 version,
3911 Proof {
3912 grovedb_proof: proof,
3913 ..Proof::default()
3914 },
3915 ResponseMetadata {
3916 protocol_version: PlatformVersion::latest().protocol_version,
3917 ..ResponseMetadata::default()
3918 },
3919 ),
3920 );
3921 assert!(
3922 matches!(
3923 err,
3924 Error::UnsupportedGroveDBProofVersion { version: 0, .. }
3925 ),
3926 "V{version}: {err:?}"
3927 );
3928 }
3929 }
3930
3931 #[test]
3932 fn identity_by_non_unique_public_key_hash_rejects_malformed_two_proof_answer() {
3933 use dapi_grpc::Message;
3934 let mut response = platform::GetIdentityByNonUniquePublicKeyHashResponse::decode(
3936 &[0x0a, 0x06, 0x12, 0x04, 0x0a, 0x02, 0x0a, 0x00][..],
3937 )
3938 .expect("V0 fields decode");
3939 let Some(NonUniqueLookupVersion::V0(v0)) = &mut response.version else {
3940 panic!("v0")
3941 };
3942 let Some(NonUniqueLookupV0Result::Proof(proved)) = &mut v0.result else {
3943 panic!("field 2 is the two-proof answer")
3944 };
3945 proved
3948 .grovedb_identity_public_key_hash_proof
3949 .as_mut()
3950 .expect("index proof")
3951 .grovedb_proof = vec![0x01, 0xff, 0xff];
3952 v0.metadata = Some(ResponseMetadata {
3953 protocol_version: 13,
3954 ..Default::default()
3955 });
3956 let err = non_unique_lookup_error(non_unique_request(0, vec![0; 20], None), response);
3957 assert!(matches!(err, Error::GroveDBError { .. }), "{err}");
3958 }
3959
3960 #[test]
3961 fn identity_by_non_unique_public_key_hash_rejects_two_proof_answer_without_index_proof() {
3962 use platform::get_identity_by_non_unique_public_key_hash_response::get_identity_by_non_unique_public_key_hash_response_v0::IdentityProvedResponse;
3963 use platform::get_identity_by_non_unique_public_key_hash_response::GetIdentityByNonUniquePublicKeyHashResponseV0;
3964 let response = platform::GetIdentityByNonUniquePublicKeyHashResponse {
3966 version: Some(NonUniqueLookupVersion::V0(
3967 GetIdentityByNonUniquePublicKeyHashResponseV0 {
3968 result: Some(NonUniqueLookupV0Result::Proof(IdentityProvedResponse {
3969 grovedb_identity_public_key_hash_proof: None,
3970 identity_proof_bytes: Some(vec![0x01]),
3971 })),
3972 metadata: Some(ResponseMetadata {
3973 protocol_version: 13,
3974 ..Default::default()
3975 }),
3976 },
3977 )),
3978 };
3979 let err = non_unique_lookup_error(non_unique_request(0, vec![0; 20], None), response);
3980 assert!(matches!(err, Error::NoProofInResult), "{err}");
3981 }
3982
3983 #[test]
3984 fn identity_by_non_unique_response_with_no_result_yields_no_proof() {
3985 use platform::get_identity_by_non_unique_public_key_hash_response::{
3986 GetIdentityByNonUniquePublicKeyHashResponseV0,
3987 GetIdentityByNonUniquePublicKeyHashResponseV1,
3988 };
3989 for version in [0, 1] {
3990 let response = platform::GetIdentityByNonUniquePublicKeyHashResponse {
3991 version: Some(match version {
3992 0 => {
3993 NonUniqueLookupVersion::V0(GetIdentityByNonUniquePublicKeyHashResponseV0 {
3994 result: None,
3995 metadata: None,
3996 })
3997 }
3998 _ => {
3999 NonUniqueLookupVersion::V1(GetIdentityByNonUniquePublicKeyHashResponseV1 {
4000 result: None,
4001 metadata: None,
4002 })
4003 }
4004 }),
4005 };
4006 let err =
4007 non_unique_lookup_error(non_unique_request(version, vec![0u8; 20], None), response);
4008 assert!(matches!(err, Error::NoProofInResult), "V{version}: {err:?}");
4009 }
4010 }
4011
4012 #[test]
4013 fn identity_by_non_unique_proved_response_without_metadata_is_refused() {
4014 for version in [0, 1] {
4015 let mut response =
4016 non_unique_response(version, Proof::default(), ResponseMetadata::default());
4017 match &mut response.version {
4018 Some(NonUniqueLookupVersion::V0(v0)) => v0.metadata = None,
4019 Some(NonUniqueLookupVersion::V1(v1)) => v1.metadata = None,
4020 None => panic!("version"),
4021 }
4022 let err =
4023 non_unique_lookup_error(non_unique_request(version, vec![0u8; 20], None), response);
4024 assert!(
4025 matches!(err, Error::EmptyResponseMetadata),
4026 "V{version}: {err:?}"
4027 );
4028 }
4029 }
4030
4031 #[test]
4032 fn identity_by_non_unique_request_without_version_is_refused() {
4033 for version in [0, 1] {
4034 let err = non_unique_lookup_error(
4035 platform::GetIdentityByNonUniquePublicKeyHashRequest { version: None },
4036 non_unique_response(version, Proof::default(), ResponseMetadata::default()),
4037 );
4038 assert!(matches!(err, Error::EmptyVersion), "V{version}: {err:?}");
4039 }
4040 }
4041
4042 #[test]
4043 fn identity_by_non_unique_response_with_no_version_yields_no_proof() {
4044 for version in [0, 1] {
4045 let err = non_unique_lookup_error(
4046 non_unique_request(version, vec![0u8; 20], None),
4047 platform::GetIdentityByNonUniquePublicKeyHashResponse { version: None },
4048 );
4049 assert!(matches!(err, Error::NoProofInResult), "V{version}: {err:?}");
4050 }
4051 }
4052
4053 #[test]
4054 fn identities_balances_rejects_non_32_byte_id() {
4055 use dapi_grpc::platform::v0::get_identities_balances_request::GetIdentitiesBalancesRequestV0;
4056 use platform::get_identities_balances_response::{
4057 get_identities_balances_response_v0::Result as V0Result,
4058 GetIdentitiesBalancesResponseV0, Version,
4059 };
4060
4061 let response = platform::GetIdentitiesBalancesResponse {
4062 version: Some(Version::V0(GetIdentitiesBalancesResponseV0 {
4063 result: Some(V0Result::Proof(Proof::default())),
4064 metadata: Some(ResponseMetadata::default()),
4065 })),
4066 };
4067
4068 let request: platform::GetIdentitiesBalancesRequest = GetIdentitiesBalancesRequestV0 {
4069 ids: vec![vec![0u8; 10]], prove: true,
4071 }
4072 .into();
4073
4074 let provider = unreachable_provider();
4075 let err =
4076 <IdentityBalances as FromProof<platform::GetIdentitiesBalancesRequest>>::maybe_from_proof(
4077 request,
4078 response,
4079 Network::Testnet,
4080 default_platform_version(),
4081 &provider,
4082 )
4083 .unwrap_err();
4084 match err {
4085 Error::RequestError { error } => {
4086 assert!(error.contains("all 32 bytes"), "got: {error}");
4087 }
4088 other => panic!("expected RequestError, got: {other:?}"),
4089 }
4090 }
4091
4092 #[test]
4093 fn data_contracts_rejects_wrong_size_id() {
4094 use dapi_grpc::platform::v0::get_data_contracts_request::GetDataContractsRequestV0;
4095 use platform::get_data_contracts_response::{
4096 get_data_contracts_response_v0::Result as V0Result, GetDataContractsResponseV0, Version,
4097 };
4098
4099 let response = platform::GetDataContractsResponse {
4100 version: Some(Version::V0(GetDataContractsResponseV0 {
4101 result: Some(V0Result::Proof(Proof::default())),
4102 metadata: Some(ResponseMetadata::default()),
4103 })),
4104 };
4105 let request: platform::GetDataContractsRequest = GetDataContractsRequestV0 {
4106 ids: vec![vec![0u8; 20]], prove: true,
4108 }
4109 .into();
4110 let provider = unreachable_provider();
4111 let err =
4112 <DataContracts as FromProof<platform::GetDataContractsRequest>>::maybe_from_proof(
4113 request,
4114 response,
4115 Network::Testnet,
4116 default_platform_version(),
4117 &provider,
4118 )
4119 .unwrap_err();
4120 match err {
4121 Error::RequestError { error } => {
4122 assert!(error.contains("wrong id size"), "got: {error}");
4123 }
4124 other => panic!("expected RequestError, got: {other:?}"),
4125 }
4126 }
4127
4128 #[test]
4129 fn upgrade_vote_status_rejects_bad_start_pro_tx_hash_length() {
4130 use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_request::GetProtocolVersionUpgradeVoteStatusRequestV0;
4131 use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_response::{
4132 get_protocol_version_upgrade_vote_status_response_v0::Result as V0Result,
4133 GetProtocolVersionUpgradeVoteStatusResponseV0, Version,
4134 };
4135
4136 let response = GetProtocolVersionUpgradeVoteStatusResponse {
4137 version: Some(Version::V0(GetProtocolVersionUpgradeVoteStatusResponseV0 {
4138 result: Some(V0Result::Proof(Proof::default())),
4139 metadata: Some(ResponseMetadata::default()),
4140 })),
4141 };
4142 let request: GetProtocolVersionUpgradeVoteStatusRequest =
4144 GetProtocolVersionUpgradeVoteStatusRequestV0 {
4145 start_pro_tx_hash: vec![0u8; 5],
4146 count: 10,
4147 prove: true,
4148 }
4149 .into();
4150 let provider = unreachable_provider();
4151 let err = <MasternodeProtocolVotes as FromProof<
4152 GetProtocolVersionUpgradeVoteStatusRequest,
4153 >>::maybe_from_proof(
4154 request,
4155 response,
4156 Network::Testnet,
4157 default_platform_version(),
4158 &provider,
4159 )
4160 .unwrap_err();
4161 match err {
4162 Error::RequestError { .. } => {}
4163 other => panic!("expected RequestError for bad pro_tx_hash length, got: {other:?}"),
4164 }
4165 }
4166
4167 #[test]
4168 fn upgrade_vote_status_empty_version_on_request_none() {
4169 use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_response::{
4170 get_protocol_version_upgrade_vote_status_response_v0::Result as V0Result,
4171 GetProtocolVersionUpgradeVoteStatusResponseV0, Version,
4172 };
4173 let response = GetProtocolVersionUpgradeVoteStatusResponse {
4174 version: Some(Version::V0(GetProtocolVersionUpgradeVoteStatusResponseV0 {
4175 result: Some(V0Result::Proof(Proof::default())),
4176 metadata: Some(ResponseMetadata::default()),
4177 })),
4178 };
4179 let request = GetProtocolVersionUpgradeVoteStatusRequest { version: None };
4180 let provider = unreachable_provider();
4181 let err = <MasternodeProtocolVotes as FromProof<
4182 GetProtocolVersionUpgradeVoteStatusRequest,
4183 >>::maybe_from_proof(
4184 request,
4185 response,
4186 Network::Testnet,
4187 default_platform_version(),
4188 &provider,
4189 )
4190 .unwrap_err();
4191 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
4192 }
4193
4194 #[test]
4195 fn path_elements_no_proof_without_response() {
4196 let request = GetPathElementsRequest::default();
4197 let response = GetPathElementsResponse::default();
4198 let provider = unreachable_provider();
4199 let err = <Elements as FromProof<GetPathElementsRequest>>::maybe_from_proof(
4200 request,
4201 response,
4202 Network::Testnet,
4203 default_platform_version(),
4204 &provider,
4205 )
4206 .unwrap_err();
4207 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
4208 }
4209
4210 #[test]
4211 fn prefunded_balance_rejects_bad_id_length() {
4212 use dapi_grpc::platform::v0::get_prefunded_specialized_balance_request::GetPrefundedSpecializedBalanceRequestV0;
4213 use platform::get_prefunded_specialized_balance_response::{
4214 get_prefunded_specialized_balance_response_v0::Result as V0Result,
4215 GetPrefundedSpecializedBalanceResponseV0, Version,
4216 };
4217 let response = platform::GetPrefundedSpecializedBalanceResponse {
4218 version: Some(Version::V0(GetPrefundedSpecializedBalanceResponseV0 {
4219 result: Some(V0Result::Proof(Proof::default())),
4220 metadata: Some(ResponseMetadata::default()),
4221 })),
4222 };
4223 let request: platform::GetPrefundedSpecializedBalanceRequest =
4224 GetPrefundedSpecializedBalanceRequestV0 {
4225 id: vec![0u8; 3], prove: true,
4227 }
4228 .into();
4229 let provider = unreachable_provider();
4230 let err = <PrefundedSpecializedBalance as FromProof<
4231 platform::GetPrefundedSpecializedBalanceRequest,
4232 >>::maybe_from_proof(
4233 request,
4234 response,
4235 Network::Testnet,
4236 default_platform_version(),
4237 &provider,
4238 )
4239 .unwrap_err();
4240 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
4241 }
4242
4243 #[test]
4244 fn epochs_info_rejects_overflowing_start_epoch() {
4245 use dapi_grpc::platform::v0::get_epochs_info_request::GetEpochsInfoRequestV0;
4246 use platform::get_epochs_info_response::{
4247 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
4248 };
4249 let response = platform::GetEpochsInfoResponse {
4250 version: Some(Version::V0(GetEpochsInfoResponseV0 {
4251 result: Some(V0Result::Proof(Proof::default())),
4252 metadata: Some(ResponseMetadata {
4253 epoch: 10,
4254 ..Default::default()
4255 }),
4256 })),
4257 };
4258 let request = platform::GetEpochsInfoRequest {
4260 version: Some(platform::get_epochs_info_request::Version::V0(
4261 GetEpochsInfoRequestV0 {
4262 start_epoch: Some(100_000),
4263 count: 1,
4264 ascending: true,
4265 prove: true,
4266 },
4267 )),
4268 };
4269 let provider = unreachable_provider();
4270 let err =
4271 <ExtendedEpochInfos as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
4272 request,
4273 response,
4274 Network::Testnet,
4275 default_platform_version(),
4276 &provider,
4277 )
4278 .unwrap_err();
4279 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
4280 }
4281
4282 #[test]
4283 fn broadcast_state_transition_rejects_garbage_payload() {
4284 let request = platform::BroadcastStateTransitionRequest {
4287 state_transition: vec![0xFFu8; 16], };
4289 use platform::wait_for_state_transition_result_response::{
4292 wait_for_state_transition_result_response_v0::Result as V0Result, Version,
4293 WaitForStateTransitionResultResponseV0,
4294 };
4295 let response = platform::WaitForStateTransitionResultResponse {
4296 version: Some(Version::V0(WaitForStateTransitionResultResponseV0 {
4297 result: Some(V0Result::Proof(Proof::default())),
4298 metadata: Some(ResponseMetadata::default()),
4299 })),
4300 };
4301 let provider = unreachable_provider();
4302 let err = <StateTransitionProofOutcome as FromProof<
4303 platform::BroadcastStateTransitionRequest,
4304 >>::maybe_from_proof(
4305 request,
4306 response,
4307 Network::Testnet,
4308 default_platform_version(),
4309 &provider,
4310 )
4311 .unwrap_err();
4312 assert!(
4313 matches!(err, Error::ProtocolError { .. }),
4314 "expected ProtocolError from StateTransition decode, got: {err:?}"
4315 );
4316 }
4317
4318 #[test]
4323 fn u32_to_u16_opt_zero_maps_to_none() {
4324 let parsed = u32_to_u16_opt(0).unwrap();
4327 assert!(parsed.is_none(), "value 0 must decode to None");
4328 }
4329
4330 #[test]
4331 fn u32_to_u16_opt_at_boundary() {
4332 let parsed = u32_to_u16_opt(u16::MAX as u32).unwrap();
4333 assert_eq!(parsed, Some(u16::MAX));
4334 }
4335
4336 #[test]
4337 fn u32_to_u16_opt_error_just_above_boundary() {
4338 let err = u32_to_u16_opt((u16::MAX as u32) + 1).unwrap_err();
4340 match err {
4341 Error::RequestError { error } => {
4342 assert!(error.contains("out of range"), "got: {error}");
4343 }
4344 other => panic!("expected RequestError, got: {other:?}"),
4345 }
4346 }
4347
4348 #[test]
4349 fn try_u32_to_u16_at_boundary_plus_one() {
4350 assert!(try_u32_to_u16(u16::MAX as u32).is_ok());
4352 assert!(try_u32_to_u16((u16::MAX as u32) + 1).is_err());
4353 }
4354
4355 #[test]
4360 fn length_option_of_length_none_counts_zero() {
4361 let none_opt: Option<Vec<Option<u32>>> = None;
4362 assert_eq!(none_opt.count(), 0);
4363 assert_eq!(none_opt.count_some(), 0);
4364 }
4365
4366 #[test]
4367 fn length_vec_of_key_option_pair_only_none_values() {
4368 let v: Vec<(u8, Option<u32>)> = vec![(1, None), (2, None)];
4369 assert_eq!(v.count(), 2);
4370 assert_eq!(
4371 v.count_some(),
4372 0,
4373 "count_some must only count entries whose value is Some"
4374 );
4375 }
4376
4377 #[test]
4378 fn length_btreemap_only_none_values() {
4379 let mut m: BTreeMap<u8, Option<u32>> = BTreeMap::new();
4380 m.insert(1, None);
4381 m.insert(2, None);
4382 assert_eq!(m.count(), 2);
4383 assert_eq!(m.count_some(), 0);
4384 }
4385
4386 #[test]
4387 fn into_option_for_vec_of_key_option_pair_empty_and_nonempty() {
4388 let empty: Vec<(u8, Option<u32>)> = vec![];
4389 assert!(
4390 empty.into_option().is_none(),
4391 "empty vec must decode to None"
4392 );
4393
4394 let single: Vec<(u8, Option<u32>)> = vec![(1, None)];
4395 assert!(
4396 single.into_option().is_some(),
4397 "non-empty vec with only None values must still be Some"
4398 );
4399 }
4400
4401 #[test]
4402 fn into_option_for_btreemap_empty_and_nonempty() {
4403 let empty: BTreeMap<u8, Option<u32>> = BTreeMap::new();
4404 assert!(empty.into_option().is_none());
4405
4406 let mut m: BTreeMap<u8, Option<u32>> = BTreeMap::new();
4407 m.insert(1, None);
4408 assert!(m.into_option().is_some());
4409 }
4410
4411 #[test]
4416 fn parse_key_request_type_specific_keys_empty_ids() {
4417 use dapi_grpc::platform::v0::SpecificKeys;
4419 let outer = Some(GrpcKeyType {
4420 request: Some(key_request_type::Request::SpecificKeys(SpecificKeys {
4421 key_ids: vec![],
4422 })),
4423 });
4424 let parsed = parse_key_request_type(&outer).unwrap();
4425 match parsed {
4426 KeyRequestType::SpecificKeys(ids) => {
4427 assert!(ids.is_empty(), "empty ids must round-trip as empty");
4428 }
4429 _ => panic!("expected SpecificKeys variant"),
4430 }
4431 }
4432
4433 #[test]
4434 fn parse_key_request_type_search_key_empty_purpose_map() {
4435 use dapi_grpc::platform::v0::SearchKey;
4437 let outer = Some(GrpcKeyType {
4438 request: Some(key_request_type::Request::SearchKey(SearchKey {
4439 purpose_map: std::collections::HashMap::new(),
4440 })),
4441 });
4442 let parsed = parse_key_request_type(&outer).unwrap();
4443 match parsed {
4444 KeyRequestType::SearchKey(m) => {
4445 assert!(m.is_empty(), "empty map must round-trip as empty");
4446 }
4447 _ => panic!("expected SearchKey variant"),
4448 }
4449 }
4450
4451 #[test]
4452 fn parse_key_request_type_search_key_negative_kind_rejected() {
4453 use dapi_grpc::platform::v0::{SearchKey, SecurityLevelMap};
4455 let mut sec_map: std::collections::HashMap<u32, i32> = std::collections::HashMap::new();
4456 sec_map.insert(0, -1);
4457 let mut purpose_map = std::collections::HashMap::new();
4458 purpose_map.insert(
4459 0u32,
4460 SecurityLevelMap {
4461 security_level_map: sec_map,
4462 },
4463 );
4464 let outer = Some(GrpcKeyType {
4465 request: Some(key_request_type::Request::SearchKey(SearchKey {
4466 purpose_map,
4467 })),
4468 });
4469 let err = parse_key_request_type(&outer)
4472 .err()
4473 .expect("negative kind must error");
4474 match err {
4475 Error::RequestError { error } => {
4476 assert!(error.contains("missing requested key type"), "got: {error}");
4477 }
4478 other => panic!("expected RequestError, got: {other:?}"),
4479 }
4480 }
4481
4482 #[derive(Debug, PartialEq)]
4489 struct PresentFromProof(u32);
4490
4491 impl FromProof<()> for PresentFromProof {
4492 type Request = ();
4493 type Response = ();
4494
4495 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
4496 _request: I,
4497 _response: O,
4498 _network: Network,
4499 _platform_version: &PlatformVersion,
4500 _provider: &'a dyn ContextProvider,
4501 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
4502 where
4503 Self: Sized + 'a,
4504 {
4505 Ok((
4506 Some(PresentFromProof(7)),
4507 ResponseMetadata {
4508 height: 123,
4509 ..Default::default()
4510 },
4511 Proof::default(),
4512 ))
4513 }
4514 }
4515
4516 #[test]
4517 fn from_proof_with_metadata_returns_value_and_metadata() {
4518 let provider = unreachable_provider();
4520 let (value, mtd) = <PresentFromProof as FromProof<()>>::from_proof_with_metadata(
4521 (),
4522 (),
4523 Network::Testnet,
4524 default_platform_version(),
4525 &provider,
4526 )
4527 .unwrap();
4528 assert_eq!(value, PresentFromProof(7));
4529 assert_eq!(mtd.height, 123);
4530 }
4531
4532 #[test]
4533 fn from_proof_with_metadata_and_proof_returns_all_three() {
4534 let provider = unreachable_provider();
4535 let (value, mtd, _proof) =
4536 <PresentFromProof as FromProof<()>>::from_proof_with_metadata_and_proof(
4537 (),
4538 (),
4539 Network::Testnet,
4540 default_platform_version(),
4541 &provider,
4542 )
4543 .unwrap();
4544 assert_eq!(value, PresentFromProof(7));
4545 assert_eq!(mtd.height, 123);
4546 }
4547
4548 #[test]
4549 fn from_proof_on_missing_returns_not_found_via_wrapper() {
4550 let provider = unreachable_provider();
4552 let err = <MissingFromProof as FromProof<()>>::from_proof_with_metadata(
4553 (),
4554 (),
4555 Network::Testnet,
4556 default_platform_version(),
4557 &provider,
4558 )
4559 .unwrap_err();
4560 assert!(matches!(err, Error::NotFound), "got: {err:?}");
4561 }
4562
4563 #[test]
4564 fn from_proof_with_metadata_and_proof_missing_returns_not_found() {
4565 let provider = unreachable_provider();
4566 let err = <MissingFromProof as FromProof<()>>::from_proof_with_metadata_and_proof(
4567 (),
4568 (),
4569 Network::Testnet,
4570 default_platform_version(),
4571 &provider,
4572 )
4573 .unwrap_err();
4574 assert!(matches!(err, Error::NotFound), "got: {err:?}");
4575 }
4576
4577 #[test]
4578 fn maybe_from_proof_delegates_to_with_metadata_and_forwards_none() {
4579 let provider = unreachable_provider();
4582 let result = <MissingFromProof as FromProof<()>>::maybe_from_proof(
4583 (),
4584 (),
4585 Network::Testnet,
4586 default_platform_version(),
4587 &provider,
4588 )
4589 .unwrap();
4590 assert!(result.is_none(), "MissingFromProof must bubble None");
4591 }
4592
4593 fn default_metadata_with_epoch(epoch: u32) -> ResponseMetadata {
4598 ResponseMetadata {
4599 epoch,
4600 ..Default::default()
4601 }
4602 }
4603
4604 #[test]
4605 fn identity_keys_rejects_bad_identity_id_length() {
4606 use dapi_grpc::platform::v0::get_identity_keys_request::GetIdentityKeysRequestV0;
4607 use platform::get_identity_keys_response::{
4608 get_identity_keys_response_v0::Result as V0Result, GetIdentityKeysResponseV0, Version,
4609 };
4610
4611 let response = platform::GetIdentityKeysResponse {
4612 version: Some(Version::V0(GetIdentityKeysResponseV0 {
4613 result: Some(V0Result::Proof(Proof::default())),
4614 metadata: Some(ResponseMetadata::default()),
4615 })),
4616 };
4617 let request: platform::GetIdentityKeysRequest = GetIdentityKeysRequestV0 {
4618 identity_id: vec![0u8; 5], request_type: None,
4620 limit: None,
4621 offset: None,
4622 prove: true,
4623 }
4624 .into();
4625 let provider = unreachable_provider();
4626 let err =
4627 <IdentityPublicKeys as FromProof<platform::GetIdentityKeysRequest>>::maybe_from_proof(
4628 request,
4629 response,
4630 Network::Testnet,
4631 default_platform_version(),
4632 &provider,
4633 )
4634 .unwrap_err();
4635 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4636 }
4637
4638 #[test]
4639 fn identity_keys_rejects_overflowing_limit() {
4640 use dapi_grpc::platform::v0::get_identity_keys_request::GetIdentityKeysRequestV0;
4641 use platform::get_identity_keys_response::{
4642 get_identity_keys_response_v0::Result as V0Result, GetIdentityKeysResponseV0, Version,
4643 };
4644
4645 let response = platform::GetIdentityKeysResponse {
4646 version: Some(Version::V0(GetIdentityKeysResponseV0 {
4647 result: Some(V0Result::Proof(Proof::default())),
4648 metadata: Some(ResponseMetadata::default()),
4649 })),
4650 };
4651 let request: platform::GetIdentityKeysRequest = GetIdentityKeysRequestV0 {
4652 identity_id: vec![0u8; 32], request_type: None,
4654 limit: Some(100_000),
4655 offset: None,
4656 prove: true,
4657 }
4658 .into();
4659 let provider = unreachable_provider();
4660 let err =
4661 <IdentityPublicKeys as FromProof<platform::GetIdentityKeysRequest>>::maybe_from_proof(
4662 request,
4663 response,
4664 Network::Testnet,
4665 default_platform_version(),
4666 &provider,
4667 )
4668 .unwrap_err();
4669 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
4670 }
4671
4672 #[test]
4673 fn identity_keys_rejects_overflowing_offset() {
4674 use dapi_grpc::platform::v0::get_identity_keys_request::GetIdentityKeysRequestV0;
4675 use platform::get_identity_keys_response::{
4676 get_identity_keys_response_v0::Result as V0Result, GetIdentityKeysResponseV0, Version,
4677 };
4678
4679 let response = platform::GetIdentityKeysResponse {
4680 version: Some(Version::V0(GetIdentityKeysResponseV0 {
4681 result: Some(V0Result::Proof(Proof::default())),
4682 metadata: Some(ResponseMetadata::default()),
4683 })),
4684 };
4685 let request: platform::GetIdentityKeysRequest = GetIdentityKeysRequestV0 {
4686 identity_id: vec![0u8; 32],
4687 request_type: None,
4688 limit: None,
4689 offset: Some(100_000),
4690 prove: true,
4691 }
4692 .into();
4693 let provider = unreachable_provider();
4694 let err =
4695 <IdentityPublicKeys as FromProof<platform::GetIdentityKeysRequest>>::maybe_from_proof(
4696 request,
4697 response,
4698 Network::Testnet,
4699 default_platform_version(),
4700 &provider,
4701 )
4702 .unwrap_err();
4703 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
4704 }
4705
4706 #[test]
4707 fn identity_keys_rejects_missing_key_request_type() {
4708 use dapi_grpc::platform::v0::get_identity_keys_request::GetIdentityKeysRequestV0;
4711 use platform::get_identity_keys_response::{
4712 get_identity_keys_response_v0::Result as V0Result, GetIdentityKeysResponseV0, Version,
4713 };
4714
4715 let response = platform::GetIdentityKeysResponse {
4716 version: Some(Version::V0(GetIdentityKeysResponseV0 {
4717 result: Some(V0Result::Proof(Proof::default())),
4718 metadata: Some(ResponseMetadata::default()),
4719 })),
4720 };
4721 let request: platform::GetIdentityKeysRequest = GetIdentityKeysRequestV0 {
4722 identity_id: vec![0u8; 32],
4723 request_type: None,
4724 limit: None,
4725 offset: None,
4726 prove: true,
4727 }
4728 .into();
4729 let provider = unreachable_provider();
4730 let err =
4731 <IdentityPublicKeys as FromProof<platform::GetIdentityKeysRequest>>::maybe_from_proof(
4732 request,
4733 response,
4734 Network::Testnet,
4735 default_platform_version(),
4736 &provider,
4737 )
4738 .unwrap_err();
4739 match err {
4740 Error::RequestError { error } => {
4741 assert!(error.contains("missing key request type"), "got: {error}");
4742 }
4743 other => panic!("expected RequestError, got: {other:?}"),
4744 }
4745 }
4746
4747 #[test]
4748 fn identity_keys_no_proof_when_response_empty() {
4749 let request = platform::GetIdentityKeysRequest::default();
4750 let response = platform::GetIdentityKeysResponse::default();
4751 let provider = unreachable_provider();
4752 let err =
4753 <IdentityPublicKeys as FromProof<platform::GetIdentityKeysRequest>>::maybe_from_proof(
4754 request,
4755 response,
4756 Network::Testnet,
4757 default_platform_version(),
4758 &provider,
4759 )
4760 .unwrap_err();
4761 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
4762 }
4763
4764 #[test]
4765 fn identity_nonce_rejects_bad_identity_id_length() {
4766 use dapi_grpc::platform::v0::get_identity_nonce_request::GetIdentityNonceRequestV0;
4767 use platform::get_identity_nonce_response::{
4768 get_identity_nonce_response_v0::Result as V0Result, GetIdentityNonceResponseV0, Version,
4769 };
4770
4771 let response = platform::GetIdentityNonceResponse {
4772 version: Some(Version::V0(GetIdentityNonceResponseV0 {
4773 result: Some(V0Result::Proof(Proof::default())),
4774 metadata: Some(ResponseMetadata::default()),
4775 })),
4776 };
4777 let request: platform::GetIdentityNonceRequest = GetIdentityNonceRequestV0 {
4778 identity_id: vec![0u8; 1], prove: true,
4780 }
4781 .into();
4782 let provider = unreachable_provider();
4783 let err = <IdentityNonceFetcher as FromProof<
4784 platform::GetIdentityNonceRequest,
4785 >>::maybe_from_proof(
4786 request,
4787 response,
4788 Network::Testnet,
4789 default_platform_version(),
4790 &provider,
4791 )
4792 .unwrap_err();
4793 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4794 }
4795
4796 #[test]
4797 fn identity_nonce_no_proof_when_response_empty() {
4798 let request = platform::GetIdentityNonceRequest::default();
4799 let response = platform::GetIdentityNonceResponse::default();
4800 let provider = unreachable_provider();
4801 let err = <IdentityNonceFetcher as FromProof<
4802 platform::GetIdentityNonceRequest,
4803 >>::maybe_from_proof(
4804 request,
4805 response,
4806 Network::Testnet,
4807 default_platform_version(),
4808 &provider,
4809 )
4810 .unwrap_err();
4811 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
4812 }
4813
4814 #[test]
4815 fn identity_contract_nonce_rejects_bad_identity_id_length() {
4816 use dapi_grpc::platform::v0::get_identity_contract_nonce_request::GetIdentityContractNonceRequestV0;
4817 use platform::get_identity_contract_nonce_response::{
4818 get_identity_contract_nonce_response_v0::Result as V0Result,
4819 GetIdentityContractNonceResponseV0, Version,
4820 };
4821
4822 let response = platform::GetIdentityContractNonceResponse {
4823 version: Some(Version::V0(GetIdentityContractNonceResponseV0 {
4824 result: Some(V0Result::Proof(Proof::default())),
4825 metadata: Some(ResponseMetadata::default()),
4826 })),
4827 };
4828 let request: platform::GetIdentityContractNonceRequest =
4829 GetIdentityContractNonceRequestV0 {
4830 identity_id: vec![0u8; 10], contract_id: vec![0u8; 32],
4832 prove: true,
4833 }
4834 .into();
4835 let provider = unreachable_provider();
4836 let err = <IdentityContractNonceFetcher as FromProof<
4837 platform::GetIdentityContractNonceRequest,
4838 >>::maybe_from_proof(
4839 request,
4840 response,
4841 Network::Testnet,
4842 default_platform_version(),
4843 &provider,
4844 )
4845 .unwrap_err();
4846 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4847 }
4848
4849 #[test]
4850 fn identity_contract_nonce_rejects_bad_contract_id_length() {
4851 use dapi_grpc::platform::v0::get_identity_contract_nonce_request::GetIdentityContractNonceRequestV0;
4852 use platform::get_identity_contract_nonce_response::{
4853 get_identity_contract_nonce_response_v0::Result as V0Result,
4854 GetIdentityContractNonceResponseV0, Version,
4855 };
4856
4857 let response = platform::GetIdentityContractNonceResponse {
4858 version: Some(Version::V0(GetIdentityContractNonceResponseV0 {
4859 result: Some(V0Result::Proof(Proof::default())),
4860 metadata: Some(ResponseMetadata::default()),
4861 })),
4862 };
4863 let request: platform::GetIdentityContractNonceRequest =
4864 GetIdentityContractNonceRequestV0 {
4865 identity_id: vec![0u8; 32],
4866 contract_id: vec![0u8; 10], prove: true,
4868 }
4869 .into();
4870 let provider = unreachable_provider();
4871 let err = <IdentityContractNonceFetcher as FromProof<
4872 platform::GetIdentityContractNonceRequest,
4873 >>::maybe_from_proof(
4874 request,
4875 response,
4876 Network::Testnet,
4877 default_platform_version(),
4878 &provider,
4879 )
4880 .unwrap_err();
4881 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4882 }
4883
4884 #[test]
4885 fn identity_balance_rejects_bad_id_length() {
4886 use dapi_grpc::platform::v0::get_identity_balance_request::GetIdentityBalanceRequestV0;
4887 use platform::get_identity_balance_response::{
4888 get_identity_balance_response_v0::Result as V0Result, GetIdentityBalanceResponseV0,
4889 Version,
4890 };
4891
4892 let response = platform::GetIdentityBalanceResponse {
4893 version: Some(Version::V0(GetIdentityBalanceResponseV0 {
4894 result: Some(V0Result::Proof(Proof::default())),
4895 metadata: Some(ResponseMetadata::default()),
4896 })),
4897 };
4898 let request: platform::GetIdentityBalanceRequest = GetIdentityBalanceRequestV0 {
4899 id: vec![0u8; 5],
4900 prove: true,
4901 }
4902 .into();
4903 let provider = unreachable_provider();
4904 let err =
4905 <IdentityBalance as FromProof<platform::GetIdentityBalanceRequest>>::maybe_from_proof(
4906 request,
4907 response,
4908 Network::Testnet,
4909 default_platform_version(),
4910 &provider,
4911 )
4912 .unwrap_err();
4913 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4914 }
4915
4916 #[test]
4917 fn identity_balance_empty_version_on_request_version_none() {
4918 use platform::get_identity_balance_response::{
4920 get_identity_balance_response_v0::Result as V0Result, GetIdentityBalanceResponseV0,
4921 Version,
4922 };
4923 let response = platform::GetIdentityBalanceResponse {
4924 version: Some(Version::V0(GetIdentityBalanceResponseV0 {
4925 result: Some(V0Result::Proof(Proof::default())),
4926 metadata: Some(ResponseMetadata::default()),
4927 })),
4928 };
4929 let request = platform::GetIdentityBalanceRequest { version: None };
4930 let provider = unreachable_provider();
4931 let err =
4932 <IdentityBalance as FromProof<platform::GetIdentityBalanceRequest>>::maybe_from_proof(
4933 request,
4934 response,
4935 Network::Testnet,
4936 default_platform_version(),
4937 &provider,
4938 )
4939 .unwrap_err();
4940 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
4941 }
4942
4943 #[test]
4944 fn identity_balance_and_revision_rejects_bad_id_length() {
4945 use dapi_grpc::platform::v0::get_identity_balance_and_revision_request::GetIdentityBalanceAndRevisionRequestV0;
4946 use platform::get_identity_balance_and_revision_response::{
4947 get_identity_balance_and_revision_response_v0::Result as V0Result,
4948 GetIdentityBalanceAndRevisionResponseV0, Version,
4949 };
4950 let response = platform::GetIdentityBalanceAndRevisionResponse {
4951 version: Some(Version::V0(GetIdentityBalanceAndRevisionResponseV0 {
4952 result: Some(V0Result::Proof(Proof::default())),
4953 metadata: Some(ResponseMetadata::default()),
4954 })),
4955 };
4956 let request: platform::GetIdentityBalanceAndRevisionRequest =
4957 GetIdentityBalanceAndRevisionRequestV0 {
4958 id: vec![0u8; 5],
4959 prove: true,
4960 }
4961 .into();
4962 let provider = unreachable_provider();
4963 let err = <IdentityBalanceAndRevision as FromProof<
4964 platform::GetIdentityBalanceAndRevisionRequest,
4965 >>::maybe_from_proof(
4966 request,
4967 response,
4968 Network::Testnet,
4969 default_platform_version(),
4970 &provider,
4971 )
4972 .unwrap_err();
4973 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4974 }
4975
4976 #[test]
4977 fn identities_balances_empty_version_none() {
4978 use platform::get_identities_balances_response::{
4979 get_identities_balances_response_v0::Result as V0Result,
4980 GetIdentitiesBalancesResponseV0, Version,
4981 };
4982 let response = platform::GetIdentitiesBalancesResponse {
4983 version: Some(Version::V0(GetIdentitiesBalancesResponseV0 {
4984 result: Some(V0Result::Proof(Proof::default())),
4985 metadata: Some(ResponseMetadata::default()),
4986 })),
4987 };
4988 let request = platform::GetIdentitiesBalancesRequest { version: None };
4989 let provider = unreachable_provider();
4990 let err =
4991 <IdentityBalances as FromProof<platform::GetIdentitiesBalancesRequest>>::maybe_from_proof(
4992 request,
4993 response,
4994 Network::Testnet,
4995 default_platform_version(),
4996 &provider,
4997 )
4998 .unwrap_err();
4999 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5000 }
5001
5002 #[test]
5003 fn data_contract_rejects_bad_id_length() {
5004 use dapi_grpc::platform::v0::get_data_contract_request::GetDataContractRequestV0;
5005 use platform::get_data_contract_response::{
5006 get_data_contract_response_v0::Result as V0Result, GetDataContractResponseV0, Version,
5007 };
5008 let response = platform::GetDataContractResponse {
5009 version: Some(Version::V0(GetDataContractResponseV0 {
5010 result: Some(V0Result::Proof(Proof::default())),
5011 metadata: Some(ResponseMetadata::default()),
5012 })),
5013 };
5014 let request: platform::GetDataContractRequest = GetDataContractRequestV0 {
5015 id: vec![0u8; 5],
5016 prove: true,
5017 }
5018 .into();
5019 let provider = unreachable_provider();
5020 let err = <DataContract as FromProof<platform::GetDataContractRequest>>::maybe_from_proof(
5021 request,
5022 response,
5023 Network::Testnet,
5024 default_platform_version(),
5025 &provider,
5026 )
5027 .unwrap_err();
5028 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5029 }
5030
5031 #[test]
5032 fn data_contract_no_proof_when_response_empty() {
5033 let request = platform::GetDataContractRequest::default();
5034 let response = platform::GetDataContractResponse::default();
5035 let provider = unreachable_provider();
5036 let err = <DataContract as FromProof<platform::GetDataContractRequest>>::maybe_from_proof(
5037 request,
5038 response,
5039 Network::Testnet,
5040 default_platform_version(),
5041 &provider,
5042 )
5043 .unwrap_err();
5044 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5045 }
5046
5047 #[test]
5048 fn data_contract_with_serialization_rejects_bad_id_length() {
5049 use dapi_grpc::platform::v0::get_data_contract_request::GetDataContractRequestV0;
5051 use platform::get_data_contract_response::{
5052 get_data_contract_response_v0::Result as V0Result, GetDataContractResponseV0, Version,
5053 };
5054 let response = platform::GetDataContractResponse {
5055 version: Some(Version::V0(GetDataContractResponseV0 {
5056 result: Some(V0Result::Proof(Proof::default())),
5057 metadata: Some(ResponseMetadata::default()),
5058 })),
5059 };
5060 let request: platform::GetDataContractRequest = GetDataContractRequestV0 {
5061 id: vec![0u8; 5],
5062 prove: true,
5063 }
5064 .into();
5065 let provider = unreachable_provider();
5066 let err =
5067 <(DataContract, Vec<u8>) as FromProof<platform::GetDataContractRequest>>::maybe_from_proof(
5068 request,
5069 response,
5070 Network::Testnet,
5071 default_platform_version(),
5072 &provider,
5073 )
5074 .unwrap_err();
5075 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5076 }
5077
5078 #[test]
5079 fn data_contract_history_rejects_bad_id_length() {
5080 use dapi_grpc::platform::v0::get_data_contract_history_request::GetDataContractHistoryRequestV0;
5081 use platform::get_data_contract_history_response::{
5082 get_data_contract_history_response_v0::Result as V0Result,
5083 GetDataContractHistoryResponseV0, Version,
5084 };
5085 let response = platform::GetDataContractHistoryResponse {
5086 version: Some(Version::V0(GetDataContractHistoryResponseV0 {
5087 result: Some(V0Result::Proof(Proof::default())),
5088 metadata: Some(ResponseMetadata::default()),
5089 })),
5090 };
5091 let request: platform::GetDataContractHistoryRequest = GetDataContractHistoryRequestV0 {
5092 id: vec![0u8; 5],
5093 limit: None,
5094 offset: None,
5095 start_at_ms: 0,
5096 prove: true,
5097 }
5098 .into();
5099 let provider = unreachable_provider();
5100 let err = <DataContractHistory as FromProof<
5101 platform::GetDataContractHistoryRequest,
5102 >>::maybe_from_proof(
5103 request,
5104 response,
5105 Network::Testnet,
5106 default_platform_version(),
5107 &provider,
5108 )
5109 .unwrap_err();
5110 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5111 }
5112
5113 #[test]
5114 fn data_contract_history_rejects_overflowing_limit() {
5115 use dapi_grpc::platform::v0::get_data_contract_history_request::GetDataContractHistoryRequestV0;
5116 use platform::get_data_contract_history_response::{
5117 get_data_contract_history_response_v0::Result as V0Result,
5118 GetDataContractHistoryResponseV0, Version,
5119 };
5120 let response = platform::GetDataContractHistoryResponse {
5121 version: Some(Version::V0(GetDataContractHistoryResponseV0 {
5122 result: Some(V0Result::Proof(Proof::default())),
5123 metadata: Some(ResponseMetadata::default()),
5124 })),
5125 };
5126 let request: platform::GetDataContractHistoryRequest = GetDataContractHistoryRequestV0 {
5127 id: vec![0u8; 32],
5128 limit: Some(100_000),
5129 offset: None,
5130 start_at_ms: 0,
5131 prove: true,
5132 }
5133 .into();
5134 let provider = unreachable_provider();
5135 let err = <DataContractHistory as FromProof<
5136 platform::GetDataContractHistoryRequest,
5137 >>::maybe_from_proof(
5138 request,
5139 response,
5140 Network::Testnet,
5141 default_platform_version(),
5142 &provider,
5143 )
5144 .unwrap_err();
5145 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5146 }
5147
5148 #[test]
5149 fn document_history_no_proof_when_response_empty() {
5150 let request = platform::GetDocumentHistoryRequest::default();
5151 let response = platform::GetDocumentHistoryResponse::default();
5152 let provider = unreachable_provider();
5153
5154 let err = document_history_error(request, response, &provider);
5155
5156 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5157 }
5158
5159 #[test]
5160 fn document_history_empty_response_metadata() {
5161 use platform::get_document_history_response::{
5162 get_document_history_response_v0::Result as V0Result, GetDocumentHistoryResponseV0,
5163 Version,
5164 };
5165 let request = platform::GetDocumentHistoryRequest::default();
5166 let response = platform::GetDocumentHistoryResponse {
5167 version: Some(Version::V0(GetDocumentHistoryResponseV0 {
5168 result: Some(V0Result::Proof(Proof::default())),
5169 metadata: None,
5170 })),
5171 };
5172 let provider = unreachable_provider();
5173
5174 let err = document_history_error(request, response, &provider);
5175
5176 assert!(matches!(err, Error::EmptyResponseMetadata), "got: {err:?}");
5177 }
5178
5179 #[test]
5180 fn document_history_empty_version() {
5181 let request = platform::GetDocumentHistoryRequest { version: None };
5182 let response = document_history_response_with_proof_and_metadata();
5183 let provider = unreachable_provider();
5184
5185 let err = document_history_error(request, response, &provider);
5186
5187 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5188 }
5189
5190 #[test]
5191 fn document_history_rejects_bad_contract_id_length() {
5192 let request =
5193 document_history_request(vec![0u8; 5], "niceDocument", vec![1u8; 32], None, None);
5194 let response = document_history_response_with_proof_and_metadata();
5195 let provider = unreachable_provider();
5196
5197 let err = document_history_error(request, response, &provider);
5198
5199 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5200 }
5201
5202 #[test]
5203 fn document_history_rejects_bad_document_id_length() {
5204 let request =
5205 document_history_request(vec![0u8; 32], "niceDocument", vec![1u8; 5], None, None);
5206 let response = document_history_response_with_proof_and_metadata();
5207 let provider = unreachable_provider();
5208
5209 let err = document_history_error(request, response, &provider);
5210
5211 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5212 }
5213
5214 #[test]
5215 fn document_history_rejects_overflowing_limit() {
5216 let request = document_history_request(
5217 vec![0u8; 32],
5218 "niceDocument",
5219 vec![1u8; 32],
5220 Some(100_000),
5221 None,
5222 );
5223 let response = document_history_response_with_proof_and_metadata();
5224 let provider = unreachable_provider();
5225
5226 let err = document_history_error(request, response, &provider);
5227
5228 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5229 }
5230
5231 #[test]
5232 fn document_history_returns_not_found_when_contract_provider_misses() {
5233 let request =
5234 document_history_request(vec![0u8; 32], "niceDocument", vec![1u8; 32], None, None);
5235 let response = document_history_response_with_proof_and_metadata();
5236 let provider = NoDataContractProvider;
5237
5238 let err = document_history_error(request, response, &provider);
5239
5240 assert!(matches!(err, Error::NotFound), "got: {err:?}");
5241 }
5242
5243 #[test]
5244 fn document_history_rejects_unknown_document_type() {
5245 let data_contract = dpp::tests::fixtures::get_data_contract_fixture(
5246 None,
5247 0,
5248 default_platform_version().protocol_version,
5249 )
5250 .data_contract_owned();
5251 let contract_id = data_contract.id().to_vec();
5252 let provider = StaticDataContractProvider {
5253 data_contract: std::sync::Arc::new(data_contract),
5254 };
5255 let request =
5256 document_history_request(contract_id, "missingDocument", vec![1u8; 32], None, None);
5257 let response = document_history_response_with_proof_and_metadata();
5258
5259 let err = document_history_error(request, response, &provider);
5260
5261 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5262 }
5263
5264 #[test]
5265 fn address_info_rejects_bad_address_bytes() {
5266 use dapi_grpc::platform::v0::get_address_info_request::GetAddressInfoRequestV0;
5268 use platform::get_address_info_response::{
5269 get_address_info_response_v0::Result as V0Result, GetAddressInfoResponseV0, Version,
5270 };
5271 let response = platform::GetAddressInfoResponse {
5272 version: Some(Version::V0(GetAddressInfoResponseV0 {
5273 result: Some(V0Result::Proof(Proof::default())),
5274 metadata: Some(ResponseMetadata::default()),
5275 })),
5276 };
5277 let request: platform::GetAddressInfoRequest = GetAddressInfoRequestV0 {
5278 address: vec![0u8; 3], prove: true,
5280 }
5281 .into();
5282 let provider = unreachable_provider();
5283 let err = <AddressInfo as FromProof<platform::GetAddressInfoRequest>>::maybe_from_proof(
5284 request,
5285 response,
5286 Network::Testnet,
5287 default_platform_version(),
5288 &provider,
5289 )
5290 .unwrap_err();
5291 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5292 }
5293
5294 #[test]
5295 fn addresses_infos_rejects_bad_address_bytes() {
5296 use dapi_grpc::platform::v0::get_addresses_infos_request::GetAddressesInfosRequestV0;
5297 use platform::get_addresses_infos_response::{
5298 get_addresses_infos_response_v0::Result as V0Result, GetAddressesInfosResponseV0,
5299 Version,
5300 };
5301 let response = platform::GetAddressesInfosResponse {
5302 version: Some(Version::V0(GetAddressesInfosResponseV0 {
5303 result: Some(V0Result::Proof(Proof::default())),
5304 metadata: Some(ResponseMetadata::default()),
5305 })),
5306 };
5307 let request: platform::GetAddressesInfosRequest = GetAddressesInfosRequestV0 {
5308 addresses: vec![vec![0u8; 3]],
5309 prove: true,
5310 }
5311 .into();
5312 let provider = unreachable_provider();
5313 let err =
5314 <AddressInfos as FromProof<platform::GetAddressesInfosRequest>>::maybe_from_proof(
5315 request,
5316 response,
5317 Network::Testnet,
5318 default_platform_version(),
5319 &provider,
5320 )
5321 .unwrap_err();
5322 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5323 }
5324
5325 #[test]
5326 fn addresses_trunk_state_grove_no_proof() {
5327 let response = platform::GetAddressesTrunkStateResponse::default();
5330 let request = platform::GetAddressesTrunkStateRequest::default();
5331 let provider = unreachable_provider();
5332 let err = <GroveTrunkQueryResult as FromProof<
5333 platform::GetAddressesTrunkStateRequest,
5334 >>::maybe_from_proof(
5335 request,
5336 response,
5337 Network::Testnet,
5338 default_platform_version(),
5339 &provider,
5340 )
5341 .unwrap_err();
5342 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5343 }
5344
5345 #[test]
5346 fn platform_address_trunk_state_no_proof() {
5347 let response = platform::GetAddressesTrunkStateResponse::default();
5349 let request = platform::GetAddressesTrunkStateRequest::default();
5350 let provider = unreachable_provider();
5351 let err = <PlatformAddressTrunkState as FromProof<
5352 platform::GetAddressesTrunkStateRequest,
5353 >>::maybe_from_proof(
5354 request,
5355 response,
5356 Network::Testnet,
5357 default_platform_version(),
5358 &provider,
5359 )
5360 .unwrap_err();
5361 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5362 }
5363
5364 #[test]
5365 fn epochs_info_empty_version_none() {
5366 use platform::get_epochs_info_response::{
5367 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
5368 };
5369 let response = platform::GetEpochsInfoResponse {
5370 version: Some(Version::V0(GetEpochsInfoResponseV0 {
5371 result: Some(V0Result::Proof(Proof::default())),
5372 metadata: Some(ResponseMetadata::default()),
5373 })),
5374 };
5375 let request = platform::GetEpochsInfoRequest { version: None };
5376 let provider = unreachable_provider();
5377 let err =
5378 <ExtendedEpochInfos as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
5379 request,
5380 response,
5381 Network::Testnet,
5382 default_platform_version(),
5383 &provider,
5384 )
5385 .unwrap_err();
5386 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5387 }
5388
5389 #[test]
5390 fn epochs_info_rejects_overflowing_count() {
5391 use dapi_grpc::platform::v0::get_epochs_info_request::GetEpochsInfoRequestV0;
5393 use platform::get_epochs_info_response::{
5394 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
5395 };
5396 let response = platform::GetEpochsInfoResponse {
5397 version: Some(Version::V0(GetEpochsInfoResponseV0 {
5398 result: Some(V0Result::Proof(Proof::default())),
5399 metadata: Some(default_metadata_with_epoch(10)),
5400 })),
5401 };
5402 let request = platform::GetEpochsInfoRequest {
5403 version: Some(platform::get_epochs_info_request::Version::V0(
5404 GetEpochsInfoRequestV0 {
5405 start_epoch: Some(0),
5406 count: 100_000,
5407 ascending: true,
5408 prove: true,
5409 },
5410 )),
5411 };
5412 let provider = unreachable_provider();
5413 let err =
5414 <ExtendedEpochInfos as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
5415 request,
5416 response,
5417 Network::Testnet,
5418 default_platform_version(),
5419 &provider,
5420 )
5421 .unwrap_err();
5422 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5423 }
5424
5425 #[test]
5426 fn epochs_info_ascending_without_start_ignores_metadata_epoch() {
5427 use dapi_grpc::platform::v0::get_epochs_info_request::GetEpochsInfoRequestV0;
5430 use platform::get_epochs_info_response::{
5431 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
5432 };
5433 let response = platform::GetEpochsInfoResponse {
5434 version: Some(Version::V0(GetEpochsInfoResponseV0 {
5435 result: Some(V0Result::Proof(Proof::default())),
5436 metadata: Some(default_metadata_with_epoch(70_000)),
5437 })),
5438 };
5439 let request = platform::GetEpochsInfoRequest {
5440 version: Some(platform::get_epochs_info_request::Version::V0(
5441 GetEpochsInfoRequestV0 {
5442 start_epoch: None,
5443 count: 1,
5444 ascending: true,
5445 prove: true,
5446 },
5447 )),
5448 };
5449 let provider = unreachable_provider();
5450 let err =
5451 <ExtendedEpochInfos as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
5452 request,
5453 response,
5454 Network::Testnet,
5455 default_platform_version(),
5456 &provider,
5457 )
5458 .unwrap_err();
5459 assert!(
5460 !matches!(err, Error::RequestError { .. }),
5461 "metadata epoch unexpectedly influenced the request: {err:?}"
5462 );
5463 }
5464
5465 #[test]
5466 fn epochs_info_descending_requires_explicit_start_epoch() {
5467 use dapi_grpc::platform::v0::get_epochs_info_request::GetEpochsInfoRequestV0;
5468 use platform::get_epochs_info_response::{
5469 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
5470 };
5471 let response = platform::GetEpochsInfoResponse {
5472 version: Some(Version::V0(GetEpochsInfoResponseV0 {
5473 result: Some(V0Result::Proof(Proof::default())),
5474 metadata: Some(default_metadata_with_epoch(10)),
5475 })),
5476 };
5477 let request = platform::GetEpochsInfoRequest {
5478 version: Some(platform::get_epochs_info_request::Version::V0(
5479 GetEpochsInfoRequestV0 {
5480 start_epoch: None,
5481 count: 1,
5482 ascending: false,
5483 prove: true,
5484 },
5485 )),
5486 };
5487 let provider = unreachable_provider();
5488
5489 let err =
5490 <ExtendedEpochInfos as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
5491 request,
5492 response,
5493 Network::Testnet,
5494 default_platform_version(),
5495 &provider,
5496 )
5497 .unwrap_err();
5498
5499 match err {
5500 Error::RequestError { error } => assert!(error.contains("explicit start epoch")),
5501 other => panic!("expected explicit-epoch request error, got: {other:?}"),
5502 }
5503 }
5504
5505 #[test]
5506 fn epochs_info_descending_with_explicit_max_start_passes_guard() {
5507 use dapi_grpc::platform::v0::get_epochs_info_request::GetEpochsInfoRequestV0;
5514 use dpp::block::epoch::MAX_EPOCH;
5515 use platform::get_epochs_info_response::{
5516 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
5517 };
5518 let response = platform::GetEpochsInfoResponse {
5519 version: Some(Version::V0(GetEpochsInfoResponseV0 {
5520 result: Some(V0Result::Proof(Proof::default())),
5521 metadata: Some(default_metadata_with_epoch(10)),
5522 })),
5523 };
5524 let request = platform::GetEpochsInfoRequest {
5525 version: Some(platform::get_epochs_info_request::Version::V0(
5526 GetEpochsInfoRequestV0 {
5527 start_epoch: Some(MAX_EPOCH as u32),
5528 count: 1,
5529 ascending: false,
5530 prove: true,
5531 },
5532 )),
5533 };
5534 let provider = unreachable_provider();
5535
5536 let err =
5537 <ExtendedEpochInfos as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
5538 request,
5539 response,
5540 Network::Testnet,
5541 default_platform_version(),
5542 &provider,
5543 )
5544 .unwrap_err();
5545
5546 assert!(
5547 !matches!(err, Error::RequestError { .. }),
5548 "explicit-start descending query must pass the guard, got: {err:?}"
5549 );
5550 }
5551
5552 #[test]
5553 fn extended_epoch_info_single_bubbles_empty_version() {
5554 use platform::get_epochs_info_response::{
5556 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
5557 };
5558 let response = platform::GetEpochsInfoResponse {
5559 version: Some(Version::V0(GetEpochsInfoResponseV0 {
5560 result: Some(V0Result::Proof(Proof::default())),
5561 metadata: Some(ResponseMetadata::default()),
5562 })),
5563 };
5564 let request = platform::GetEpochsInfoRequest { version: None };
5565 let provider = unreachable_provider();
5566 let err =
5567 <ExtendedEpochInfo as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
5568 request,
5569 response,
5570 Network::Testnet,
5571 default_platform_version(),
5572 &provider,
5573 )
5574 .unwrap_err();
5575 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5576 }
5577
5578 #[test]
5579 fn finalized_epoch_infos_rejects_overflowing_start_index() {
5580 use dapi_grpc::platform::v0::get_finalized_epoch_infos_request::GetFinalizedEpochInfosRequestV0;
5581 use platform::get_finalized_epoch_infos_response::{
5582 get_finalized_epoch_infos_response_v0::Result as V0Result,
5583 GetFinalizedEpochInfosResponseV0, Version,
5584 };
5585 let response = platform::GetFinalizedEpochInfosResponse {
5586 version: Some(Version::V0(GetFinalizedEpochInfosResponseV0 {
5587 result: Some(V0Result::Proof(Proof::default())),
5588 metadata: Some(ResponseMetadata::default()),
5589 })),
5590 };
5591 let request: platform::GetFinalizedEpochInfosRequest = GetFinalizedEpochInfosRequestV0 {
5592 start_epoch_index: 100_000,
5593 start_epoch_index_included: true,
5594 end_epoch_index: 1,
5595 end_epoch_index_included: true,
5596 prove: true,
5597 }
5598 .into();
5599 let provider = unreachable_provider();
5600 let err = <FinalizedEpochInfos as FromProof<
5601 platform::GetFinalizedEpochInfosRequest,
5602 >>::maybe_from_proof(
5603 request,
5604 response,
5605 Network::Testnet,
5606 default_platform_version(),
5607 &provider,
5608 )
5609 .unwrap_err();
5610 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5611 }
5612
5613 #[test]
5614 fn finalized_epoch_infos_rejects_overflowing_end_index() {
5615 use dapi_grpc::platform::v0::get_finalized_epoch_infos_request::GetFinalizedEpochInfosRequestV0;
5616 use platform::get_finalized_epoch_infos_response::{
5617 get_finalized_epoch_infos_response_v0::Result as V0Result,
5618 GetFinalizedEpochInfosResponseV0, Version,
5619 };
5620 let response = platform::GetFinalizedEpochInfosResponse {
5621 version: Some(Version::V0(GetFinalizedEpochInfosResponseV0 {
5622 result: Some(V0Result::Proof(Proof::default())),
5623 metadata: Some(ResponseMetadata::default()),
5624 })),
5625 };
5626 let request: platform::GetFinalizedEpochInfosRequest = GetFinalizedEpochInfosRequestV0 {
5627 start_epoch_index: 1,
5628 start_epoch_index_included: true,
5629 end_epoch_index: 100_000,
5630 end_epoch_index_included: true,
5631 prove: true,
5632 }
5633 .into();
5634 let provider = unreachable_provider();
5635 let err = <FinalizedEpochInfos as FromProof<
5636 platform::GetFinalizedEpochInfosRequest,
5637 >>::maybe_from_proof(
5638 request,
5639 response,
5640 Network::Testnet,
5641 default_platform_version(),
5642 &provider,
5643 )
5644 .unwrap_err();
5645 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5646 }
5647
5648 #[test]
5649 fn upgrade_state_no_proof_when_response_empty() {
5650 let response = GetProtocolVersionUpgradeStateResponse::default();
5652 let request = GetProtocolVersionUpgradeStateRequest::default();
5653 let provider = unreachable_provider();
5654 let err = <ProtocolVersionUpgrades as FromProof<
5655 GetProtocolVersionUpgradeStateRequest,
5656 >>::maybe_from_proof(
5657 request,
5658 response,
5659 Network::Testnet,
5660 default_platform_version(),
5661 &provider,
5662 )
5663 .unwrap_err();
5664 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5665 }
5666
5667 #[test]
5668 fn upgrade_vote_status_no_proof_when_response_empty() {
5669 let response = GetProtocolVersionUpgradeVoteStatusResponse::default();
5670 let request = GetProtocolVersionUpgradeVoteStatusRequest::default();
5671 let provider = unreachable_provider();
5672 let err = <MasternodeProtocolVotes as FromProof<
5673 GetProtocolVersionUpgradeVoteStatusRequest,
5674 >>::maybe_from_proof(
5675 request,
5676 response,
5677 Network::Testnet,
5678 default_platform_version(),
5679 &provider,
5680 )
5681 .unwrap_err();
5682 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5683 }
5684
5685 #[test]
5686 fn upgrade_vote_status_rejects_overflowing_count() {
5687 use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_request::GetProtocolVersionUpgradeVoteStatusRequestV0;
5688 use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_response::{
5689 get_protocol_version_upgrade_vote_status_response_v0::Result as V0Result,
5690 GetProtocolVersionUpgradeVoteStatusResponseV0, Version,
5691 };
5692
5693 let response = GetProtocolVersionUpgradeVoteStatusResponse {
5694 version: Some(Version::V0(GetProtocolVersionUpgradeVoteStatusResponseV0 {
5695 result: Some(V0Result::Proof(Proof::default())),
5696 metadata: Some(ResponseMetadata::default()),
5697 })),
5698 };
5699 let request: GetProtocolVersionUpgradeVoteStatusRequest =
5701 GetProtocolVersionUpgradeVoteStatusRequestV0 {
5702 start_pro_tx_hash: vec![],
5703 count: 100_000,
5704 prove: true,
5705 }
5706 .into();
5707 let provider = unreachable_provider();
5708 let err = <MasternodeProtocolVotes as FromProof<
5709 GetProtocolVersionUpgradeVoteStatusRequest,
5710 >>::maybe_from_proof(
5711 request,
5712 response,
5713 Network::Testnet,
5714 default_platform_version(),
5715 &provider,
5716 )
5717 .unwrap_err();
5718 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5719 }
5720
5721 #[test]
5722 fn path_elements_empty_version_when_no_version() {
5723 use platform::get_path_elements_response::{
5725 get_path_elements_response_v0::Result as V0Result, GetPathElementsResponseV0, Version,
5726 };
5727 let response = GetPathElementsResponse {
5728 version: Some(Version::V0(GetPathElementsResponseV0 {
5729 result: Some(V0Result::Proof(Proof::default())),
5730 metadata: Some(ResponseMetadata::default()),
5731 })),
5732 };
5733 let request = GetPathElementsRequest { version: None };
5734 let provider = unreachable_provider();
5735 let err = <Elements as FromProof<GetPathElementsRequest>>::maybe_from_proof(
5736 request,
5737 response,
5738 Network::Testnet,
5739 default_platform_version(),
5740 &provider,
5741 )
5742 .unwrap_err();
5743 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5744 }
5745
5746 #[test]
5747 fn identities_contract_keys_rejects_bad_identity_id() {
5748 use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0;
5749 use platform::get_identities_contract_keys_response::{
5750 get_identities_contract_keys_response_v0::Result as V0Result,
5751 GetIdentitiesContractKeysResponseV0, Version,
5752 };
5753 let response = platform::GetIdentitiesContractKeysResponse {
5754 version: Some(Version::V0(GetIdentitiesContractKeysResponseV0 {
5755 result: Some(V0Result::Proof(Proof::default())),
5756 metadata: Some(ResponseMetadata::default()),
5757 })),
5758 };
5759 let request: platform::GetIdentitiesContractKeysRequest =
5760 GetIdentitiesContractKeysRequestV0 {
5761 identities_ids: vec![vec![0u8; 5]], contract_id: vec![0u8; 32],
5763 document_type_name: None,
5764 purposes: vec![0],
5765 prove: true,
5766 }
5767 .into();
5768 let provider = unreachable_provider();
5769 let err = <IdentitiesContractKeys as FromProof<
5770 platform::GetIdentitiesContractKeysRequest,
5771 >>::maybe_from_proof(
5772 request,
5773 response,
5774 Network::Testnet,
5775 default_platform_version(),
5776 &provider,
5777 )
5778 .unwrap_err();
5779 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5780 }
5781
5782 #[test]
5783 fn identities_contract_keys_rejects_bad_contract_id() {
5784 use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0;
5785 use platform::get_identities_contract_keys_response::{
5786 get_identities_contract_keys_response_v0::Result as V0Result,
5787 GetIdentitiesContractKeysResponseV0, Version,
5788 };
5789 let response = platform::GetIdentitiesContractKeysResponse {
5790 version: Some(Version::V0(GetIdentitiesContractKeysResponseV0 {
5791 result: Some(V0Result::Proof(Proof::default())),
5792 metadata: Some(ResponseMetadata::default()),
5793 })),
5794 };
5795 let request: platform::GetIdentitiesContractKeysRequest =
5796 GetIdentitiesContractKeysRequestV0 {
5797 identities_ids: vec![vec![0u8; 32]],
5798 contract_id: vec![0u8; 5], document_type_name: None,
5800 purposes: vec![0],
5801 prove: true,
5802 }
5803 .into();
5804 let provider = unreachable_provider();
5805 let err = <IdentitiesContractKeys as FromProof<
5806 platform::GetIdentitiesContractKeysRequest,
5807 >>::maybe_from_proof(
5808 request,
5809 response,
5810 Network::Testnet,
5811 default_platform_version(),
5812 &provider,
5813 )
5814 .unwrap_err();
5815 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5816 }
5817
5818 #[test]
5819 fn identities_contract_keys_rejects_bad_purpose() {
5820 use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0;
5821 use platform::get_identities_contract_keys_response::{
5822 get_identities_contract_keys_response_v0::Result as V0Result,
5823 GetIdentitiesContractKeysResponseV0, Version,
5824 };
5825 let response = platform::GetIdentitiesContractKeysResponse {
5826 version: Some(Version::V0(GetIdentitiesContractKeysResponseV0 {
5827 result: Some(V0Result::Proof(Proof::default())),
5828 metadata: Some(ResponseMetadata::default()),
5829 })),
5830 };
5831 let request: platform::GetIdentitiesContractKeysRequest =
5833 GetIdentitiesContractKeysRequestV0 {
5834 identities_ids: vec![vec![0u8; 32]],
5835 contract_id: vec![0u8; 32],
5836 document_type_name: None,
5837 purposes: vec![250],
5838 prove: true,
5839 }
5840 .into();
5841 let provider = unreachable_provider();
5842 let err = <IdentitiesContractKeys as FromProof<
5843 platform::GetIdentitiesContractKeysRequest,
5844 >>::maybe_from_proof(
5845 request,
5846 response,
5847 Network::Testnet,
5848 default_platform_version(),
5849 &provider,
5850 )
5851 .unwrap_err();
5852 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5853 }
5854
5855 #[test]
5856 fn prefunded_balance_empty_version_on_request_version_none() {
5857 use platform::get_prefunded_specialized_balance_response::{
5859 get_prefunded_specialized_balance_response_v0::Result as V0Result,
5860 GetPrefundedSpecializedBalanceResponseV0, Version,
5861 };
5862 let response = platform::GetPrefundedSpecializedBalanceResponse {
5863 version: Some(Version::V0(GetPrefundedSpecializedBalanceResponseV0 {
5864 result: Some(V0Result::Proof(Proof::default())),
5865 metadata: Some(ResponseMetadata::default()),
5866 })),
5867 };
5868 let request = platform::GetPrefundedSpecializedBalanceRequest { version: None };
5869 let provider = unreachable_provider();
5870 let err = <PrefundedSpecializedBalance as FromProof<
5871 platform::GetPrefundedSpecializedBalanceRequest,
5872 >>::maybe_from_proof(
5873 request,
5874 response,
5875 Network::Testnet,
5876 default_platform_version(),
5877 &provider,
5878 )
5879 .unwrap_err();
5880 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5881 }
5882
5883 #[test]
5884 fn evonodes_proposed_epoch_blocks_by_ids_empty_version() {
5885 use platform::get_evonodes_proposed_epoch_blocks_response::{
5886 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
5887 GetEvonodesProposedEpochBlocksResponseV0, Version,
5888 };
5889 let response = platform::GetEvonodesProposedEpochBlocksResponse {
5890 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
5891 result: Some(V0Result::Proof(Proof::default())),
5892 metadata: Some(ResponseMetadata::default()),
5893 })),
5894 };
5895 let request = platform::GetEvonodesProposedEpochBlocksByIdsRequest { version: None };
5896 let provider = unreachable_provider();
5897 let err = <ProposerBlockCounts as FromProof<
5898 platform::GetEvonodesProposedEpochBlocksByIdsRequest,
5899 >>::maybe_from_proof(
5900 request,
5901 response,
5902 Network::Testnet,
5903 default_platform_version(),
5904 &provider,
5905 )
5906 .unwrap_err();
5907 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5908 }
5909
5910 #[test]
5911 fn evonodes_proposed_epoch_blocks_by_ids_rejects_overflowing_epoch() {
5912 use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_ids_request::GetEvonodesProposedEpochBlocksByIdsRequestV0;
5914 use platform::get_evonodes_proposed_epoch_blocks_response::{
5915 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
5916 GetEvonodesProposedEpochBlocksResponseV0, Version,
5917 };
5918 let response = platform::GetEvonodesProposedEpochBlocksResponse {
5919 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
5920 result: Some(V0Result::Proof(Proof::default())),
5921 metadata: Some(default_metadata_with_epoch(1)),
5922 })),
5923 };
5924 let request: platform::GetEvonodesProposedEpochBlocksByIdsRequest =
5925 GetEvonodesProposedEpochBlocksByIdsRequestV0 {
5926 epoch: Some(100_000),
5927 ids: vec![],
5928 prove: true,
5929 }
5930 .into();
5931 let provider = unreachable_provider();
5932 let err = <ProposerBlockCounts as FromProof<
5933 platform::GetEvonodesProposedEpochBlocksByIdsRequest,
5934 >>::maybe_from_proof(
5935 request,
5936 response,
5937 Network::Testnet,
5938 default_platform_version(),
5939 &provider,
5940 )
5941 .unwrap_err();
5942 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5943 }
5944
5945 #[test]
5946 fn evonodes_proposed_epoch_blocks_by_ids_requires_explicit_epoch() {
5947 use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_ids_request::GetEvonodesProposedEpochBlocksByIdsRequestV0;
5950 use platform::get_evonodes_proposed_epoch_blocks_response::{
5951 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
5952 GetEvonodesProposedEpochBlocksResponseV0, Version,
5953 };
5954 let response = platform::GetEvonodesProposedEpochBlocksResponse {
5955 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
5956 result: Some(V0Result::Proof(Proof::default())),
5957 metadata: Some(default_metadata_with_epoch(99_999)),
5958 })),
5959 };
5960 let request: platform::GetEvonodesProposedEpochBlocksByIdsRequest =
5961 GetEvonodesProposedEpochBlocksByIdsRequestV0 {
5962 epoch: None,
5963 ids: vec![],
5964 prove: true,
5965 }
5966 .into();
5967 let provider = unreachable_provider();
5968 let err = <ProposerBlockCounts as FromProof<
5969 platform::GetEvonodesProposedEpochBlocksByIdsRequest,
5970 >>::maybe_from_proof(
5971 request,
5972 response,
5973 Network::Testnet,
5974 default_platform_version(),
5975 &provider,
5976 )
5977 .unwrap_err();
5978 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5979 }
5980
5981 #[test]
5982 fn evonodes_proposed_epoch_blocks_by_range_empty_version() {
5983 use platform::get_evonodes_proposed_epoch_blocks_response::{
5984 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
5985 GetEvonodesProposedEpochBlocksResponseV0, Version,
5986 };
5987 let response = platform::GetEvonodesProposedEpochBlocksResponse {
5988 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
5989 result: Some(V0Result::Proof(Proof::default())),
5990 metadata: Some(ResponseMetadata::default()),
5991 })),
5992 };
5993 let request = platform::GetEvonodesProposedEpochBlocksByRangeRequest { version: None };
5994 let provider = unreachable_provider();
5995 let err = <ProposerBlockCounts as FromProof<
5996 platform::GetEvonodesProposedEpochBlocksByRangeRequest,
5997 >>::maybe_from_proof(
5998 request,
5999 response,
6000 Network::Testnet,
6001 default_platform_version(),
6002 &provider,
6003 )
6004 .unwrap_err();
6005 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
6006 }
6007
6008 #[test]
6009 fn evonodes_proposed_epoch_blocks_by_range_requires_explicit_epoch() {
6010 use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::GetEvonodesProposedEpochBlocksByRangeRequestV0;
6011 use platform::get_evonodes_proposed_epoch_blocks_response::{
6012 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
6013 GetEvonodesProposedEpochBlocksResponseV0, Version,
6014 };
6015 let response = platform::GetEvonodesProposedEpochBlocksResponse {
6016 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
6017 result: Some(V0Result::Proof(Proof::default())),
6018 metadata: Some(default_metadata_with_epoch(99_999)),
6019 })),
6020 };
6021 let request: platform::GetEvonodesProposedEpochBlocksByRangeRequest =
6022 GetEvonodesProposedEpochBlocksByRangeRequestV0 {
6023 epoch: None,
6024 limit: None,
6025 start: None,
6026 prove: true,
6027 }
6028 .into();
6029 let provider = unreachable_provider();
6030 let err = <ProposerBlockCounts as FromProof<
6031 platform::GetEvonodesProposedEpochBlocksByRangeRequest,
6032 >>::maybe_from_proof(
6033 request,
6034 response,
6035 Network::Testnet,
6036 default_platform_version(),
6037 &provider,
6038 )
6039 .unwrap_err();
6040
6041 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
6042 }
6043
6044 #[test]
6045 fn evonodes_proposed_epoch_blocks_by_range_rejects_bad_start_after() {
6046 use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::{
6048 get_evonodes_proposed_epoch_blocks_by_range_request_v0::Start,
6049 GetEvonodesProposedEpochBlocksByRangeRequestV0,
6050 };
6051 use platform::get_evonodes_proposed_epoch_blocks_response::{
6052 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
6053 GetEvonodesProposedEpochBlocksResponseV0, Version,
6054 };
6055 let response = platform::GetEvonodesProposedEpochBlocksResponse {
6056 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
6057 result: Some(V0Result::Proof(Proof::default())),
6058 metadata: Some(default_metadata_with_epoch(1)),
6059 })),
6060 };
6061 let request: platform::GetEvonodesProposedEpochBlocksByRangeRequest =
6062 GetEvonodesProposedEpochBlocksByRangeRequestV0 {
6063 epoch: Some(1),
6064 limit: None,
6065 start: Some(Start::StartAfter(vec![0u8; 5])),
6066 prove: true,
6067 }
6068 .into();
6069 let provider = unreachable_provider();
6070 let err = <ProposerBlockCounts as FromProof<
6071 platform::GetEvonodesProposedEpochBlocksByRangeRequest,
6072 >>::maybe_from_proof(
6073 request,
6074 response,
6075 Network::Testnet,
6076 default_platform_version(),
6077 &provider,
6078 )
6079 .unwrap_err();
6080 assert!(matches!(err, Error::DriveError { .. }), "got: {err:?}");
6081 }
6082
6083 #[test]
6084 fn evonodes_proposed_epoch_blocks_by_range_rejects_bad_start_at() {
6085 use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::{
6087 get_evonodes_proposed_epoch_blocks_by_range_request_v0::Start,
6088 GetEvonodesProposedEpochBlocksByRangeRequestV0,
6089 };
6090 use platform::get_evonodes_proposed_epoch_blocks_response::{
6091 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
6092 GetEvonodesProposedEpochBlocksResponseV0, Version,
6093 };
6094 let response = platform::GetEvonodesProposedEpochBlocksResponse {
6095 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
6096 result: Some(V0Result::Proof(Proof::default())),
6097 metadata: Some(default_metadata_with_epoch(1)),
6098 })),
6099 };
6100 let request: platform::GetEvonodesProposedEpochBlocksByRangeRequest =
6101 GetEvonodesProposedEpochBlocksByRangeRequestV0 {
6102 epoch: Some(1),
6103 limit: None,
6104 start: Some(Start::StartAt(vec![0u8; 4])),
6105 prove: true,
6106 }
6107 .into();
6108 let provider = unreachable_provider();
6109 let err = <ProposerBlockCounts as FromProof<
6110 platform::GetEvonodesProposedEpochBlocksByRangeRequest,
6111 >>::maybe_from_proof(
6112 request,
6113 response,
6114 Network::Testnet,
6115 default_platform_version(),
6116 &provider,
6117 )
6118 .unwrap_err();
6119 assert!(matches!(err, Error::DriveError { .. }), "got: {err:?}");
6120 }
6121
6122 #[test]
6123 fn evonodes_proposed_epoch_blocks_by_range_rejects_overflow_limit() {
6124 use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::GetEvonodesProposedEpochBlocksByRangeRequestV0;
6125 use platform::get_evonodes_proposed_epoch_blocks_response::{
6126 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
6127 GetEvonodesProposedEpochBlocksResponseV0, Version,
6128 };
6129 let response = platform::GetEvonodesProposedEpochBlocksResponse {
6130 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
6131 result: Some(V0Result::Proof(Proof::default())),
6132 metadata: Some(default_metadata_with_epoch(1)),
6133 })),
6134 };
6135 let request: platform::GetEvonodesProposedEpochBlocksByRangeRequest =
6136 GetEvonodesProposedEpochBlocksByRangeRequestV0 {
6137 epoch: Some(1),
6138 limit: Some(100_000),
6139 start: None,
6140 prove: true,
6141 }
6142 .into();
6143 let provider = unreachable_provider();
6144 let err = <ProposerBlockCounts as FromProof<
6145 platform::GetEvonodesProposedEpochBlocksByRangeRequest,
6146 >>::maybe_from_proof(
6147 request,
6148 response,
6149 Network::Testnet,
6150 default_platform_version(),
6151 &provider,
6152 )
6153 .unwrap_err();
6154 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
6155 }
6156
6157 #[test]
6158 fn shielded_pool_state_no_proof_when_response_empty() {
6159 let response = platform::GetShieldedPoolStateResponse::default();
6160 let request = platform::GetShieldedPoolStateRequest::default();
6161 let provider = unreachable_provider();
6162 let err = <ShieldedPoolState as FromProof<
6163 platform::GetShieldedPoolStateRequest,
6164 >>::maybe_from_proof(
6165 request,
6166 response,
6167 Network::Testnet,
6168 default_platform_version(),
6169 &provider,
6170 )
6171 .unwrap_err();
6172 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
6173 }
6174
6175 #[test]
6176 fn shielded_notes_count_no_proof_when_response_empty() {
6177 let response = platform::GetShieldedNotesCountResponse::default();
6178 let request = platform::GetShieldedNotesCountRequest::default();
6179 let provider = unreachable_provider();
6180 let err = <ShieldedNotesCount as FromProof<
6181 platform::GetShieldedNotesCountRequest,
6182 >>::maybe_from_proof(
6183 request,
6184 response,
6185 Network::Testnet,
6186 default_platform_version(),
6187 &provider,
6188 )
6189 .unwrap_err();
6190 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
6191 }
6192
6193 #[test]
6194 fn shielded_anchors_no_proof_when_response_empty() {
6195 let response = platform::GetShieldedAnchorsResponse::default();
6196 let request = platform::GetShieldedAnchorsRequest::default();
6197 let provider = unreachable_provider();
6198 let err =
6199 <ShieldedAnchors as FromProof<platform::GetShieldedAnchorsRequest>>::maybe_from_proof(
6200 request,
6201 response,
6202 Network::Testnet,
6203 default_platform_version(),
6204 &provider,
6205 )
6206 .unwrap_err();
6207 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
6208 }
6209
6210 #[test]
6211 fn most_recent_shielded_anchor_no_proof_when_response_empty() {
6212 let response = platform::GetMostRecentShieldedAnchorResponse::default();
6213 let request = platform::GetMostRecentShieldedAnchorRequest::default();
6214 let provider = unreachable_provider();
6215 let err = <MostRecentShieldedAnchor as FromProof<
6216 platform::GetMostRecentShieldedAnchorRequest,
6217 >>::maybe_from_proof(
6218 request,
6219 response,
6220 Network::Testnet,
6221 default_platform_version(),
6222 &provider,
6223 )
6224 .unwrap_err();
6225 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
6226 }
6227
6228 #[test]
6229 fn shielded_encrypted_notes_empty_version_on_request_version_none() {
6230 use platform::get_shielded_encrypted_notes_response::{
6231 get_shielded_encrypted_notes_response_v0::Result as V0Result,
6232 GetShieldedEncryptedNotesResponseV0, Version,
6233 };
6234 let response = platform::GetShieldedEncryptedNotesResponse {
6235 version: Some(Version::V0(GetShieldedEncryptedNotesResponseV0 {
6236 result: Some(V0Result::Proof(Proof::default())),
6237 metadata: Some(ResponseMetadata::default()),
6238 })),
6239 };
6240 let request = platform::GetShieldedEncryptedNotesRequest { version: None };
6241 let provider = unreachable_provider();
6242 let err = <ShieldedEncryptedNotes as FromProof<
6243 platform::GetShieldedEncryptedNotesRequest,
6244 >>::maybe_from_proof(
6245 request,
6246 response,
6247 Network::Testnet,
6248 default_platform_version(),
6249 &provider,
6250 )
6251 .unwrap_err();
6252 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
6253 }
6254
6255 #[test]
6256 fn shielded_encrypted_notes_no_proof_when_response_empty() {
6257 let response = platform::GetShieldedEncryptedNotesResponse::default();
6258 let request = platform::GetShieldedEncryptedNotesRequest::default();
6259 let provider = unreachable_provider();
6260 let err = <ShieldedEncryptedNotes as FromProof<
6261 platform::GetShieldedEncryptedNotesRequest,
6262 >>::maybe_from_proof(
6263 request,
6264 response,
6265 Network::Testnet,
6266 default_platform_version(),
6267 &provider,
6268 )
6269 .unwrap_err();
6270 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
6271 }
6272
6273 #[test]
6274 fn shielded_nullifiers_empty_version_on_request_version_none() {
6275 use platform::get_shielded_nullifiers_response::{
6276 get_shielded_nullifiers_response_v0::Result as V0Result,
6277 GetShieldedNullifiersResponseV0, Version,
6278 };
6279 let response = platform::GetShieldedNullifiersResponse {
6280 version: Some(Version::V0(GetShieldedNullifiersResponseV0 {
6281 result: Some(V0Result::Proof(Proof::default())),
6282 metadata: Some(ResponseMetadata::default()),
6283 })),
6284 };
6285 let request = platform::GetShieldedNullifiersRequest { version: None };
6286 let provider = unreachable_provider();
6287 let err = <ShieldedNullifierStatuses as FromProof<
6288 platform::GetShieldedNullifiersRequest,
6289 >>::maybe_from_proof(
6290 request,
6291 response,
6292 Network::Testnet,
6293 default_platform_version(),
6294 &provider,
6295 )
6296 .unwrap_err();
6297 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
6298 }
6299
6300 #[test]
6301 fn recent_address_balance_changes_empty_version() {
6302 use platform::get_recent_address_balance_changes_response::{
6303 get_recent_address_balance_changes_response_v0::Result as V0Result,
6304 GetRecentAddressBalanceChangesResponseV0, Version,
6305 };
6306 let response = platform::GetRecentAddressBalanceChangesResponse {
6307 version: Some(Version::V0(GetRecentAddressBalanceChangesResponseV0 {
6308 result: Some(V0Result::Proof(Proof::default())),
6309 metadata: Some(ResponseMetadata::default()),
6310 })),
6311 };
6312 let request = platform::GetRecentAddressBalanceChangesRequest { version: None };
6313 let provider = unreachable_provider();
6314 let err = <RecentAddressBalanceChanges as FromProof<
6315 platform::GetRecentAddressBalanceChangesRequest,
6316 >>::maybe_from_proof(
6317 request,
6318 response,
6319 Network::Testnet,
6320 default_platform_version(),
6321 &provider,
6322 )
6323 .unwrap_err();
6324 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
6325 }
6326
6327 #[test]
6328 fn recent_compacted_address_balance_changes_empty_version() {
6329 use platform::get_recent_compacted_address_balance_changes_response::{
6330 get_recent_compacted_address_balance_changes_response_v0::Result as V0Result,
6331 GetRecentCompactedAddressBalanceChangesResponseV0, Version,
6332 };
6333 let response = platform::GetRecentCompactedAddressBalanceChangesResponse {
6334 version: Some(Version::V0(
6335 GetRecentCompactedAddressBalanceChangesResponseV0 {
6336 result: Some(V0Result::Proof(Proof::default())),
6337 metadata: Some(ResponseMetadata::default()),
6338 },
6339 )),
6340 };
6341 let request = platform::GetRecentCompactedAddressBalanceChangesRequest { version: None };
6342 let provider = unreachable_provider();
6343 let err = <RecentCompactedAddressBalanceChanges as FromProof<
6344 platform::GetRecentCompactedAddressBalanceChangesRequest,
6345 >>::maybe_from_proof(
6346 request,
6347 response,
6348 Network::Testnet,
6349 default_platform_version(),
6350 &provider,
6351 )
6352 .unwrap_err();
6353 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
6354 }
6355
6356 #[test]
6357 fn vote_identity_vote_rejects_bad_identity_id_length() {
6358 use dapi_grpc::platform::v0::get_contested_resource_identity_votes_request::get_contested_resource_identity_votes_request_v0::StartAtVotePollIdInfo;
6360 use dapi_grpc::platform::v0::get_contested_resource_identity_votes_request::GetContestedResourceIdentityVotesRequestV0;
6361 let request: platform::GetContestedResourceIdentityVotesRequest =
6362 GetContestedResourceIdentityVotesRequestV0 {
6363 identity_id: vec![0u8; 5], limit: Some(1),
6365 offset: None,
6366 order_ascending: true,
6367 start_at_vote_poll_id_info: Some(StartAtVotePollIdInfo {
6368 start_at_poll_identifier: vec![1u8; 32],
6369 start_poll_identifier_included: true,
6370 }),
6371 prove: true,
6372 }
6373 .into();
6374 let response = platform::GetContestedResourceIdentityVotesResponse::default();
6375 let provider = unreachable_provider();
6376 let err = <Vote as FromProof<
6377 platform::GetContestedResourceIdentityVotesRequest,
6378 >>::maybe_from_proof(
6379 request,
6380 response,
6381 Network::Testnet,
6382 default_platform_version(),
6383 &provider,
6384 )
6385 .unwrap_err();
6386 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
6387 }
6388
6389 #[test]
6390 fn should_refuse_a_vote_request_that_does_not_start_at_its_vote_poll() {
6391 use dapi_grpc::platform::v0::get_contested_resource_identity_votes_request::get_contested_resource_identity_votes_request_v0::StartAtVotePollIdInfo;
6396 use dapi_grpc::platform::v0::get_contested_resource_identity_votes_request::GetContestedResourceIdentityVotesRequestV0;
6397 let request =
6398 |start_at_vote_poll_id_info| -> platform::GetContestedResourceIdentityVotesRequest {
6399 GetContestedResourceIdentityVotesRequestV0 {
6400 identity_id: vec![7u8; 32],
6401 limit: Some(1),
6402 offset: None,
6403 order_ascending: true,
6404 start_at_vote_poll_id_info,
6405 prove: true,
6406 }
6407 .into()
6408 };
6409
6410 let starting_at_its_vote_poll = request(Some(StartAtVotePollIdInfo {
6411 start_at_poll_identifier: vec![1u8; 32],
6412 start_poll_identifier_included: true,
6413 }));
6414 <Vote as FromProof<platform::GetContestedResourceIdentityVotesRequest>>::check_request(
6415 &starting_at_its_vote_poll,
6416 default_platform_version(),
6417 )
6418 .expect("a request starting at its vote poll is sent");
6419
6420 for start_at_vote_poll_id_info in [
6421 None,
6422 Some(StartAtVotePollIdInfo {
6423 start_at_poll_identifier: vec![1u8; 32],
6424 start_poll_identifier_included: false,
6425 }),
6426 Some(StartAtVotePollIdInfo {
6428 start_at_poll_identifier: vec![1u8; 5],
6429 start_poll_identifier_included: true,
6430 }),
6431 ] {
6432 let request = request(start_at_vote_poll_id_info);
6433 let err = <Vote as FromProof<
6434 platform::GetContestedResourceIdentityVotesRequest,
6435 >>::check_request(&request, default_platform_version())
6436 .unwrap_err();
6437 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
6438
6439 let provider = unreachable_provider();
6440 let err = <Vote as FromProof<
6441 platform::GetContestedResourceIdentityVotesRequest,
6442 >>::maybe_from_proof(
6443 request,
6444 platform::GetContestedResourceIdentityVotesResponse::default(),
6445 Network::Testnet,
6446 default_platform_version(),
6447 &provider,
6448 )
6449 .unwrap_err();
6450 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
6451 }
6452 }
6453
6454 #[test]
6455 fn vote_identity_vote_empty_version_on_request_none() {
6456 let request = platform::GetContestedResourceIdentityVotesRequest { version: None };
6457 let response = platform::GetContestedResourceIdentityVotesResponse::default();
6458 let provider = unreachable_provider();
6459 let err = <Vote as FromProof<
6460 platform::GetContestedResourceIdentityVotesRequest,
6461 >>::maybe_from_proof(
6462 request,
6463 response,
6464 Network::Testnet,
6465 default_platform_version(),
6466 &provider,
6467 )
6468 .unwrap_err();
6469 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
6470 }
6471
6472 #[test]
6473 fn resource_votes_by_identity_empty_version_via_try_from_request() {
6474 let request = platform::GetContestedResourceIdentityVotesRequest { version: None };
6477 let response = platform::GetContestedResourceIdentityVotesResponse::default();
6478 let provider = unreachable_provider();
6479 let err = <ResourceVotesByIdentity as FromProof<
6480 platform::GetContestedResourceIdentityVotesRequest,
6481 >>::maybe_from_proof(
6482 request,
6483 response,
6484 Network::Testnet,
6485 default_platform_version(),
6486 &provider,
6487 )
6488 .unwrap_err();
6489 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
6490 }
6491
6492 #[test]
6497 fn into_option_indexmap_empty_vs_with_entry_only_none() {
6498 use dpp::prelude::Identifier;
6499 let empty: RetrievedObjects<Identifier, u32> = RetrievedObjects::new();
6500 assert!(empty.into_option().is_none());
6501
6502 let mut map: RetrievedObjects<Identifier, u32> = RetrievedObjects::new();
6503 map.insert(Identifier::new([7u8; 32]), None);
6504 let mapped = map.into_option();
6505 assert!(
6506 mapped.is_some(),
6507 "absence markers must be preserved in into_option"
6508 );
6509 assert_eq!(mapped.unwrap().len(), 1);
6510 }
6511
6512 #[test]
6517 fn broadcast_state_transition_no_proof_when_response_empty() {
6518 let request = platform::BroadcastStateTransitionRequest {
6519 state_transition: vec![],
6520 };
6521 let response = platform::WaitForStateTransitionResultResponse::default();
6522 let provider = unreachable_provider();
6523 let err = <StateTransitionProofOutcome as FromProof<
6524 platform::BroadcastStateTransitionRequest,
6525 >>::maybe_from_proof(
6526 request,
6527 response,
6528 Network::Testnet,
6529 default_platform_version(),
6530 &provider,
6531 )
6532 .unwrap_err();
6533 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
6534 }
6535
6536 #[test]
6537 fn broadcast_state_transition_protocol_error_fires_before_metadata_check() {
6538 use platform::wait_for_state_transition_result_response::{
6551 wait_for_state_transition_result_response_v0::Result as V0Result, Version,
6552 WaitForStateTransitionResultResponseV0,
6553 };
6554 let request = platform::BroadcastStateTransitionRequest {
6555 state_transition: vec![0xFFu8; 4],
6556 };
6557 let response = platform::WaitForStateTransitionResultResponse {
6558 version: Some(Version::V0(WaitForStateTransitionResultResponseV0 {
6559 result: Some(V0Result::Proof(Proof::default())),
6560 metadata: None, })),
6562 };
6563 let provider = unreachable_provider();
6564 let err = <StateTransitionProofOutcome as FromProof<
6565 platform::BroadcastStateTransitionRequest,
6566 >>::maybe_from_proof(
6567 request,
6568 response,
6569 Network::Testnet,
6570 default_platform_version(),
6571 &provider,
6572 )
6573 .unwrap_err();
6574 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
6575 }
6576
6577 mod legacy_envelope_gate {
6581 use super::*;
6582 use crate::types::groups::{GroupActionSigners, GroupActions, Groups};
6583 use crate::types::identity_token_balance::{
6584 IdentitiesTokenBalances, IdentityTokenBalances,
6585 };
6586 use crate::types::token_info::{IdentitiesTokenInfos, IdentityTokenInfos};
6587 use crate::types::token_status::TokenStatuses;
6588 use dpp::balances::total_single_token_balance::TotalSingleTokenBalance;
6589 use dpp::data_contract::group::Group;
6590 use dpp::tokens::contract_info::TokenContractInfo;
6591
6592 fn legacy_proof() -> Proof {
6593 Proof {
6594 grovedb_proof: bincode::encode_to_vec(
6595 0u32,
6596 bincode::config::standard().with_big_endian(),
6597 )
6598 .expect("V0 envelope discriminant should encode"),
6599 ..Proof::default()
6600 }
6601 }
6602
6603 fn id(byte: u8) -> Vec<u8> {
6604 vec![byte; 32]
6605 }
6606
6607 macro_rules! request {
6608 ($module:ident, $v0:ident, $request:ident { $($field:ident: $value:expr),* $(,)? }) => {
6609 {
6610 #[allow(clippy::needless_update)]
6613 let body = platform::$module::$v0 {
6614 $($field: $value,)*
6615 ..Default::default()
6616 };
6617 platform::$request {
6618 version: Some(platform::$module::Version::V0(body)),
6619 }
6620 }
6621 };
6622 }
6623
6624 macro_rules! legacy_response {
6625 ($module:ident, $v0_module:ident, $v0:ident, $response:ident) => {
6626 platform::$response {
6627 version: Some(platform::$module::Version::V0(platform::$module::$v0 {
6628 result: Some(platform::$module::$v0_module::Result::Proof(legacy_proof())),
6629 metadata: Some(ResponseMetadata::default()),
6630 })),
6631 }
6632 };
6633 }
6634
6635 macro_rules! assert_rejects_legacy_envelope {
6636 ($target:ty, $request_type:ty, $request:expr, $response:expr) => {{
6637 let error = <$target as FromProof<$request_type>>::maybe_from_proof(
6638 $request,
6639 $response,
6640 Network::Testnet,
6641 PlatformVersion::latest(),
6642 &unreachable_provider(),
6643 )
6644 .expect_err(concat!(
6645 stringify!($target),
6646 " must reject a legacy envelope"
6647 ));
6648 assert!(
6649 matches!(
6650 error,
6651 Error::UnsupportedGroveDBProofVersion {
6652 version: 0,
6653 minimum: 1,
6654 ..
6655 }
6656 ),
6657 "{}: {error:?}",
6658 stringify!($target)
6659 );
6660 }};
6661 }
6662
6663 #[test]
6664 fn identity_queries() {
6665 assert_rejects_legacy_envelope!(
6666 Identity,
6667 platform::GetIdentityRequest,
6668 request!(
6669 get_identity_request,
6670 GetIdentityRequestV0,
6671 GetIdentityRequest {
6672 id: id(1),
6673 prove: true
6674 }
6675 ),
6676 legacy_response!(
6677 get_identity_response,
6678 get_identity_response_v0,
6679 GetIdentityResponseV0,
6680 GetIdentityResponse
6681 )
6682 );
6683 assert_rejects_legacy_envelope!(
6684 Identity,
6685 platform::GetIdentityByPublicKeyHashRequest,
6686 request!(
6687 get_identity_by_public_key_hash_request,
6688 GetIdentityByPublicKeyHashRequestV0,
6689 GetIdentityByPublicKeyHashRequest {
6690 public_key_hash: vec![1; 20],
6691 prove: true
6692 }
6693 ),
6694 legacy_response!(
6695 get_identity_by_public_key_hash_response,
6696 get_identity_by_public_key_hash_response_v0,
6697 GetIdentityByPublicKeyHashResponseV0,
6698 GetIdentityByPublicKeyHashResponse
6699 )
6700 );
6701 assert_rejects_legacy_envelope!(
6702 IdentityPublicKeys,
6703 platform::GetIdentityKeysRequest,
6704 request!(
6705 get_identity_keys_request,
6706 GetIdentityKeysRequestV0,
6707 GetIdentityKeysRequest {
6708 identity_id: id(1),
6709 request_type: Some(platform::KeyRequestType {
6710 request: Some(platform::key_request_type::Request::AllKeys(
6711 platform::AllKeys {}
6712 )),
6713 }),
6714 prove: true
6715 }
6716 ),
6717 legacy_response!(
6718 get_identity_keys_response,
6719 get_identity_keys_response_v0,
6720 GetIdentityKeysResponseV0,
6721 GetIdentityKeysResponse
6722 )
6723 );
6724 assert_rejects_legacy_envelope!(
6725 IdentityNonceFetcher,
6726 platform::GetIdentityNonceRequest,
6727 request!(
6728 get_identity_nonce_request,
6729 GetIdentityNonceRequestV0,
6730 GetIdentityNonceRequest {
6731 identity_id: id(1),
6732 prove: true
6733 }
6734 ),
6735 legacy_response!(
6736 get_identity_nonce_response,
6737 get_identity_nonce_response_v0,
6738 GetIdentityNonceResponseV0,
6739 GetIdentityNonceResponse
6740 )
6741 );
6742 assert_rejects_legacy_envelope!(
6743 IdentityContractNonceFetcher,
6744 platform::GetIdentityContractNonceRequest,
6745 request!(
6746 get_identity_contract_nonce_request,
6747 GetIdentityContractNonceRequestV0,
6748 GetIdentityContractNonceRequest {
6749 identity_id: id(1),
6750 contract_id: id(2),
6751 prove: true
6752 }
6753 ),
6754 legacy_response!(
6755 get_identity_contract_nonce_response,
6756 get_identity_contract_nonce_response_v0,
6757 GetIdentityContractNonceResponseV0,
6758 GetIdentityContractNonceResponse
6759 )
6760 );
6761 assert_rejects_legacy_envelope!(
6762 IdentityBalance,
6763 platform::GetIdentityBalanceRequest,
6764 request!(
6765 get_identity_balance_request,
6766 GetIdentityBalanceRequestV0,
6767 GetIdentityBalanceRequest {
6768 id: id(1),
6769 prove: true
6770 }
6771 ),
6772 legacy_response!(
6773 get_identity_balance_response,
6774 get_identity_balance_response_v0,
6775 GetIdentityBalanceResponseV0,
6776 GetIdentityBalanceResponse
6777 )
6778 );
6779 assert_rejects_legacy_envelope!(
6780 IdentityBalances,
6781 platform::GetIdentitiesBalancesRequest,
6782 request!(
6783 get_identities_balances_request,
6784 GetIdentitiesBalancesRequestV0,
6785 GetIdentitiesBalancesRequest {
6786 ids: vec![id(1)],
6787 prove: true
6788 }
6789 ),
6790 legacy_response!(
6791 get_identities_balances_response,
6792 get_identities_balances_response_v0,
6793 GetIdentitiesBalancesResponseV0,
6794 GetIdentitiesBalancesResponse
6795 )
6796 );
6797 assert_rejects_legacy_envelope!(
6798 IdentityBalanceAndRevision,
6799 platform::GetIdentityBalanceAndRevisionRequest,
6800 request!(
6801 get_identity_balance_and_revision_request,
6802 GetIdentityBalanceAndRevisionRequestV0,
6803 GetIdentityBalanceAndRevisionRequest {
6804 id: id(1),
6805 prove: true
6806 }
6807 ),
6808 legacy_response!(
6809 get_identity_balance_and_revision_response,
6810 get_identity_balance_and_revision_response_v0,
6811 GetIdentityBalanceAndRevisionResponseV0,
6812 GetIdentityBalanceAndRevisionResponse
6813 )
6814 );
6815 assert_rejects_legacy_envelope!(
6816 IdentitiesContractKeys,
6817 platform::GetIdentitiesContractKeysRequest,
6818 request!(
6819 get_identities_contract_keys_request,
6820 GetIdentitiesContractKeysRequestV0,
6821 GetIdentitiesContractKeysRequest {
6822 identities_ids: vec![id(1)],
6823 contract_id: id(2),
6824 prove: true
6825 }
6826 ),
6827 legacy_response!(
6828 get_identities_contract_keys_response,
6829 get_identities_contract_keys_response_v0,
6830 GetIdentitiesContractKeysResponseV0,
6831 GetIdentitiesContractKeysResponse
6832 )
6833 );
6834 }
6835
6836 #[test]
6837 fn contract_and_address_queries() {
6838 assert_rejects_legacy_envelope!(
6839 DataContract,
6840 platform::GetDataContractRequest,
6841 request!(
6842 get_data_contract_request,
6843 GetDataContractRequestV0,
6844 GetDataContractRequest {
6845 id: id(1),
6846 prove: true
6847 }
6848 ),
6849 legacy_response!(
6850 get_data_contract_response,
6851 get_data_contract_response_v0,
6852 GetDataContractResponseV0,
6853 GetDataContractResponse
6854 )
6855 );
6856 assert_rejects_legacy_envelope!(
6857 (DataContract, Vec<u8>),
6858 platform::GetDataContractRequest,
6859 request!(
6860 get_data_contract_request,
6861 GetDataContractRequestV0,
6862 GetDataContractRequest {
6863 id: id(1),
6864 prove: true
6865 }
6866 ),
6867 legacy_response!(
6868 get_data_contract_response,
6869 get_data_contract_response_v0,
6870 GetDataContractResponseV0,
6871 GetDataContractResponse
6872 )
6873 );
6874 assert_rejects_legacy_envelope!(
6875 DataContracts,
6876 platform::GetDataContractsRequest,
6877 request!(
6878 get_data_contracts_request,
6879 GetDataContractsRequestV0,
6880 GetDataContractsRequest {
6881 ids: vec![id(1)],
6882 prove: true
6883 }
6884 ),
6885 legacy_response!(
6886 get_data_contracts_response,
6887 get_data_contracts_response_v0,
6888 GetDataContractsResponseV0,
6889 GetDataContractsResponse
6890 )
6891 );
6892 assert_rejects_legacy_envelope!(
6893 DataContractHistory,
6894 platform::GetDataContractHistoryRequest,
6895 request!(
6896 get_data_contract_history_request,
6897 GetDataContractHistoryRequestV0,
6898 GetDataContractHistoryRequest {
6899 id: id(1),
6900 prove: true
6901 }
6902 ),
6903 legacy_response!(
6904 get_data_contract_history_response,
6905 get_data_contract_history_response_v0,
6906 GetDataContractHistoryResponseV0,
6907 GetDataContractHistoryResponse
6908 )
6909 );
6910 assert_rejects_legacy_envelope!(
6911 AddressInfos,
6912 platform::GetAddressesInfosRequest,
6913 request!(
6914 get_addresses_infos_request,
6915 GetAddressesInfosRequestV0,
6916 GetAddressesInfosRequest { prove: true }
6917 ),
6918 legacy_response!(
6919 get_addresses_infos_response,
6920 get_addresses_infos_response_v0,
6921 GetAddressesInfosResponseV0,
6922 GetAddressesInfosResponse
6923 )
6924 );
6925 assert_rejects_legacy_envelope!(
6926 RecentAddressBalanceChanges,
6927 platform::GetRecentAddressBalanceChangesRequest,
6928 request!(
6929 get_recent_address_balance_changes_request,
6930 GetRecentAddressBalanceChangesRequestV0,
6931 GetRecentAddressBalanceChangesRequest {
6932 start_height: 1,
6933 prove: true
6934 }
6935 ),
6936 legacy_response!(
6937 get_recent_address_balance_changes_response,
6938 get_recent_address_balance_changes_response_v0,
6939 GetRecentAddressBalanceChangesResponseV0,
6940 GetRecentAddressBalanceChangesResponse
6941 )
6942 );
6943 use platform::get_addresses_trunk_state_response::{
6949 GetAddressesTrunkStateResponseV0, Version as TrunkStateVersion,
6950 };
6951 let legacy_trunk_state_response = || platform::GetAddressesTrunkStateResponse {
6952 version: Some(TrunkStateVersion::V0(GetAddressesTrunkStateResponseV0 {
6953 proof: Some(legacy_proof()),
6954 metadata: Some(ResponseMetadata::default()),
6955 })),
6956 };
6957 assert_rejects_legacy_envelope!(
6958 GroveTrunkQueryResult,
6959 platform::GetAddressesTrunkStateRequest,
6960 request!(
6961 get_addresses_trunk_state_request,
6962 GetAddressesTrunkStateRequestV0,
6963 GetAddressesTrunkStateRequest {}
6964 ),
6965 legacy_trunk_state_response()
6966 );
6967 assert_rejects_legacy_envelope!(
6968 PlatformAddressTrunkState,
6969 platform::GetAddressesTrunkStateRequest,
6970 request!(
6971 get_addresses_trunk_state_request,
6972 GetAddressesTrunkStateRequestV0,
6973 GetAddressesTrunkStateRequest {}
6974 ),
6975 legacy_trunk_state_response()
6976 );
6977 assert_rejects_legacy_envelope!(
6978 PrefundedSpecializedBalance,
6979 platform::GetPrefundedSpecializedBalanceRequest,
6980 request!(
6981 get_prefunded_specialized_balance_request,
6982 GetPrefundedSpecializedBalanceRequestV0,
6983 GetPrefundedSpecializedBalanceRequest {
6984 id: id(1),
6985 prove: true
6986 }
6987 ),
6988 legacy_response!(
6989 get_prefunded_specialized_balance_response,
6990 get_prefunded_specialized_balance_response_v0,
6991 GetPrefundedSpecializedBalanceResponseV0,
6992 GetPrefundedSpecializedBalanceResponse
6993 )
6994 );
6995 assert_rejects_legacy_envelope!(
6996 VotePollsGroupedByTimestamp,
6997 platform::GetVotePollsByEndDateRequest,
6998 request!(
6999 get_vote_polls_by_end_date_request,
7000 GetVotePollsByEndDateRequestV0,
7001 GetVotePollsByEndDateRequest { prove: true }
7002 ),
7003 legacy_response!(
7004 get_vote_polls_by_end_date_response,
7005 get_vote_polls_by_end_date_response_v0,
7006 GetVotePollsByEndDateResponseV0,
7007 GetVotePollsByEndDateResponse
7008 )
7009 );
7010 }
7011
7012 #[test]
7013 fn system_queries() {
7014 assert_rejects_legacy_envelope!(
7015 ExtendedEpochInfos,
7016 platform::GetEpochsInfoRequest,
7017 request!(
7018 get_epochs_info_request,
7019 GetEpochsInfoRequestV0,
7020 GetEpochsInfoRequest {
7021 count: 1,
7022 ascending: true,
7023 prove: true
7024 }
7025 ),
7026 legacy_response!(
7027 get_epochs_info_response,
7028 get_epochs_info_response_v0,
7029 GetEpochsInfoResponseV0,
7030 GetEpochsInfoResponse
7031 )
7032 );
7033 assert_rejects_legacy_envelope!(
7034 FinalizedEpochInfos,
7035 platform::GetFinalizedEpochInfosRequest,
7036 request!(
7037 get_finalized_epoch_infos_request,
7038 GetFinalizedEpochInfosRequestV0,
7039 GetFinalizedEpochInfosRequest {
7040 end_epoch_index: 1,
7041 prove: true
7042 }
7043 ),
7044 legacy_response!(
7045 get_finalized_epoch_infos_response,
7046 get_finalized_epoch_infos_response_v0,
7047 GetFinalizedEpochInfosResponseV0,
7048 GetFinalizedEpochInfosResponse
7049 )
7050 );
7051 assert_rejects_legacy_envelope!(
7052 ProtocolVersionUpgrades,
7053 platform::GetProtocolVersionUpgradeStateRequest,
7054 request!(
7055 get_protocol_version_upgrade_state_request,
7056 GetProtocolVersionUpgradeStateRequestV0,
7057 GetProtocolVersionUpgradeStateRequest { prove: true }
7058 ),
7059 legacy_response!(
7060 get_protocol_version_upgrade_state_response,
7061 get_protocol_version_upgrade_state_response_v0,
7062 GetProtocolVersionUpgradeStateResponseV0,
7063 GetProtocolVersionUpgradeStateResponse
7064 )
7065 );
7066 assert_rejects_legacy_envelope!(
7067 MasternodeProtocolVotes,
7068 platform::GetProtocolVersionUpgradeVoteStatusRequest,
7069 request!(
7070 get_protocol_version_upgrade_vote_status_request,
7071 GetProtocolVersionUpgradeVoteStatusRequestV0,
7072 GetProtocolVersionUpgradeVoteStatusRequest {
7073 count: 1,
7074 prove: true
7075 }
7076 ),
7077 legacy_response!(
7078 get_protocol_version_upgrade_vote_status_response,
7079 get_protocol_version_upgrade_vote_status_response_v0,
7080 GetProtocolVersionUpgradeVoteStatusResponseV0,
7081 GetProtocolVersionUpgradeVoteStatusResponse
7082 )
7083 );
7084 assert_rejects_legacy_envelope!(
7085 Elements,
7086 platform::GetPathElementsRequest,
7087 request!(
7088 get_path_elements_request,
7089 GetPathElementsRequestV0,
7090 GetPathElementsRequest { prove: true }
7091 ),
7092 legacy_response!(
7093 get_path_elements_response,
7094 get_path_elements_response_v0,
7095 GetPathElementsResponseV0,
7096 GetPathElementsResponse
7097 )
7098 );
7099 assert_rejects_legacy_envelope!(
7100 TotalCreditsInPlatform,
7101 platform::GetTotalCreditsInPlatformRequest,
7102 request!(
7103 get_total_credits_in_platform_request,
7104 GetTotalCreditsInPlatformRequestV0,
7105 GetTotalCreditsInPlatformRequest { prove: true }
7106 ),
7107 legacy_response!(
7108 get_total_credits_in_platform_response,
7109 get_total_credits_in_platform_response_v0,
7110 GetTotalCreditsInPlatformResponseV0,
7111 GetTotalCreditsInPlatformResponse
7112 )
7113 );
7114 assert_rejects_legacy_envelope!(
7115 ProposerBlockCounts,
7116 platform::GetEvonodesProposedEpochBlocksByIdsRequest,
7117 request!(
7118 get_evonodes_proposed_epoch_blocks_by_ids_request,
7119 GetEvonodesProposedEpochBlocksByIdsRequestV0,
7120 GetEvonodesProposedEpochBlocksByIdsRequest {
7121 epoch: Some(1),
7122 ids: vec![id(1)],
7123 prove: true
7124 }
7125 ),
7126 legacy_response!(
7127 get_evonodes_proposed_epoch_blocks_response,
7128 get_evonodes_proposed_epoch_blocks_response_v0,
7129 GetEvonodesProposedEpochBlocksResponseV0,
7130 GetEvonodesProposedEpochBlocksResponse
7131 )
7132 );
7133 assert_rejects_legacy_envelope!(
7134 ProposerBlockCounts,
7135 platform::GetEvonodesProposedEpochBlocksByRangeRequest,
7136 request!(
7137 get_evonodes_proposed_epoch_blocks_by_range_request,
7138 GetEvonodesProposedEpochBlocksByRangeRequestV0,
7139 GetEvonodesProposedEpochBlocksByRangeRequest {
7140 epoch: Some(1),
7141 prove: true
7142 }
7143 ),
7144 legacy_response!(
7145 get_evonodes_proposed_epoch_blocks_response,
7146 get_evonodes_proposed_epoch_blocks_response_v0,
7147 GetEvonodesProposedEpochBlocksResponseV0,
7148 GetEvonodesProposedEpochBlocksResponse
7149 )
7150 );
7151 }
7152
7153 #[test]
7154 fn shielded_queries() {
7155 assert_rejects_legacy_envelope!(
7156 ShieldedPoolState,
7157 platform::GetShieldedPoolStateRequest,
7158 request!(
7159 get_shielded_pool_state_request,
7160 GetShieldedPoolStateRequestV0,
7161 GetShieldedPoolStateRequest {
7162 prove: true,
7163 token_id: None
7164 }
7165 ),
7166 legacy_response!(
7167 get_shielded_pool_state_response,
7168 get_shielded_pool_state_response_v0,
7169 GetShieldedPoolStateResponseV0,
7170 GetShieldedPoolStateResponse
7171 )
7172 );
7173 assert_rejects_legacy_envelope!(
7174 ShieldedNotesCount,
7175 platform::GetShieldedNotesCountRequest,
7176 request!(
7177 get_shielded_notes_count_request,
7178 GetShieldedNotesCountRequestV0,
7179 GetShieldedNotesCountRequest {
7180 prove: true,
7181 token_id: None
7182 }
7183 ),
7184 legacy_response!(
7185 get_shielded_notes_count_response,
7186 get_shielded_notes_count_response_v0,
7187 GetShieldedNotesCountResponseV0,
7188 GetShieldedNotesCountResponse
7189 )
7190 );
7191 assert_rejects_legacy_envelope!(
7192 ShieldedAnchors,
7193 platform::GetShieldedAnchorsRequest,
7194 request!(
7195 get_shielded_anchors_request,
7196 GetShieldedAnchorsRequestV0,
7197 GetShieldedAnchorsRequest {
7198 prove: true,
7199 token_id: None
7200 }
7201 ),
7202 legacy_response!(
7203 get_shielded_anchors_response,
7204 get_shielded_anchors_response_v0,
7205 GetShieldedAnchorsResponseV0,
7206 GetShieldedAnchorsResponse
7207 )
7208 );
7209 assert_rejects_legacy_envelope!(
7210 MostRecentShieldedAnchor,
7211 platform::GetMostRecentShieldedAnchorRequest,
7212 request!(
7213 get_most_recent_shielded_anchor_request,
7214 GetMostRecentShieldedAnchorRequestV0,
7215 GetMostRecentShieldedAnchorRequest {
7216 prove: true,
7217 token_id: None
7218 }
7219 ),
7220 legacy_response!(
7221 get_most_recent_shielded_anchor_response,
7222 get_most_recent_shielded_anchor_response_v0,
7223 GetMostRecentShieldedAnchorResponseV0,
7224 GetMostRecentShieldedAnchorResponse
7225 )
7226 );
7227 assert_rejects_legacy_envelope!(
7228 ShieldedEncryptedNotes,
7229 platform::GetShieldedEncryptedNotesRequest,
7230 request!(
7231 get_shielded_encrypted_notes_request,
7232 GetShieldedEncryptedNotesRequestV0,
7233 GetShieldedEncryptedNotesRequest {
7234 count: 1,
7235 prove: true,
7236 token_id: None
7237 }
7238 ),
7239 legacy_response!(
7240 get_shielded_encrypted_notes_response,
7241 get_shielded_encrypted_notes_response_v0,
7242 GetShieldedEncryptedNotesResponseV0,
7243 GetShieldedEncryptedNotesResponse
7244 )
7245 );
7246 assert_rejects_legacy_envelope!(
7247 ShieldedNullifierStatuses,
7248 platform::GetShieldedNullifiersRequest,
7249 request!(
7250 get_shielded_nullifiers_request,
7251 GetShieldedNullifiersRequestV0,
7252 GetShieldedNullifiersRequest {
7253 nullifiers: vec![id(1)],
7254 prove: true,
7255 token_id: None
7256 }
7257 ),
7258 legacy_response!(
7259 get_shielded_nullifiers_response,
7260 get_shielded_nullifiers_response_v0,
7261 GetShieldedNullifiersResponseV0,
7262 GetShieldedNullifiersResponse
7263 )
7264 );
7265 }
7266
7267 #[test]
7268 fn token_and_group_queries() {
7269 assert_rejects_legacy_envelope!(
7270 IdentityTokenBalances,
7271 platform::GetIdentityTokenBalancesRequest,
7272 request!(
7273 get_identity_token_balances_request,
7274 GetIdentityTokenBalancesRequestV0,
7275 GetIdentityTokenBalancesRequest {
7276 identity_id: id(1),
7277 token_ids: vec![id(2)],
7278 prove: true
7279 }
7280 ),
7281 legacy_response!(
7282 get_identity_token_balances_response,
7283 get_identity_token_balances_response_v0,
7284 GetIdentityTokenBalancesResponseV0,
7285 GetIdentityTokenBalancesResponse
7286 )
7287 );
7288 assert_rejects_legacy_envelope!(
7289 IdentitiesTokenBalances,
7290 platform::GetIdentitiesTokenBalancesRequest,
7291 request!(
7292 get_identities_token_balances_request,
7293 GetIdentitiesTokenBalancesRequestV0,
7294 GetIdentitiesTokenBalancesRequest {
7295 token_id: id(2),
7296 identity_ids: vec![id(1)],
7297 prove: true
7298 }
7299 ),
7300 legacy_response!(
7301 get_identities_token_balances_response,
7302 get_identities_token_balances_response_v0,
7303 GetIdentitiesTokenBalancesResponseV0,
7304 GetIdentitiesTokenBalancesResponse
7305 )
7306 );
7307 assert_rejects_legacy_envelope!(
7308 IdentityTokenInfos,
7309 platform::GetIdentityTokenInfosRequest,
7310 request!(
7311 get_identity_token_infos_request,
7312 GetIdentityTokenInfosRequestV0,
7313 GetIdentityTokenInfosRequest {
7314 identity_id: id(1),
7315 token_ids: vec![id(2)],
7316 prove: true
7317 }
7318 ),
7319 legacy_response!(
7320 get_identity_token_infos_response,
7321 get_identity_token_infos_response_v0,
7322 GetIdentityTokenInfosResponseV0,
7323 GetIdentityTokenInfosResponse
7324 )
7325 );
7326 assert_rejects_legacy_envelope!(
7327 IdentitiesTokenInfos,
7328 platform::GetIdentitiesTokenInfosRequest,
7329 request!(
7330 get_identities_token_infos_request,
7331 GetIdentitiesTokenInfosRequestV0,
7332 GetIdentitiesTokenInfosRequest {
7333 token_id: id(2),
7334 identity_ids: vec![id(1)],
7335 prove: true
7336 }
7337 ),
7338 legacy_response!(
7339 get_identities_token_infos_response,
7340 get_identities_token_infos_response_v0,
7341 GetIdentitiesTokenInfosResponseV0,
7342 GetIdentitiesTokenInfosResponse
7343 )
7344 );
7345 assert_rejects_legacy_envelope!(
7346 TokenStatuses,
7347 platform::GetTokenStatusesRequest,
7348 request!(
7349 get_token_statuses_request,
7350 GetTokenStatusesRequestV0,
7351 GetTokenStatusesRequest {
7352 token_ids: vec![id(2)],
7353 prove: true
7354 }
7355 ),
7356 legacy_response!(
7357 get_token_statuses_response,
7358 get_token_statuses_response_v0,
7359 GetTokenStatusesResponseV0,
7360 GetTokenStatusesResponse
7361 )
7362 );
7363 assert_rejects_legacy_envelope!(
7364 TotalSingleTokenBalance,
7365 platform::GetTokenTotalSupplyRequest,
7366 request!(
7367 get_token_total_supply_request,
7368 GetTokenTotalSupplyRequestV0,
7369 GetTokenTotalSupplyRequest {
7370 token_id: id(2),
7371 prove: true
7372 }
7373 ),
7374 legacy_response!(
7375 get_token_total_supply_response,
7376 get_token_total_supply_response_v0,
7377 GetTokenTotalSupplyResponseV0,
7378 GetTokenTotalSupplyResponse
7379 )
7380 );
7381 assert_rejects_legacy_envelope!(
7382 TokenContractInfo,
7383 platform::GetTokenContractInfoRequest,
7384 request!(
7385 get_token_contract_info_request,
7386 GetTokenContractInfoRequestV0,
7387 GetTokenContractInfoRequest {
7388 token_id: id(2),
7389 prove: true
7390 }
7391 ),
7392 legacy_response!(
7393 get_token_contract_info_response,
7394 get_token_contract_info_response_v0,
7395 GetTokenContractInfoResponseV0,
7396 GetTokenContractInfoResponse
7397 )
7398 );
7399 assert_rejects_legacy_envelope!(
7400 TokenDirectPurchasePrices,
7401 platform::GetTokenDirectPurchasePricesRequest,
7402 request!(
7403 get_token_direct_purchase_prices_request,
7404 GetTokenDirectPurchasePricesRequestV0,
7405 GetTokenDirectPurchasePricesRequest {
7406 token_ids: vec![id(2)],
7407 prove: true
7408 }
7409 ),
7410 legacy_response!(
7411 get_token_direct_purchase_prices_response,
7412 get_token_direct_purchase_prices_response_v0,
7413 GetTokenDirectPurchasePricesResponseV0,
7414 GetTokenDirectPurchasePricesResponse
7415 )
7416 );
7417 assert_rejects_legacy_envelope!(
7418 TokenPreProgrammedDistributions,
7419 platform::GetTokenPreProgrammedDistributionsRequest,
7420 request!(
7421 get_token_pre_programmed_distributions_request,
7422 GetTokenPreProgrammedDistributionsRequestV0,
7423 GetTokenPreProgrammedDistributionsRequest {
7424 token_id: id(2),
7425 prove: true
7426 }
7427 ),
7428 legacy_response!(
7429 get_token_pre_programmed_distributions_response,
7430 get_token_pre_programmed_distributions_response_v0,
7431 GetTokenPreProgrammedDistributionsResponseV0,
7432 GetTokenPreProgrammedDistributionsResponse
7433 )
7434 );
7435 assert_rejects_legacy_envelope!(
7436 Group,
7437 platform::GetGroupInfoRequest,
7438 request!(
7439 get_group_info_request,
7440 GetGroupInfoRequestV0,
7441 GetGroupInfoRequest {
7442 contract_id: id(2),
7443 prove: true
7444 }
7445 ),
7446 legacy_response!(
7447 get_group_info_response,
7448 get_group_info_response_v0,
7449 GetGroupInfoResponseV0,
7450 GetGroupInfoResponse
7451 )
7452 );
7453 assert_rejects_legacy_envelope!(
7454 Groups,
7455 platform::GetGroupInfosRequest,
7456 request!(
7457 get_group_infos_request,
7458 GetGroupInfosRequestV0,
7459 GetGroupInfosRequest {
7460 contract_id: id(2),
7461 prove: true
7462 }
7463 ),
7464 legacy_response!(
7465 get_group_infos_response,
7466 get_group_infos_response_v0,
7467 GetGroupInfosResponseV0,
7468 GetGroupInfosResponse
7469 )
7470 );
7471 assert_rejects_legacy_envelope!(
7472 GroupActions,
7473 platform::GetGroupActionsRequest,
7474 request!(
7475 get_group_actions_request,
7476 GetGroupActionsRequestV0,
7477 GetGroupActionsRequest {
7478 contract_id: id(2),
7479 prove: true
7480 }
7481 ),
7482 legacy_response!(
7483 get_group_actions_response,
7484 get_group_actions_response_v0,
7485 GetGroupActionsResponseV0,
7486 GetGroupActionsResponse
7487 )
7488 );
7489 assert_rejects_legacy_envelope!(
7490 GroupActionSigners,
7491 platform::GetGroupActionSignersRequest,
7492 request!(
7493 get_group_action_signers_request,
7494 GetGroupActionSignersRequestV0,
7495 GetGroupActionSignersRequest {
7496 contract_id: id(2),
7497 action_id: id(3),
7498 prove: true
7499 }
7500 ),
7501 legacy_response!(
7502 get_group_action_signers_response,
7503 get_group_action_signers_response_v0,
7504 GetGroupActionSignersResponseV0,
7505 GetGroupActionSignersResponse
7506 )
7507 );
7508 }
7509 }
7510}