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