1pub mod document_average;
6pub mod document_count;
7pub mod document_split_average;
11pub mod document_split_count;
12pub mod document_split_sum;
16pub mod document_sum;
20pub mod groups;
21pub mod identity_token_balance;
22pub mod token_contract_info;
23pub mod token_direct_purchase;
24pub mod token_info;
25pub mod token_perpetual_distribution_last_claim;
26pub mod token_pre_programmed_distributions;
27pub mod token_status;
28pub mod token_total_supply;
29
30use crate::from_request::TryFromRequest;
31use crate::verify::verify_tenderdash_proof;
32use crate::{types::*, ContextProvider, DataContractProvider, Error};
33use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::get_evonodes_proposed_epoch_blocks_by_range_request_v0::Start;
34use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0;
35use dapi_grpc::platform::v0::get_path_elements_request::GetPathElementsRequestV0;
36use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_request::{
37 self, GetProtocolVersionUpgradeVoteStatusRequestV0,
38};
39use dapi_grpc::platform::v0::security_level_map::KeyKindRequestType as GrpcKeyKind;
40use dapi_grpc::platform::v0::{
41 get_address_info_request, get_addresses_infos_request,
42 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,
43 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
44};
45use dapi_grpc::platform::{
46 v0::{self as platform, key_request_type, KeyRequestType as GrpcKeyType},
47 VersionedGrpcResponse,
48};
49use dpp::address_funds::PlatformAddress;
50use dpp::block::block_info::BlockInfo;
51use dpp::block::epoch::EpochIndex;
52use dpp::block::extended_epoch_info::ExtendedEpochInfo;
53use dpp::core_subsidy::NetworkCoreSubsidy;
54use dpp::data_contract::accessors::v0::DataContractV0Getters;
55use dpp::dashcore::hashes::Hash;
56use dpp::dashcore::{Network, ProTxHash};
57use dpp::document::{Document, DocumentV0Getters};
58use dpp::fee::Credits;
59use dpp::identity::identities_contract_keys::IdentitiesContractKeys;
60use dpp::identity::Purpose;
61use dpp::platform_value::{self};
62use dpp::prelude::{AddressNonce, DataContract, Identifier, Identity};
63use dpp::serialization::PlatformDeserializable;
64use dpp::state_transition::proof_result::StateTransitionProofResult;
65use dpp::state_transition::StateTransition;
66use dpp::version::PlatformVersion;
67use dpp::voting::votes::Vote;
68use drive::drive::identity::identity_and_non_unique_public_key_hash_double_proof::IdentityAndNonUniquePublicKeyHashDoubleProof;
69use drive::drive::identity::key::fetch::{
70 IdentityKeysRequest, KeyKindRequestType, KeyRequestType, PurposeU8, SecurityLevelU8,
71};
72use drive::drive::Drive;
73use drive::error::proof::ProofError;
74use drive::grovedb::Error as GroveError;
75use drive::grovedb::GroveTrunkQueryResult;
76use drive::query::contested_resource_votes_given_by_identity_query::ContestedResourceVotesGivenByIdentityQuery;
77use drive::query::proposer_block_count_query::ProposerQueryType;
78use drive::query::vote_poll_contestant_votes_query::ContestedDocumentVotePollVotesDriveQuery;
79use drive::query::vote_poll_vote_state_query::ContestedDocumentVotePollDriveQuery;
80use drive::query::vote_polls_by_document_type_query::VotePollsByDocumentTypeQuery;
81use drive::query::{DriveDocumentQuery, VotePollsByEndDateDriveQuery};
82use indexmap::IndexMap;
83use std::array::TryFromSliceError;
84use std::collections::BTreeMap;
85use std::num::TryFromIntError;
86use crate::error::MapGroveDbError;
87
88pub trait FromProof<Req> {
102 type Request;
104 type Response;
106
107 fn maybe_from_proof<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
124 request: I,
125 response: O,
126 network: Network,
127 platform_version: &PlatformVersion,
128 provider: &'a dyn ContextProvider,
129 ) -> Result<Option<Self>, Error>
130 where
131 Self: Sized + 'a,
132 {
133 Self::maybe_from_proof_with_metadata(request, response, network, platform_version, provider)
134 .map(|maybe_result| maybe_result.0)
135 }
136
137 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
154 request: I,
155 response: O,
156 network: Network,
157 platform_version: &PlatformVersion,
158 provider: &'a dyn ContextProvider,
159 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
160 where
161 Self: Sized + 'a;
162
163 fn from_proof<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
184 request: I,
185 response: O,
186 network: Network,
187 platform_version: &PlatformVersion,
188 provider: &'a dyn ContextProvider,
189 ) -> Result<Self, Error>
190 where
191 Self: Sized + 'a,
192 {
193 Self::maybe_from_proof(request, response, network, platform_version, provider)?
194 .ok_or(Error::NotFound)
195 }
196
197 fn from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
218 request: I,
219 response: O,
220 network: Network,
221 platform_version: &PlatformVersion,
222 provider: &'a dyn ContextProvider,
223 ) -> Result<(Self, ResponseMetadata), Error>
224 where
225 Self: Sized + 'a,
226 {
227 let (main_item, response_metadata, _) = Self::maybe_from_proof_with_metadata(
228 request,
229 response,
230 network,
231 platform_version,
232 provider,
233 )?;
234 Ok((main_item.ok_or(Error::NotFound)?, response_metadata))
235 }
236
237 fn from_proof_with_metadata_and_proof<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
258 request: I,
259 response: O,
260 network: Network,
261 platform_version: &PlatformVersion,
262 provider: &'a dyn ContextProvider,
263 ) -> Result<(Self, ResponseMetadata, Proof), Error>
264 where
265 Self: Sized + 'a,
266 {
267 let (main_item, response_metadata, proof) = Self::maybe_from_proof_with_metadata(
268 request,
269 response,
270 network,
271 platform_version,
272 provider,
273 )?;
274 Ok((main_item.ok_or(Error::NotFound)?, response_metadata, proof))
275 }
276}
277
278impl FromProof<platform::GetIdentityRequest> for Identity {
279 type Request = platform::GetIdentityRequest;
280 type Response = platform::GetIdentityResponse;
281
282 fn maybe_from_proof_with_metadata<'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<(Option<Self>, ResponseMetadata, Proof), Error>
289 where
290 Identity: Sized + 'a,
291 {
292 let request: platform::GetIdentityRequest = request.into();
293 let response: Self::Response = response.into();
294
295 let proof = response.proof().or(Err(Error::NoProofInResult))?;
297 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
298
299 let id = match request.version.ok_or(Error::EmptyVersion)? {
300 get_identity_request::Version::V0(v0) => {
301 Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
302 error: e.to_string(),
303 })?
304 }
305 };
306
307 let (root_hash, maybe_identity) = Drive::verify_full_identity_by_identity_id(
309 &proof.grovedb_proof,
310 false,
311 id.into_buffer(),
312 platform_version,
313 )
314 .map_drive_error(proof, mtd)?;
315
316 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
317
318 Ok((maybe_identity, mtd.clone(), proof.clone()))
319 }
320}
321
322impl FromProof<platform::GetIdentityByPublicKeyHashRequest> for Identity {
324 type Request = platform::GetIdentityByPublicKeyHashRequest;
325 type Response = platform::GetIdentityByPublicKeyHashResponse;
326
327 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
328 request: I,
329 response: O,
330 _network: Network,
331 platform_version: &PlatformVersion,
332 provider: &'a dyn ContextProvider,
333 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
334 where
335 Identity: 'a,
336 {
337 let request = request.into();
338 let response = response.into();
339 let proof = response.proof().or(Err(Error::NoProofInResult))?;
341
342 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
343
344 let public_key_hash = match request.version.ok_or(Error::EmptyVersion)? {
345 get_identity_by_public_key_hash_request::Version::V0(v0) => {
346 let public_key_hash: [u8; 20] =
347 v0.public_key_hash
348 .try_into()
349 .map_err(|_| Error::DriveError {
350 error: "Invalid public key hash length".to_string(),
351 })?;
352 public_key_hash
353 }
354 };
355
356 let (root_hash, maybe_identity) = Drive::verify_full_identity_by_unique_public_key_hash(
358 &proof.grovedb_proof,
359 public_key_hash,
360 platform_version,
361 )
362 .map_drive_error(proof, mtd)?;
363
364 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
365
366 Ok((maybe_identity, mtd.clone(), proof.clone()))
367 }
368}
369
370impl FromProof<platform::GetIdentityByNonUniquePublicKeyHashRequest> for Identity {
371 type Request = platform::GetIdentityByNonUniquePublicKeyHashRequest;
372 type Response = platform::GetIdentityByNonUniquePublicKeyHashResponse;
373 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
374 request: I,
375 response: O,
376 _network: Network,
377 platform_version: &PlatformVersion,
378 provider: &'a dyn ContextProvider,
379 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
380 where
381 Self: Sized + 'a,
382 {
383 let request = request.into();
384 let response = response.into();
385 use platform::get_identity_by_non_unique_public_key_hash_response::{
389 get_identity_by_non_unique_public_key_hash_response_v0::Result as V0Result, Version::V0,
390 };
391
392 let (proved_response, mtd) = match response.version {
393 Some(V0(v0)) => {
394 let proof = if let V0Result::Proof(p) = v0.result.ok_or(Error::NoProofInResult)? {
395 p
396 } else {
397 return Err(Error::NoProofInResult);
398 };
399
400 (proof, v0.metadata.ok_or(Error::EmptyResponseMetadata)?)
401 }
402 _ => return Err(Error::EmptyResponseMetadata),
403 };
404
405 let (public_key_hash, after_identity) = match request.version.ok_or(Error::EmptyVersion)? {
408 get_identity_by_non_unique_public_key_hash_request::Version::V0(v0) => {
409 let public_key_hash =
410 v0.public_key_hash
411 .try_into()
412 .map_err(|_| Error::RequestError {
413 error: "Invalid public key hash length".to_string(),
414 })?;
415
416 let after = v0
417 .start_after
418 .map(|a| {
419 a.try_into().map_err(|_| Error::RequestError {
420 error: "Invalid start_after length".to_string(),
421 })
422 })
423 .transpose()?;
424 (public_key_hash, after)
425 }
426 };
427
428 let proof = proved_response
430 .grovedb_identity_public_key_hash_proof
431 .ok_or(Error::NoProofInResult)?;
432
433 let proof_tuple = IdentityAndNonUniquePublicKeyHashDoubleProof {
434 identity_proof: proved_response.identity_proof_bytes,
435 identity_id_public_key_hash_proof: proof.grovedb_proof.clone(),
436 };
437
438 let (root_hash, maybe_identity) =
440 Drive::verify_full_identity_by_non_unique_public_key_hash(
441 &proof_tuple,
442 public_key_hash,
443 after_identity,
444 platform_version,
445 )
446 .map_err(|e| match e {
447 drive::error::Error::GroveDB(e) => {
448 let maybe_query = match e.as_ref() {
450 GroveError::InvalidProof(path_query, ..) => Some(path_query.clone()),
451 _ => None,
452 };
453
454 Error::GroveDBError {
455 proof_bytes: proof.grovedb_proof.clone(),
456 path_query: maybe_query,
457 height: mtd.height,
458 time_ms: mtd.time_ms,
459 error: e.to_string(),
460 }
461 }
462 _ => e.into(),
463 })?;
464
465 verify_tenderdash_proof(&proof, &mtd, &root_hash, provider)?;
466
467 Ok((maybe_identity, mtd.clone(), proof))
468 }
469}
470
471impl FromProof<platform::GetIdentityKeysRequest> for IdentityPublicKeys {
472 type Request = platform::GetIdentityKeysRequest;
473 type Response = platform::GetIdentityKeysResponse;
474
475 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
476 request: I,
477 response: O,
478 _network: Network,
479 platform_version: &PlatformVersion,
480 provider: &'a dyn ContextProvider,
481 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
482 where
483 IdentityPublicKeys: 'a,
484 {
485 let request: Self::Request = request.into();
486 let response: Self::Response = response.into();
487
488 let proof = response.proof().or(Err(Error::NoProofInResult))?;
490
491 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
492
493 let (request_type, identity_id, limit, offset) =
494 match request.version.ok_or(Error::EmptyVersion)? {
495 get_identity_keys_request::Version::V0(v0) => {
496 let request_type = v0.request_type;
497 let identity_id = Identifier::from_bytes(&v0.identity_id)
498 .map_err(|e| Error::ProtocolError {
499 error: e.to_string(),
500 })?
501 .into_buffer();
502 let limit = v0.limit.map(try_u32_to_u16).transpose()?;
503 let offset = v0.offset.map(try_u32_to_u16).transpose()?;
504 (request_type, identity_id, limit, offset)
505 }
506 };
507
508 let request_type = parse_key_request_type(&request_type)?;
509
510 let key_request = IdentityKeysRequest {
511 identity_id,
512 request_type,
513 limit,
514 offset,
515 };
516
517 tracing::debug!(?identity_id, "checking proof of identity keys");
518
519 let (root_hash, maybe_identity) = Drive::verify_identity_keys_by_identity_id(
521 &proof.grovedb_proof,
522 key_request,
523 false,
524 false,
525 false,
526 platform_version,
527 )
528 .map_drive_error(proof, mtd)?;
529
530 let maybe_keys: Option<IdentityPublicKeys> = if let Some(identity) = maybe_identity {
531 if identity.loaded_public_keys.is_empty() {
532 None
533 } else {
534 let mut keys = identity
535 .loaded_public_keys
536 .into_iter()
537 .map(|(k, v)| (k, Some(v.clone())))
538 .collect::<IdentityPublicKeys>();
539
540 let mut not_found = identity
541 .not_found_public_keys
542 .into_iter()
543 .map(|k| (k, None))
544 .collect::<IdentityPublicKeys>();
545
546 keys.append(&mut not_found);
547
548 Some(keys)
549 }
550 } else {
551 None
552 };
553
554 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
555
556 Ok((maybe_keys, mtd.clone(), proof.clone()))
557 }
558}
559
560fn parse_key_request_type(request: &Option<GrpcKeyType>) -> Result<KeyRequestType, Error> {
561 let key_request_type = request
562 .to_owned()
563 .ok_or(Error::RequestError {
564 error: "missing key request type".to_string(),
565 })?
566 .request
567 .ok_or(Error::RequestError {
568 error: "empty request field in key request type".to_string(),
569 })?;
570
571 let request_type = match key_request_type {
572 key_request_type::Request::AllKeys(_) => KeyRequestType::AllKeys,
573 key_request_type::Request::SpecificKeys(specific_keys) => {
574 KeyRequestType::SpecificKeys(specific_keys.key_ids)
575 }
576 key_request_type::Request::SearchKey(search_key) => {
577 let purpose = search_key
578 .purpose_map
579 .iter()
580 .map(|(k, v)| {
581 let v = v.security_level_map
582 .iter()
583 .map(|(level, &kind)| {
584 let kt = match GrpcKeyKind::try_from(kind) {
585 Ok(GrpcKeyKind::CurrentKeyOfKindRequest) => {
586 Ok(KeyKindRequestType::CurrentKeyOfKindRequest)
587 }
588 Ok(GrpcKeyKind::AllKeysOfKindRequest) => {
589 Ok(KeyKindRequestType::AllKeysOfKindRequest)
590 }
591 _ => Err(Error::RequestError {
592 error: format!("missing requested key type: {}", kind),
593 }),
594 };
595 match kt {
596 Err(e) => Err(e),
597 Ok(d) => Ok((*level as u8, d))
598 }
599 })
600 .collect::<Result<BTreeMap<SecurityLevelU8,KeyKindRequestType>,Error>>();
601
602 match v {
603 Err(e) =>Err(e),
604 Ok(d) => Ok((*k as u8,d)),
605 }
606 })
607 .collect::<Result<BTreeMap<PurposeU8, BTreeMap<SecurityLevelU8, KeyKindRequestType>>,Error>>()?;
608
609 KeyRequestType::SearchKey(purpose)
610 }
611 };
612
613 Ok(request_type)
614}
615
616impl FromProof<platform::GetIdentityNonceRequest> for IdentityNonceFetcher {
617 type Request = platform::GetIdentityNonceRequest;
618 type Response = platform::GetIdentityNonceResponse;
619
620 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
621 request: I,
622 response: O,
623 _network: Network,
624 platform_version: &PlatformVersion,
625 provider: &'a dyn ContextProvider,
626 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
627 where
628 IdentityNonceFetcher: 'a,
629 {
630 let request: Self::Request = request.into();
631 let response: Self::Response = response.into();
632
633 let proof = response.proof().or(Err(Error::NoProofInResult))?;
635
636 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
637
638 let identity_id =
639 match request.version.ok_or(Error::EmptyVersion)? {
640 get_identity_nonce_request::Version::V0(v0) => Ok::<Identifier, Error>(
641 Identifier::from_bytes(&v0.identity_id).map_err(|e| Error::ProtocolError {
642 error: e.to_string(),
643 })?,
644 ),
645 }?;
646
647 let (root_hash, maybe_nonce) = Drive::verify_identity_nonce(
649 &proof.grovedb_proof,
650 identity_id.into_buffer(),
651 false,
652 platform_version,
653 )
654 .map_drive_error(proof, mtd)?;
655
656 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
657
658 Ok((
659 maybe_nonce.map(IdentityNonceFetcher),
660 mtd.clone(),
661 proof.clone(),
662 ))
663 }
664}
665
666impl FromProof<platform::GetIdentityContractNonceRequest> for IdentityContractNonceFetcher {
667 type Request = platform::GetIdentityContractNonceRequest;
668 type Response = platform::GetIdentityContractNonceResponse;
669
670 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
671 request: I,
672 response: O,
673 _network: Network,
674 platform_version: &PlatformVersion,
675 provider: &'a dyn ContextProvider,
676 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
677 where
678 IdentityContractNonceFetcher: 'a,
679 {
680 let request: Self::Request = request.into();
681 let response: Self::Response = response.into();
682
683 let proof = response.proof().or(Err(Error::NoProofInResult))?;
685
686 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
687
688 let (identity_id, contract_id) = match request.version.ok_or(Error::EmptyVersion)? {
689 get_identity_contract_nonce_request::Version::V0(v0) => {
690 Ok::<(Identifier, Identifier), Error>((
691 Identifier::from_bytes(&v0.identity_id).map_err(|e| Error::ProtocolError {
692 error: e.to_string(),
693 })?,
694 Identifier::from_bytes(&v0.contract_id).map_err(|e| Error::ProtocolError {
695 error: e.to_string(),
696 })?,
697 ))
698 }
699 }?;
700
701 let (root_hash, maybe_identity) = Drive::verify_identity_contract_nonce(
703 &proof.grovedb_proof,
704 identity_id.into_buffer(),
705 contract_id.into_buffer(),
706 false,
707 platform_version,
708 )
709 .map_drive_error(proof, mtd)?;
710
711 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
712
713 Ok((
714 maybe_identity.map(IdentityContractNonceFetcher),
715 mtd.clone(),
716 proof.clone(),
717 ))
718 }
719}
720
721impl FromProof<platform::GetIdentityBalanceRequest> for IdentityBalance {
722 type Request = platform::GetIdentityBalanceRequest;
723 type Response = platform::GetIdentityBalanceResponse;
724
725 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
726 request: I,
727 response: O,
728 _network: Network,
729 platform_version: &PlatformVersion,
730 provider: &'a dyn ContextProvider,
731 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
732 where
733 IdentityBalance: 'a,
734 {
735 let request: Self::Request = request.into();
736 let response: Self::Response = response.into();
737
738 let proof = response.proof().or(Err(Error::NoProofInResult))?;
740
741 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
742
743 let id = match request.version.ok_or(Error::EmptyVersion)? {
744 get_identity_balance_request::Version::V0(v0) => Identifier::from_bytes(&v0.id)
745 .map_err(|e| Error::ProtocolError {
746 error: e.to_string(),
747 }),
748 }?;
749
750 let (root_hash, maybe_identity) = Drive::verify_identity_balance_for_identity_id(
752 &proof.grovedb_proof,
753 id.into_buffer(),
754 false,
755 platform_version,
756 )
757 .map_drive_error(proof, mtd)?;
758
759 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
760
761 Ok((maybe_identity, mtd.clone(), proof.clone()))
762 }
763}
764
765impl FromProof<platform::GetIdentitiesBalancesRequest> for IdentityBalances {
766 type Request = platform::GetIdentitiesBalancesRequest;
767 type Response = platform::GetIdentitiesBalancesResponse;
768
769 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
770 request: I,
771 response: O,
772 _network: Network,
773 platform_version: &PlatformVersion,
774 provider: &'a dyn ContextProvider,
775 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
776 where
777 IdentityBalances: 'a,
778 {
779 let request: Self::Request = request.into();
780 let response: Self::Response = response.into();
781 let proof = response.proof().or(Err(Error::NoProofInResult))?;
783
784 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
785
786 let identities_ids = match request.version.ok_or(Error::EmptyVersion)? {
787 get_identities_balances_request::Version::V0(v0) => v0.ids,
788 };
789
790 let identity_ids = identities_ids
791 .into_iter()
792 .map(|identity_bytes| {
793 Identifier::from_bytes(&identity_bytes)
794 .map(|identifier| identifier.into_buffer())
795 .map_err(|e| Error::RequestError {
796 error: format!("identities must be all 32 bytes {}", e),
797 })
798 })
799 .collect::<Result<Vec<[u8; 32]>, Error>>()?;
800 let (root_hash, balances) = Drive::verify_identity_balances_for_identity_ids(
801 &proof.grovedb_proof,
802 false,
803 &identity_ids,
804 platform_version,
805 )
806 .map_drive_error(proof, mtd)?;
807
808 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
809
810 Ok((Some(balances), mtd.clone(), proof.clone()))
811 }
812}
813
814impl FromProof<platform::GetIdentityBalanceAndRevisionRequest> for IdentityBalanceAndRevision {
815 type Request = platform::GetIdentityBalanceAndRevisionRequest;
816 type Response = platform::GetIdentityBalanceAndRevisionResponse;
817
818 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
819 request: I,
820 response: O,
821 _network: Network,
822 platform_version: &PlatformVersion,
823 provider: &'a dyn ContextProvider,
824 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
825 where
826 IdentityBalanceAndRevision: 'a,
827 {
828 let request: Self::Request = request.into();
829 let response: Self::Response = response.into();
830
831 let proof = response.proof().or(Err(Error::NoProofInResult))?;
833
834 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
835
836 let id = match request.version.ok_or(Error::EmptyVersion)? {
837 get_identity_balance_and_revision_request::Version::V0(v0) => {
838 Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
839 error: e.to_string(),
840 })
841 }
842 }?;
843
844 let (root_hash, maybe_identity) =
846 Drive::verify_identity_balance_and_revision_for_identity_id(
847 &proof.grovedb_proof,
848 id.into_buffer(),
849 false,
850 platform_version,
851 )
852 .map_drive_error(proof, mtd)?;
853
854 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
855
856 Ok((maybe_identity, mtd.clone(), proof.clone()))
857 }
858}
859
860impl FromProof<platform::GetAddressInfoRequest> for AddressInfo {
861 type Request = platform::GetAddressInfoRequest;
862 type Response = platform::GetAddressInfoResponse;
863
864 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
865 request: I,
866 response: O,
867 _network: Network,
868 platform_version: &PlatformVersion,
869 provider: &'a dyn ContextProvider,
870 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
871 where
872 AddressInfo: 'a,
873 {
874 let request: Self::Request = request.into();
875 let response: Self::Response = response.into();
876
877 let proof = response.proof().or(Err(Error::NoProofInResult))?;
878 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
879
880 let address = match request.version.ok_or(Error::EmptyVersion)? {
881 get_address_info_request::Version::V0(v0) => PlatformAddress::from_bytes(&v0.address)
882 .map_err(|e| Error::RequestError {
883 error: format!("invalid address: {}", e),
884 })?,
885 };
886
887 let (root_hash, maybe_info) =
888 Drive::verify_address_info(&proof.grovedb_proof, &address, false, platform_version)
889 .map_drive_error(proof, mtd)?;
890
891 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
892
893 let info = maybe_info.map(|(nonce, balance)| AddressInfo {
894 address,
895 nonce,
896 balance,
897 });
898
899 Ok((info, mtd.clone(), proof.clone()))
900 }
901}
902
903impl FromProof<platform::GetAddressesInfosRequest> for AddressInfos {
904 type Request = platform::GetAddressesInfosRequest;
905 type Response = platform::GetAddressesInfosResponse;
906
907 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
908 request: I,
909 response: O,
910 _network: Network,
911 platform_version: &PlatformVersion,
912 provider: &'a dyn ContextProvider,
913 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
914 where
915 AddressInfos: 'a,
916 {
917 let request: Self::Request = request.into();
918 let response: Self::Response = response.into();
919
920 let proof = response.proof().or(Err(Error::NoProofInResult))?;
921 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
922
923 let addresses_bytes = match request.version.ok_or(Error::EmptyVersion)? {
924 get_addresses_infos_request::Version::V0(v0) => v0.addresses,
925 };
926
927 let addresses: Vec<PlatformAddress> = addresses_bytes
928 .into_iter()
929 .map(|bytes| {
930 PlatformAddress::from_bytes(&bytes).map_err(|e| Error::RequestError {
931 error: format!("invalid address: {}", e),
932 })
933 })
934 .collect::<Result<_, _>>()?;
935
936 let (root_hash, entries) = Drive::verify_addresses_infos::<
937 _,
938 Vec<(PlatformAddress, Option<(AddressNonce, Credits)>)>,
939 >(
940 &proof.grovedb_proof,
941 addresses.iter(),
942 false,
943 platform_version,
944 )
945 .map_drive_error(proof, mtd)?;
946
947 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
948
949 let infos = entries
950 .into_iter()
951 .map(|(address, maybe_info)| {
952 let info = maybe_info.map(|(nonce, balance)| AddressInfo {
953 address,
954 nonce,
955 balance,
956 });
957 (address, info)
958 })
959 .collect::<AddressInfos>();
960
961 Ok((Some(infos), mtd.clone(), proof.clone()))
962 }
963}
964
965impl FromProof<platform::GetRecentAddressBalanceChangesRequest> for RecentAddressBalanceChanges {
966 type Request = platform::GetRecentAddressBalanceChangesRequest;
967 type Response = platform::GetRecentAddressBalanceChangesResponse;
968
969 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
970 request: I,
971 response: O,
972 _network: Network,
973 platform_version: &PlatformVersion,
974 provider: &'a dyn ContextProvider,
975 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
976 where
977 RecentAddressBalanceChanges: 'a,
978 {
979 use dapi_grpc::platform::v0::get_recent_address_balance_changes_request;
980
981 let request: Self::Request = request.into();
982 let response: Self::Response = response.into();
983
984 let proof = response.proof().or(Err(Error::NoProofInResult))?;
985 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
986
987 let (start_height, start_height_exclusive) =
988 match request.version.ok_or(Error::EmptyVersion)? {
989 get_recent_address_balance_changes_request::Version::V0(v0) => {
990 (v0.start_height, v0.start_height_exclusive)
991 }
992 };
993
994 let limit = Some(100u16); let (root_hash, verified_changes) = if start_height_exclusive {
997 Drive::verify_recent_address_balance_changes_after(
998 &proof.grovedb_proof,
999 start_height,
1000 limit,
1001 false,
1002 platform_version,
1003 )
1004 .map_drive_error(proof, mtd)?
1005 } else {
1006 Drive::verify_recent_address_balance_changes(
1007 &proof.grovedb_proof,
1008 start_height,
1009 limit,
1010 false,
1011 platform_version,
1012 )
1013 .map_drive_error(proof, mtd)?
1014 };
1015
1016 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1017
1018 let result = RecentAddressBalanceChanges(
1019 verified_changes
1020 .into_iter()
1021 .map(|(block_height, changes)| BlockAddressBalanceChanges {
1022 block_height,
1023 changes,
1024 })
1025 .collect(),
1026 );
1027
1028 Ok((Some(result), mtd.clone(), proof.clone()))
1029 }
1030}
1031
1032impl FromProof<platform::GetRecentCompactedAddressBalanceChangesRequest>
1033 for RecentCompactedAddressBalanceChanges
1034{
1035 type Request = platform::GetRecentCompactedAddressBalanceChangesRequest;
1036 type Response = platform::GetRecentCompactedAddressBalanceChangesResponse;
1037
1038 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1039 request: I,
1040 response: O,
1041 _network: Network,
1042 platform_version: &PlatformVersion,
1043 provider: &'a dyn ContextProvider,
1044 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1045 where
1046 RecentCompactedAddressBalanceChanges: 'a,
1047 {
1048 use dapi_grpc::platform::v0::get_recent_compacted_address_balance_changes_request;
1049
1050 let request: Self::Request = request.into();
1051 let response: Self::Response = response.into();
1052
1053 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1054 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1055
1056 let start_block_height = match request.version.ok_or(Error::EmptyVersion)? {
1057 get_recent_compacted_address_balance_changes_request::Version::V0(v0) => {
1058 v0.start_block_height
1059 }
1060 };
1061
1062 let limit = Some(25u16);
1065
1066 let (root_hash, verified_changes) = Drive::verify_compacted_address_balance_changes(
1067 &proof.grovedb_proof,
1068 start_block_height,
1069 limit,
1070 platform_version,
1071 )
1072 .map_drive_error(proof, mtd)?;
1073
1074 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1075
1076 let result = RecentCompactedAddressBalanceChanges(
1077 verified_changes
1078 .into_iter()
1079 .map(|(start_block_height, end_block_height, changes)| {
1080 CompactedBlockAddressBalanceChanges {
1081 start_block_height,
1082 end_block_height,
1083 changes,
1084 }
1085 })
1086 .collect(),
1087 );
1088
1089 Ok((Some(result), mtd.clone(), proof.clone()))
1090 }
1091}
1092
1093impl FromProof<platform::GetAddressesTrunkStateRequest> for GroveTrunkQueryResult {
1094 type Request = platform::GetAddressesTrunkStateRequest;
1095 type Response = platform::GetAddressesTrunkStateResponse;
1096
1097 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1098 _request: I,
1099 response: O,
1100 _network: Network,
1101 platform_version: &PlatformVersion,
1102 provider: &'a dyn ContextProvider,
1103 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1104 where
1105 GroveTrunkQueryResult: 'a,
1106 {
1107 let response: Self::Response = response.into();
1108
1109 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1110 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1111
1112 let (root_hash, trunk_result) =
1113 Drive::verify_address_funds_trunk_query(&proof.grovedb_proof, platform_version)
1114 .map_drive_error(proof, mtd)?;
1115
1116 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1117
1118 Ok((Some(trunk_result), mtd.clone(), proof.clone()))
1119 }
1120}
1121
1122impl FromProof<platform::GetAddressesTrunkStateRequest> for PlatformAddressTrunkState {
1123 type Request = platform::GetAddressesTrunkStateRequest;
1124 type Response = platform::GetAddressesTrunkStateResponse;
1125
1126 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1127 request: I,
1128 response: O,
1129 network: Network,
1130 platform_version: &PlatformVersion,
1131 provider: &'a dyn ContextProvider,
1132 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1133 where
1134 PlatformAddressTrunkState: 'a,
1135 {
1136 let (result, metadata, proof) = <GroveTrunkQueryResult as FromProof<
1137 platform::GetAddressesTrunkStateRequest,
1138 >>::maybe_from_proof_with_metadata(
1139 request, response, network, platform_version, provider
1140 )?;
1141
1142 Ok((result.map(PlatformAddressTrunkState), metadata, proof))
1143 }
1144}
1145
1146impl FromProof<platform::GetDataContractRequest> for DataContract {
1147 type Request = platform::GetDataContractRequest;
1148 type Response = platform::GetDataContractResponse;
1149
1150 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1151 request: I,
1152 response: O,
1153 _network: Network,
1154 platform_version: &PlatformVersion,
1155 provider: &'a dyn ContextProvider,
1156 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1157 where
1158 DataContract: 'a,
1159 {
1160 let request: Self::Request = request.into();
1161 let response: Self::Response = response.into();
1162
1163 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1165
1166 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1167
1168 let id = match request.version.ok_or(Error::EmptyVersion)? {
1169 get_data_contract_request::Version::V0(v0) => {
1170 Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
1171 error: e.to_string(),
1172 })
1173 }
1174 }?;
1175
1176 let (root_hash, maybe_contract) = Drive::verify_contract(
1178 &proof.grovedb_proof,
1179 None,
1180 false,
1181 false,
1182 id.into_buffer(),
1183 platform_version,
1184 )
1185 .map_drive_error(proof, mtd)?;
1186
1187 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1188
1189 Ok((maybe_contract, mtd.clone(), proof.clone()))
1190 }
1191}
1192
1193impl FromProof<platform::GetDataContractRequest> for (DataContract, Vec<u8>) {
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_return_serialization(
1225 &proof.grovedb_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::GetDataContractsRequest> for DataContracts {
1241 type Request = platform::GetDataContractsRequest;
1242 type Response = platform::GetDataContractsResponse;
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 DataContracts: '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 ids = match request.version.ok_or(Error::EmptyVersion)? {
1263 get_data_contracts_request::Version::V0(v0) => v0.ids,
1264 };
1265
1266 let ids = ids
1267 .iter()
1268 .map(|id| {
1269 id.clone().try_into().map_err(|_e| Error::RequestError {
1270 error: format!("wrong id size: expected: {}, got: {}", 32, id.len()),
1271 })
1272 })
1273 .collect::<Result<Vec<[u8; 32]>, Error>>()?;
1274
1275 let (root_hash, contracts) = Drive::verify_contracts(
1277 &proof.grovedb_proof,
1278 false,
1279 ids.as_slice(),
1280 platform_version,
1281 )
1282 .map_drive_error(proof, mtd)?;
1283
1284 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1285 let contracts = contracts
1286 .into_iter()
1287 .map(|(k, v)| {
1288 Identifier::from_bytes(&k).map(|id| (id, v)).map_err(|e| {
1289 Error::ResultEncodingError {
1290 error: e.to_string(),
1291 }
1292 })
1293 })
1294 .collect::<Result<DataContracts, Error>>()?;
1295
1296 let maybe_contracts = if contracts.is_empty() {
1297 None
1298 } else {
1299 Some(contracts)
1300 };
1301
1302 Ok((maybe_contracts, mtd.clone(), proof.clone()))
1303 }
1304}
1305
1306impl FromProof<platform::GetDataContractHistoryRequest> for DataContractHistory {
1307 type Request = platform::GetDataContractHistoryRequest;
1308 type Response = platform::GetDataContractHistoryResponse;
1309
1310 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1311 request: I,
1312 response: O,
1313 _network: Network,
1314 platform_version: &PlatformVersion,
1315 provider: &'a dyn ContextProvider,
1316 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1317 where
1318 Self: Sized + 'a,
1319 {
1320 let request: Self::Request = request.into();
1321 let response: Self::Response = response.into();
1322
1323 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1325
1326 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1327
1328 let (id, limit, offset, start_at_ms) = match request.version.ok_or(Error::EmptyVersion)? {
1329 get_data_contract_history_request::Version::V0(v0) => {
1330 let id = Identifier::from_bytes(&v0.id).map_err(|e| Error::ProtocolError {
1331 error: e.to_string(),
1332 })?;
1333 let limit = u32_to_u16_opt(v0.limit.unwrap_or_default())?;
1334 let offset = u32_to_u16_opt(v0.offset.unwrap_or_default())?;
1335 let start_at_ms = v0.start_at_ms;
1336 (id, limit, offset, start_at_ms)
1337 }
1338 };
1339
1340 let (root_hash, maybe_history) = Drive::verify_contract_history(
1342 &proof.grovedb_proof,
1343 id.into_buffer(),
1344 start_at_ms,
1345 limit,
1346 offset,
1347 platform_version,
1348 )
1349 .map_drive_error(proof, mtd)?;
1350
1351 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1352
1353 Ok((
1354 maybe_history.map(IndexMap::from_iter),
1355 mtd.clone(),
1356 proof.clone(),
1357 ))
1358 }
1359}
1360
1361impl FromProof<platform::GetDocumentHistoryRequest> for DocumentHistory {
1362 type Request = platform::GetDocumentHistoryRequest;
1363 type Response = platform::GetDocumentHistoryResponse;
1364
1365 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1366 request: I,
1367 response: O,
1368 _network: Network,
1369 platform_version: &PlatformVersion,
1370 provider: &'a dyn ContextProvider,
1371 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1372 where
1373 Self: Sized + 'a,
1374 {
1375 let request: Self::Request = request.into();
1376 let response: Self::Response = response.into();
1377
1378 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1379 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1380
1381 let (contract_id, document_type_name, document_id, limit, offset, start_at_ms) =
1382 match request.version.ok_or(Error::EmptyVersion)? {
1383 get_document_history_request::Version::V0(v0) => {
1384 let contract_id =
1385 Identifier::from_bytes(&v0.data_contract_id).map_err(|e| {
1386 Error::ProtocolError {
1387 error: e.to_string(),
1388 }
1389 })?;
1390 let document_id = Identifier::from_bytes(&v0.document_id).map_err(|e| {
1391 Error::ProtocolError {
1392 error: e.to_string(),
1393 }
1394 })?;
1395 let limit = u32_to_u16_opt(v0.limit.unwrap_or_default())?;
1396 let offset = u32_to_u16_opt(v0.offset.unwrap_or_default())?;
1397 (
1398 contract_id,
1399 v0.document_type_name,
1400 document_id,
1401 limit,
1402 offset,
1403 v0.start_at_ms,
1404 )
1405 }
1406 };
1407
1408 let data_contract = provider
1409 .get_data_contract(&contract_id, platform_version)?
1410 .ok_or(Error::NotFound)?;
1411 let document_type = data_contract
1412 .document_type_for_name(&document_type_name)
1413 .map_err(|e| Error::ProtocolError {
1414 error: e.to_string(),
1415 })?;
1416
1417 let (root_hash, maybe_history) = Drive::verify_document_history(
1418 &proof.grovedb_proof,
1419 contract_id.into_buffer(),
1420 &document_type_name,
1421 document_type,
1422 document_id.into_buffer(),
1423 start_at_ms,
1424 limit,
1425 offset,
1426 platform_version,
1427 )
1428 .map_drive_error(proof, mtd)?;
1429
1430 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1431
1432 Ok((
1437 maybe_history.map(IndexMap::from_iter),
1438 mtd.clone(),
1439 proof.clone(),
1440 ))
1441 }
1442}
1443
1444impl FromProof<platform::BroadcastStateTransitionRequest> for StateTransitionProofResult {
1445 type Request = platform::BroadcastStateTransitionRequest;
1446 type Response = platform::WaitForStateTransitionResultResponse;
1447
1448 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1449 request: I,
1450 response: O,
1451 _network: Network,
1452 platform_version: &PlatformVersion,
1453 provider: &'a dyn ContextProvider,
1454 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1455 where
1456 Self: Sized + 'a,
1457 {
1458 let request: Self::Request = request.into();
1459 let response: Self::Response = response.into();
1460
1461 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1463
1464 let state_transition = StateTransition::deserialize_from_bytes(&request.state_transition)
1465 .map_err(|e| Error::ProtocolError {
1466 error: e.to_string(),
1467 })?;
1468
1469 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1470
1471 let epoch_u16 = try_u32_to_u16(mtd.epoch).map_err(|_| {
1472 Into::<Error>::into(drive::error::Error::Proof(ProofError::InvalidMetadata(
1473 format!(
1474 "platform returned an epoch {} that was higher than maximum of a 16 bit integer",
1475 mtd.epoch
1476 ),
1477 )))
1478 })?;
1479
1480 let block_info = BlockInfo {
1481 time_ms: mtd.time_ms,
1482 height: mtd.height,
1483 core_height: mtd.core_chain_locked_height,
1484 epoch: epoch_u16.try_into()?,
1485 };
1486
1487 let contracts_provider_fn = provider.as_contract_lookup_fn(platform_version);
1488
1489 let (root_hash, result) = Drive::verify_state_transition_was_executed_with_proof(
1490 &state_transition,
1491 &block_info,
1492 &proof.grovedb_proof,
1493 &contracts_provider_fn,
1494 platform_version,
1495 )
1496 .map_drive_error(proof, mtd)?;
1497
1498 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1499
1500 Ok((Some(result), mtd.clone(), proof.clone()))
1501 }
1502}
1503
1504impl FromProof<platform::GetEpochsInfoRequest> for ExtendedEpochInfo {
1505 type Request = platform::GetEpochsInfoRequest;
1506 type Response = platform::GetEpochsInfoResponse;
1507
1508 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1509 request: I,
1510 response: O,
1511 network: Network,
1512 platform_version: &PlatformVersion,
1513 provider: &'a dyn ContextProvider,
1514 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1515 where
1516 Self: Sized + 'a,
1517 {
1518 let epochs = ExtendedEpochInfos::maybe_from_proof_with_metadata(
1519 request,
1520 response,
1521 network,
1522 platform_version,
1523 provider,
1524 )?;
1525
1526 if let Some(e) = epochs.0 {
1527 if e.len() != 1 {
1528 return Err(Error::RequestError {
1529 error: format!("expected 1 epoch, got {}", e.len()),
1530 });
1531 }
1532 let epoch = e.into_iter().next().and_then(|v| v.1);
1533 Ok((epoch, epochs.1, epochs.2))
1534 } else {
1535 Ok((None, epochs.1, epochs.2))
1536 }
1537 }
1538}
1539
1540impl FromProof<platform::GetEpochsInfoRequest> for ExtendedEpochInfos {
1541 type Request = platform::GetEpochsInfoRequest;
1542 type Response = platform::GetEpochsInfoResponse;
1543
1544 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1545 request: I,
1546 response: O,
1547 _network: Network,
1548 platform_version: &PlatformVersion,
1549 provider: &'a dyn ContextProvider,
1550 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1551 where
1552 Self: Sized + 'a,
1553 {
1554 let request: Self::Request = request.into();
1555 let response: Self::Response = response.into();
1556 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1558
1559 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1560
1561 let (start_epoch, count, ascending) = match request.version.ok_or(Error::EmptyVersion)? {
1562 get_epochs_info_request::Version::V0(v0) => (v0.start_epoch, v0.count, v0.ascending),
1563 };
1564
1565 let current_epoch: EpochIndex = try_u32_to_u16(mtd.epoch)?;
1566 let start_epoch: Option<EpochIndex> = if let Some(epoch) = start_epoch {
1567 Some(try_u32_to_u16(epoch)?)
1568 } else {
1569 None
1570 };
1571 let count = try_u32_to_u16(count)?;
1572
1573 let (root_hash, epoch_info) = Drive::verify_epoch_infos(
1574 &proof.grovedb_proof,
1575 current_epoch,
1576 start_epoch,
1577 count,
1578 ascending,
1579 platform_version,
1580 )
1581 .map_drive_error(proof, mtd)?;
1582
1583 let epoch_info = epoch_info
1584 .into_iter()
1585 .map(|v| {
1586 #[allow(clippy::infallible_destructuring_match)]
1587 let info = match &v {
1588 ExtendedEpochInfo::V0(i) => i,
1589 };
1590
1591 (info.index, Some(v))
1592 })
1593 .collect::<ExtendedEpochInfos>();
1594
1595 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1596
1597 Ok((epoch_info.into_option(), mtd.clone(), proof.clone()))
1598 }
1599}
1600
1601impl FromProof<platform::GetFinalizedEpochInfosRequest> for FinalizedEpochInfos {
1602 type Request = platform::GetFinalizedEpochInfosRequest;
1603 type Response = platform::GetFinalizedEpochInfosResponse;
1604
1605 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1606 request: I,
1607 response: O,
1608 _network: Network,
1609 platform_version: &PlatformVersion,
1610 provider: &'a dyn ContextProvider,
1611 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1612 where
1613 Self: Sized + 'a,
1614 {
1615 let request: Self::Request = request.into();
1616 let response: Self::Response = response.into();
1617 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1619
1620 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1621
1622 let (
1623 start_epoch_index,
1624 start_epoch_index_included,
1625 end_epoch_index,
1626 end_epoch_index_included,
1627 ) = match request.version.ok_or(Error::EmptyVersion)? {
1628 get_finalized_epoch_infos_request::Version::V0(v0) => (
1629 v0.start_epoch_index,
1630 v0.start_epoch_index_included,
1631 v0.end_epoch_index,
1632 v0.end_epoch_index_included,
1633 ),
1634 };
1635
1636 let start_epoch_index: EpochIndex = try_u32_to_u16(start_epoch_index)?;
1637 let end_epoch_index: EpochIndex = try_u32_to_u16(end_epoch_index)?;
1638
1639 let (root_hash, epoch_info) = Drive::verify_finalized_epoch_infos(
1640 &proof.grovedb_proof,
1641 start_epoch_index,
1642 start_epoch_index_included,
1643 end_epoch_index,
1644 end_epoch_index_included,
1645 platform_version,
1646 )
1647 .map_drive_error(proof, mtd)?;
1648
1649 let epoch_info = epoch_info
1650 .into_iter()
1651 .map(|(epoch_index, finalized_epoch_info)| (epoch_index, Some(finalized_epoch_info)))
1652 .collect::<FinalizedEpochInfos>();
1653
1654 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1655
1656 Ok((epoch_info.into_option(), mtd.clone(), proof.clone()))
1657 }
1658}
1659
1660fn try_u32_to_u16(i: u32) -> Result<u16, Error> {
1661 i.try_into()
1662 .map_err(|e: TryFromIntError| Error::RequestError {
1663 error: e.to_string(),
1664 })
1665}
1666
1667impl FromProof<GetProtocolVersionUpgradeStateRequest> for ProtocolVersionUpgrades {
1668 type Request = GetProtocolVersionUpgradeStateRequest;
1669 type Response = GetProtocolVersionUpgradeStateResponse;
1670
1671 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1672 _request: I,
1673 response: O,
1674 _network: Network,
1675 platform_version: &PlatformVersion,
1676 provider: &'a dyn ContextProvider,
1677 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1678 where
1679 Self: Sized + 'a,
1680 {
1681 let response: Self::Response = response.into();
1682 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1684 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1685
1686 let (root_hash, objects) =
1687 Drive::verify_upgrade_state(&proof.grovedb_proof, platform_version)
1688 .map_drive_error(proof, mtd)?;
1689
1690 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1691
1692 let response: Self = objects.into_iter().map(|(k, v)| (k, Some(v))).collect();
1694
1695 Ok((response.into_option(), mtd.clone(), proof.clone()))
1696 }
1697}
1698
1699impl FromProof<GetProtocolVersionUpgradeVoteStatusRequest> for MasternodeProtocolVotes {
1700 type Request = GetProtocolVersionUpgradeVoteStatusRequest;
1701 type Response = GetProtocolVersionUpgradeVoteStatusResponse;
1702
1703 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1704 request: I,
1705 response: O,
1706 _network: Network,
1707 platform_version: &PlatformVersion,
1708 provider: &'a dyn ContextProvider,
1709 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1710 where
1711 Self: Sized + 'a,
1712 {
1713 let request = request.into();
1714 let response: Self::Response = response.into();
1715 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1717 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1718
1719 let request_v0: GetProtocolVersionUpgradeVoteStatusRequestV0 = match request.version {
1720 Some(get_protocol_version_upgrade_vote_status_request::Version::V0(v0)) => v0,
1721 None => return Err(Error::EmptyVersion),
1722 };
1723
1724 let start_pro_tx_hash: Option<[u8; 32]> =
1725 if request_v0.start_pro_tx_hash.is_empty() {
1726 None
1727 } else {
1728 Some(request_v0.start_pro_tx_hash[..].try_into().map_err(
1729 |e: TryFromSliceError| Error::RequestError {
1730 error: e.to_string(),
1731 },
1732 )?)
1733 };
1734
1735 let (root_hash, objects) = Drive::verify_upgrade_vote_status(
1736 &proof.grovedb_proof,
1737 start_pro_tx_hash,
1738 try_u32_to_u16(request_v0.count)?,
1739 platform_version,
1740 )
1741 .map_drive_error(proof, mtd)?;
1742
1743 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1744
1745 if objects.is_empty() {
1746 return Ok((None, mtd.clone(), proof.clone()));
1747 }
1748 let votes: MasternodeProtocolVotes = objects
1749 .into_iter()
1750 .map(|(key, value)| {
1751 ProTxHash::from_slice(&key)
1752 .map(|pro_tx_hash| {
1753 (
1754 pro_tx_hash,
1755 Some(MasternodeProtocolVote {
1756 pro_tx_hash,
1757 voted_version: value,
1758 }),
1759 )
1760 })
1761 .map_err(|e| Error::ResultEncodingError {
1762 error: e.to_string(),
1763 })
1764 })
1765 .collect::<Result<MasternodeProtocolVotes, Error>>()?;
1766
1767 Ok((votes.into_option(), mtd.clone(), proof.clone()))
1768 }
1769}
1770
1771impl FromProof<GetPathElementsRequest> for Elements {
1772 type Request = GetPathElementsRequest;
1773 type Response = GetPathElementsResponse;
1774
1775 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1776 request: I,
1777 response: O,
1778 _network: Network,
1779 platform_version: &PlatformVersion,
1780 provider: &'a dyn ContextProvider,
1781 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1782 where
1783 Self: Sized + 'a,
1784 {
1785 let request = request.into();
1786 let response: Self::Response = response.into();
1787 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1789 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1790
1791 let request_v0: GetPathElementsRequestV0 = match request.version {
1792 Some(get_path_elements_request::Version::V0(v0)) => v0,
1793 None => return Err(Error::EmptyVersion),
1794 };
1795
1796 let path = request_v0.path;
1797 let keys = request_v0.keys;
1798
1799 let (root_hash, objects) =
1800 Drive::verify_elements(&proof.grovedb_proof, path, keys, platform_version)?;
1801 let elements: Elements = Elements::from_iter(objects);
1802
1803 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1804
1805 Ok((elements.into_option(), mtd.clone(), proof.clone()))
1806 }
1807}
1808
1809impl<'dq, Q> FromProof<Q> for Documents
1810where
1811 Q: TryInto<DriveDocumentQuery<'dq>> + Clone + 'dq,
1812 Q::Error: std::fmt::Display,
1813{
1814 type Request = Q;
1815 type Response = platform::GetDocumentsResponse;
1816
1817 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1818 request: I,
1819 response: O,
1820 _network: Network,
1821 platform_version: &PlatformVersion,
1822 provider: &'a dyn ContextProvider,
1823 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1824 where
1825 Self: 'a,
1826 {
1827 let request: Self::Request = request.into();
1828 let response: Self::Response = response.into();
1829
1830 let request: DriveDocumentQuery<'dq> =
1831 request
1832 .clone()
1833 .try_into()
1834 .map_err(|e: Q::Error| Error::RequestError {
1835 error: e.to_string(),
1836 })?;
1837
1838 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1840
1841 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1842
1843 let (root_hash, documents) = request
1844 .verify_proof(&proof.grovedb_proof, platform_version)
1845 .map_drive_error(proof, mtd)?;
1846
1847 let documents = documents
1848 .into_iter()
1849 .map(|d| (d.id(), Some(d)))
1850 .collect::<Documents>();
1851
1852 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1853
1854 Ok((documents.into_option(), mtd.clone(), proof.clone()))
1855 }
1856}
1857
1858impl FromProof<platform::GetIdentitiesContractKeysRequest> for IdentitiesContractKeys {
1859 type Request = platform::GetIdentitiesContractKeysRequest;
1860 type Response = platform::GetIdentitiesContractKeysResponse;
1861
1862 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1863 request: I,
1864 response: O,
1865 _network: Network,
1866 platform_version: &PlatformVersion,
1867 provider: &'a dyn ContextProvider,
1868 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1869 where
1870 Self: 'a,
1871 {
1872 let request: Self::Request = request.into();
1873 let response: Self::Response = response.into();
1874
1875 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1877
1878 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1879
1880 let (identities_ids, contract_id, document_type_name, purposes) =
1881 match request.version.ok_or(Error::EmptyVersion)? {
1882 get_identities_contract_keys_request::Version::V0(v0) => {
1883 let GetIdentitiesContractKeysRequestV0 {
1884 identities_ids,
1885 contract_id,
1886 document_type_name,
1887 purposes,
1888 ..
1889 } = v0;
1890 let identifiers = identities_ids
1891 .into_iter()
1892 .map(|identity_id_vec| {
1893 let identifier = Identifier::from_vec(identity_id_vec)?;
1894 Ok(identifier.to_buffer())
1895 })
1896 .collect::<Result<Vec<[u8; 32]>, platform_value::Error>>()
1897 .map_err(|e| Error::ProtocolError {
1898 error: e.to_string(),
1899 })?;
1900 let contract_id = Identifier::from_vec(contract_id)
1901 .map_err(|e| Error::ProtocolError {
1902 error: e.to_string(),
1903 })?
1904 .into_buffer();
1905 let purposes = purposes
1906 .into_iter()
1907 .map(|purpose| {
1908 Purpose::try_from(purpose).map_err(|e| Error::ProtocolError {
1909 error: e.to_string(),
1910 })
1911 })
1912 .collect::<Result<Vec<Purpose>, Error>>()?;
1913 (identifiers, contract_id, document_type_name, purposes)
1914 }
1915 };
1916
1917 let (root_hash, identities_contract_keys) = Drive::verify_identities_contract_keys(
1919 &proof.grovedb_proof,
1920 identities_ids.as_slice(),
1921 &contract_id,
1922 document_type_name,
1923 purposes,
1924 false,
1925 platform_version,
1926 )
1927 .map_drive_error(proof, mtd)?;
1928
1929 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1930
1931 if identities_contract_keys.is_empty() {
1932 return Ok((None, mtd.clone(), proof.clone()));
1933 }
1934
1935 Ok((Some(identities_contract_keys), mtd.clone(), proof.clone()))
1936 }
1937}
1938
1939impl FromProof<platform::GetContestedResourcesRequest> for ContestedResources {
1940 type Request = platform::GetContestedResourcesRequest;
1941 type Response = platform::GetContestedResourcesResponse;
1942
1943 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1944 request: I,
1945 response: O,
1946 _network: Network,
1947 platform_version: &PlatformVersion,
1948 provider: &'a dyn ContextProvider,
1949 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1950 where
1951 Self: Sized + 'a,
1952 {
1953 let request: Self::Request = request.into();
1954 let response: Self::Response = response.into();
1955
1956 let drive_query = VotePollsByDocumentTypeQuery::try_from_request(request)?;
1958 let resolved_request = drive_query.resolve_with_known_contracts_provider(
1959 &provider.as_contract_lookup_fn(platform_version),
1960 )?;
1961
1962 let proof = response.proof().or(Err(Error::NoProofInResult))?;
1964 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
1965
1966 let (root_hash, items) = resolved_request
1967 .verify_contests_proof(&proof.grovedb_proof, platform_version)
1968 .map_drive_error(proof, mtd)?;
1969
1970 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
1971
1972 let resources: ContestedResources = items.into_iter().map(ContestedResource).collect();
1973
1974 Ok((resources.into_option(), mtd.clone(), proof.clone()))
1975 }
1976}
1977
1978impl FromProof<platform::GetContestedResourceVoteStateRequest> for Contenders {
1980 type Request = platform::GetContestedResourceVoteStateRequest;
1981 type Response = platform::GetContestedResourceVoteStateResponse;
1982
1983 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
1984 request: I,
1985 response: O,
1986 _network: Network,
1987 platform_version: &PlatformVersion,
1988 provider: &'a dyn ContextProvider,
1989 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
1990 where
1991 Self: 'a,
1992 {
1993 let request: Self::Request = request.into();
1994 let response: Self::Response = response.into();
1995
1996 let drive_query = ContestedDocumentVotePollDriveQuery::try_from_request(request)?;
1998
1999 let contracts_provider = provider.as_contract_lookup_fn(platform_version);
2001 let resolved_request =
2002 drive_query.resolve_with_known_contracts_provider(&contracts_provider)?;
2003
2004 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2006 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2007
2008 let (root_hash, contested_resource_vote_state) = resolved_request
2009 .verify_vote_poll_vote_state_proof(&proof.grovedb_proof, platform_version)
2010 .map_drive_error(proof, mtd)?;
2011
2012 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2013
2014 let contenders = contested_resource_vote_state
2015 .contenders
2016 .into_iter()
2017 .map(|v| (v.identity_id(), v))
2018 .collect();
2019
2020 let response = Contenders {
2021 winner: contested_resource_vote_state.winner,
2022 contenders,
2023 abstain_vote_tally: contested_resource_vote_state.abstaining_vote_tally,
2024 lock_vote_tally: contested_resource_vote_state.locked_vote_tally,
2025 };
2026 Ok((response.into_option(), mtd.clone(), proof.clone()))
2027 }
2028}
2029
2030impl FromProof<GetContestedResourceVotersForIdentityRequest> for Voters {
2031 type Request = GetContestedResourceVotersForIdentityRequest;
2032 type Response = GetContestedResourceVotersForIdentityResponse;
2033
2034 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2035 request: I,
2036 response: O,
2037 _network: Network,
2038 platform_version: &PlatformVersion,
2039 provider: &'a dyn ContextProvider,
2040 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2041 where
2042 Self: Sized + 'a,
2043 {
2044 let request: Self::Request = request.into();
2045 let response: Self::Response = response.into();
2046
2047 let drive_query = ContestedDocumentVotePollVotesDriveQuery::try_from_request(request)?;
2049
2050 let contracts_provider = provider.as_contract_lookup_fn(platform_version);
2052
2053 let resolved_request =
2054 drive_query.resolve_with_known_contracts_provider(&contracts_provider)?;
2055
2056 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2058 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2059
2060 let (root_hash, voters) = resolved_request
2061 .verify_vote_poll_votes_proof(&proof.grovedb_proof, platform_version)
2062 .map_drive_error(proof, mtd)?;
2063
2064 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2065
2066 if voters.is_empty() {
2067 return Ok((None, mtd.clone(), proof.clone()));
2068 }
2069 let result: Voters = voters.into_iter().map(Voter::from).collect();
2070
2071 Ok((result.into_option(), mtd.clone(), proof.clone()))
2072 }
2073}
2074
2075impl FromProof<platform::GetContestedResourceIdentityVotesRequest> for ResourceVotesByIdentity {
2076 type Request = platform::GetContestedResourceIdentityVotesRequest;
2077 type Response = platform::GetContestedResourceIdentityVotesResponse;
2078
2079 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2080 request: I,
2081 response: O,
2082 _network: Network,
2083 platform_version: &PlatformVersion,
2084 provider: &'a dyn ContextProvider,
2085 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2086 where
2087 Self: Sized + 'a,
2088 {
2089 let request: Self::Request = request.into();
2090 let response: Self::Response = response.into();
2091
2092 let drive_query = ContestedResourceVotesGivenByIdentityQuery::try_from_request(request)?;
2094
2095 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2097 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2098
2099 let contract_provider_fn = provider.as_contract_lookup_fn(platform_version);
2100 let (root_hash, voters) = drive_query
2101 .verify_identity_votes_given_proof::<Vec<_>>(
2102 &proof.grovedb_proof,
2103 &contract_provider_fn,
2104 platform_version,
2105 )
2106 .map_drive_error(proof, mtd)?;
2107
2108 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2109
2110 let response: ResourceVotesByIdentity = voters
2111 .into_iter()
2112 .map(|(id, vote)| (id, Some(vote)))
2113 .collect();
2114
2115 Ok((response.into_option(), mtd.clone(), proof.clone()))
2116 }
2117}
2118
2119impl FromProof<platform::GetVotePollsByEndDateRequest> for VotePollsGroupedByTimestamp {
2120 type Request = platform::GetVotePollsByEndDateRequest;
2121 type Response = platform::GetVotePollsByEndDateResponse;
2122
2123 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2124 request: I,
2125 response: O,
2126 _network: Network,
2127 platform_version: &PlatformVersion,
2128 provider: &'a dyn ContextProvider,
2129 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2130 where
2131 Self: Sized + 'a,
2132 {
2133 let request: Self::Request = request.into();
2134 let response: Self::Response = response.into();
2135
2136 let drive_query = VotePollsByEndDateDriveQuery::try_from_request(request)?;
2138
2139 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2141 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2142
2143 let (root_hash, vote_polls) = drive_query
2144 .verify_vote_polls_by_end_date_proof::<Vec<(_, _)>>(
2145 &proof.grovedb_proof,
2146 platform_version,
2147 )
2148 .map_drive_error(proof, mtd)?;
2149
2150 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2151
2152 let response = VotePollsGroupedByTimestamp(vote_polls).sorted(drive_query.order_ascending);
2153
2154 Ok((response.into_option(), mtd.clone(), proof.clone()))
2155 }
2156}
2157
2158impl FromProof<platform::GetPrefundedSpecializedBalanceRequest> for PrefundedSpecializedBalance {
2159 type Request = platform::GetPrefundedSpecializedBalanceRequest;
2160 type Response = platform::GetPrefundedSpecializedBalanceResponse;
2161
2162 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2163 request: I,
2164 response: O,
2165 _network: Network,
2166 platform_version: &PlatformVersion,
2167 provider: &'a dyn ContextProvider,
2168 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2169 where
2170 Self: Sized + 'a,
2171 {
2172 let request: Self::Request = request.into();
2173 let response: Self::Response = response.into();
2174
2175 let balance_id = match request.version.ok_or(Error::EmptyVersion)? {
2176 get_prefunded_specialized_balance_request::Version::V0(v0) => {
2177 Identifier::from_vec(v0.id).map_err(|e| Error::RequestError {
2178 error: e.to_string(),
2179 })?
2180 }
2181 };
2182
2183 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2184
2185 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2186
2187 let (root_hash, balance) = Drive::verify_specialized_balance(
2188 &proof.grovedb_proof,
2189 balance_id.into_buffer(),
2190 false,
2191 platform_version,
2192 )
2193 .map_drive_error(proof, mtd)?;
2194
2195 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2196
2197 Ok((balance.map(|v| v.into()), mtd.clone(), proof.clone()))
2198 }
2199}
2200
2201impl FromProof<platform::GetContestedResourceIdentityVotesRequest> for Vote {
2202 type Request = platform::GetContestedResourceIdentityVotesRequest;
2203 type Response = platform::GetContestedResourceIdentityVotesResponse;
2204
2205 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2206 request: I,
2207 response: O,
2208 network: Network,
2209 platform_version: &PlatformVersion,
2210 provider: &'a dyn ContextProvider,
2211 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2212 where
2213 Self: Sized + 'a,
2214 {
2215 let request = request.into();
2216 let id_in_request = match request.version.as_ref().ok_or(Error::EmptyVersion)? {
2217 get_contested_resource_identity_votes_request::Version::V0(v0) => {
2218 Identifier::from_bytes(&v0.identity_id).map_err(|e| Error::RequestError {
2219 error: e.to_string(),
2220 })?
2221 }
2222 };
2223
2224 let (maybe_votes, mtd, proof) = ResourceVotesByIdentity::maybe_from_proof_with_metadata(
2225 request,
2226 response,
2227 network,
2228 platform_version,
2229 provider,
2230 )?;
2231
2232 let (id, vote) = match maybe_votes {
2233 Some(v) if v.len() > 1 => {
2234 return Err(Error::ResponseDecodeError {
2235 error: format!("expected 1 vote, got {}", v.len()),
2236 })
2237 }
2238 Some(v) if v.is_empty() => return Ok((None, mtd, proof)),
2239 Some(v) => v
2240 .into_iter()
2241 .next()
2242 .expect("is_empty() must detect empty map"),
2243 None => return Ok((None, mtd, proof)),
2244 };
2245
2246 if id != id_in_request {
2247 return Err(Error::ResponseDecodeError {
2248 error: format!(
2249 "expected vote for identity {}, got vote for identity {}",
2250 id_in_request, id
2251 ),
2252 });
2253 }
2254
2255 Ok((vote.map(Vote::ResourceVote), mtd, proof))
2256 }
2257}
2258
2259impl FromProof<platform::GetTotalCreditsInPlatformRequest> for TotalCreditsInPlatform {
2260 type Request = platform::GetTotalCreditsInPlatformRequest;
2261 type Response = platform::GetTotalCreditsInPlatformResponse;
2262
2263 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2264 _request: I,
2265 response: O,
2266 network: Network,
2267 platform_version: &PlatformVersion,
2268 provider: &'a dyn ContextProvider,
2269 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2270 where
2271 Self: Sized + 'a,
2272 {
2273 let response: Self::Response = response.into();
2274 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2276 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2277
2278 let core_subsidy_halving_interval = network.core_subsidy_halving_interval();
2279
2280 let (root_hash, credits) = Drive::verify_total_credits_in_system(
2281 &proof.grovedb_proof,
2282 core_subsidy_halving_interval,
2283 || {
2284 provider.get_platform_activation_height().map_err(|e| {
2285 drive::error::Error::Proof(ProofError::MissingContextRequirement(e.to_string()))
2286 })
2287 },
2288 mtd.core_chain_locked_height,
2289 platform_version,
2290 )
2291 .map_drive_error(proof, mtd)?;
2292
2293 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2294
2295 Ok((
2296 Some(TotalCreditsInPlatform(credits)),
2297 mtd.clone(),
2298 proof.clone(),
2299 ))
2300 }
2301}
2302impl FromProof<platform::GetEvonodesProposedEpochBlocksByIdsRequest> for ProposerBlockCounts {
2303 type Request = platform::GetEvonodesProposedEpochBlocksByIdsRequest;
2304 type Response = platform::GetEvonodesProposedEpochBlocksResponse;
2305
2306 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2307 request: I,
2308 response: O,
2309 _network: Network,
2310 platform_version: &PlatformVersion,
2311 provider: &'a dyn ContextProvider,
2312 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2313 where
2314 Self: Sized + 'a,
2315 {
2316 let request: Self::Request = request.into();
2317 let response: Self::Response = response.into();
2318 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2320 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2321
2322 let (ids, epoch) = match request.version.ok_or(Error::EmptyVersion)? {
2323 get_evonodes_proposed_epoch_blocks_by_ids_request::Version::V0(v0) => {
2324 (v0.ids, v0.epoch)
2325 }
2326 };
2327
2328 let epoch_index = match epoch {
2329 Some(index) => try_u32_to_u16(index)?,
2330 None => try_u32_to_u16(mtd.epoch)?,
2331 };
2332
2333 let (root_hash, proposer_block_counts) = Drive::verify_epoch_proposers(
2334 &proof.grovedb_proof,
2335 epoch_index,
2336 ProposerQueryType::ByIds(ids),
2337 platform_version,
2338 )
2339 .map_drive_error(proof, mtd)?;
2340
2341 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2342
2343 Ok((
2344 Some(ProposerBlockCounts(proposer_block_counts)),
2345 mtd.clone(),
2346 proof.clone(),
2347 ))
2348 }
2349}
2350
2351impl FromProof<platform::GetEvonodesProposedEpochBlocksByRangeRequest> for ProposerBlockCounts {
2352 type Request = platform::GetEvonodesProposedEpochBlocksByRangeRequest;
2353 type Response = platform::GetEvonodesProposedEpochBlocksResponse;
2354
2355 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2356 request: I,
2357 response: O,
2358 _network: Network,
2359 platform_version: &PlatformVersion,
2360 provider: &'a dyn ContextProvider,
2361 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2362 where
2363 Self: Sized + 'a,
2364 {
2365 let request: Self::Request = request.into();
2366 let response: Self::Response = response.into();
2367 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2369 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2370
2371 let (epoch, limit, start) = match request.version.ok_or(Error::EmptyVersion)? {
2372 get_evonodes_proposed_epoch_blocks_by_range_request::Version::V0(v0) => {
2373 (v0.epoch, v0.limit, v0.start)
2374 }
2375 };
2376
2377 let formatted_start = match start {
2378 None => None,
2379 Some(Start::StartAfter(after)) => {
2380 let id: [u8; 32] = after.try_into().map_err(|_| Error::DriveError {
2381 error: "Invalid public key hash length".to_string(),
2382 })?;
2383 Some((id, false))
2384 }
2385 Some(Start::StartAt(at)) => {
2386 let id: [u8; 32] = at.try_into().map_err(|_| Error::DriveError {
2387 error: "Invalid public key hash length".to_string(),
2388 })?;
2389 Some((id, true))
2390 }
2391 };
2392
2393 let epoch_index = match epoch {
2394 Some(index) => try_u32_to_u16(index)?,
2395 None => try_u32_to_u16(mtd.epoch)?,
2396 };
2397 let checked_limit = limit.map(try_u32_to_u16).transpose()?;
2398
2399 let (root_hash, proposer_block_counts) = Drive::verify_epoch_proposers(
2400 &proof.grovedb_proof,
2401 epoch_index,
2402 ProposerQueryType::ByRange(checked_limit, formatted_start),
2403 platform_version,
2404 )
2405 .map_drive_error(proof, mtd)?;
2406
2407 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2408
2409 Ok((
2410 Some(ProposerBlockCounts(proposer_block_counts)),
2411 mtd.clone(),
2412 proof.clone(),
2413 ))
2414 }
2415}
2416
2417fn u32_to_u16_opt(i: u32) -> Result<Option<u16>, Error> {
2420 let i: Option<u16> = if i != 0 {
2421 let i: u16 = i
2422 .try_into()
2423 .map_err(|e: TryFromIntError| Error::RequestError {
2424 error: format!("value {} out of range: {}", i, e),
2425 })?;
2426 Some(i)
2427 } else {
2428 None
2429 };
2430
2431 Ok(i)
2432}
2433
2434impl FromProof<platform::GetShieldedPoolStateRequest> for ShieldedPoolState {
2437 type Request = platform::GetShieldedPoolStateRequest;
2438 type Response = platform::GetShieldedPoolStateResponse;
2439
2440 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2441 _request: I,
2442 response: O,
2443 _network: Network,
2444 platform_version: &PlatformVersion,
2445 provider: &'a dyn ContextProvider,
2446 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2447 where
2448 Self: Sized + 'a,
2449 {
2450 let response: Self::Response = response.into();
2451 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2452 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2453
2454 let (root_hash, maybe_balance) =
2455 Drive::verify_shielded_pool_state(&proof.grovedb_proof, false, platform_version)
2456 .map_drive_error(proof, mtd)?;
2457
2458 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2459
2460 Ok((
2461 maybe_balance.map(ShieldedPoolState),
2462 mtd.clone(),
2463 proof.clone(),
2464 ))
2465 }
2466}
2467
2468impl FromProof<platform::GetShieldedNotesCountRequest> for ShieldedNotesCount {
2469 type Request = platform::GetShieldedNotesCountRequest;
2470 type Response = platform::GetShieldedNotesCountResponse;
2471
2472 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2473 _request: I,
2474 response: O,
2475 _network: Network,
2476 platform_version: &PlatformVersion,
2477 provider: &'a dyn ContextProvider,
2478 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2479 where
2480 Self: Sized + 'a,
2481 {
2482 let response: Self::Response = response.into();
2483 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2484 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2485
2486 let (root_hash, maybe_count) =
2491 Drive::verify_shielded_notes_count(&proof.grovedb_proof, false, platform_version)
2492 .map_drive_error(proof, mtd)?;
2493
2494 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2495
2496 Ok((
2497 maybe_count.map(ShieldedNotesCount),
2498 mtd.clone(),
2499 proof.clone(),
2500 ))
2501 }
2502}
2503
2504impl FromProof<platform::GetShieldedAnchorsRequest> for ShieldedAnchors {
2505 type Request = platform::GetShieldedAnchorsRequest;
2506 type Response = platform::GetShieldedAnchorsResponse;
2507
2508 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2509 _request: I,
2510 response: O,
2511 _network: Network,
2512 platform_version: &PlatformVersion,
2513 provider: &'a dyn ContextProvider,
2514 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2515 where
2516 Self: Sized + 'a,
2517 {
2518 let response: Self::Response = response.into();
2519 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2520 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2521
2522 let (root_hash, anchors) =
2523 Drive::verify_shielded_anchors(&proof.grovedb_proof, false, platform_version)
2524 .map_drive_error(proof, mtd)?;
2525
2526 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2527
2528 let result = if anchors.is_empty() {
2529 None
2530 } else {
2531 Some(ShieldedAnchors(anchors))
2532 };
2533
2534 Ok((result, mtd.clone(), proof.clone()))
2535 }
2536}
2537
2538impl FromProof<platform::GetMostRecentShieldedAnchorRequest> for MostRecentShieldedAnchor {
2539 type Request = platform::GetMostRecentShieldedAnchorRequest;
2540 type Response = platform::GetMostRecentShieldedAnchorResponse;
2541
2542 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2543 _request: I,
2544 response: O,
2545 _network: Network,
2546 platform_version: &PlatformVersion,
2547 provider: &'a dyn ContextProvider,
2548 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2549 where
2550 Self: Sized + 'a,
2551 {
2552 let response: Self::Response = response.into();
2553 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2554 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2555
2556 let (root_hash, maybe_anchor) = Drive::verify_most_recent_shielded_anchor(
2557 &proof.grovedb_proof,
2558 false,
2559 platform_version,
2560 )
2561 .map_drive_error(proof, mtd)?;
2562
2563 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2564
2565 Ok((
2566 maybe_anchor.map(MostRecentShieldedAnchor),
2567 mtd.clone(),
2568 proof.clone(),
2569 ))
2570 }
2571}
2572
2573impl FromProof<platform::GetShieldedEncryptedNotesRequest> for ShieldedEncryptedNotes {
2574 type Request = platform::GetShieldedEncryptedNotesRequest;
2575 type Response = platform::GetShieldedEncryptedNotesResponse;
2576
2577 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2578 request: I,
2579 response: O,
2580 _network: Network,
2581 platform_version: &PlatformVersion,
2582 provider: &'a dyn ContextProvider,
2583 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2584 where
2585 Self: Sized + 'a,
2586 {
2587 use dapi_grpc::platform::v0::get_shielded_encrypted_notes_request;
2588
2589 let request: Self::Request = request.into();
2590 let response: Self::Response = response.into();
2591 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2592 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2593
2594 let (start_index, count) = match request.version.ok_or(Error::EmptyVersion)? {
2595 get_shielded_encrypted_notes_request::Version::V0(v0) => (v0.start_index, v0.count),
2596 };
2597
2598 let max_elements = platform_version
2599 .drive_abci
2600 .query
2601 .shielded_queries
2602 .max_query_chunks as u32
2603 * (1u32 << drive::drive::shielded::paths::SHIELDED_NOTES_CHUNK_POWER);
2604
2605 let (root_hash, notes, total_count) = Drive::verify_shielded_encrypted_notes(
2606 &proof.grovedb_proof,
2607 start_index,
2608 count,
2609 max_elements,
2610 false,
2611 platform_version,
2612 )
2613 .map_drive_error(proof, mtd)?;
2614
2615 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2616
2617 let result = Some(ShieldedEncryptedNotes {
2623 notes: notes
2624 .into_iter()
2625 .map(|n| ShieldedEncryptedNote {
2626 cmx: n.cmx.to_vec(),
2627 nullifier: n.nullifier.to_vec(),
2628 cv_net: n.cv_net.to_vec(),
2629 encrypted_note: n.encrypted_note.to_vec(),
2630 })
2631 .collect(),
2632 total_count,
2633 });
2634
2635 Ok((result, mtd.clone(), proof.clone()))
2636 }
2637}
2638
2639impl FromProof<platform::GetShieldedNullifiersRequest> for ShieldedNullifierStatuses {
2640 type Request = platform::GetShieldedNullifiersRequest;
2641 type Response = platform::GetShieldedNullifiersResponse;
2642
2643 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
2644 request: I,
2645 response: O,
2646 _network: Network,
2647 platform_version: &PlatformVersion,
2648 provider: &'a dyn ContextProvider,
2649 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
2650 where
2651 Self: Sized + 'a,
2652 {
2653 use dapi_grpc::platform::v0::get_shielded_nullifiers_request;
2654
2655 let request: Self::Request = request.into();
2656 let response: Self::Response = response.into();
2657 let proof = response.proof().or(Err(Error::NoProofInResult))?;
2658 let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?;
2659
2660 let nullifiers = match request.version.ok_or(Error::EmptyVersion)? {
2661 get_shielded_nullifiers_request::Version::V0(v0) => v0.nullifiers,
2662 };
2663
2664 let (root_hash, statuses) = Drive::verify_shielded_nullifiers(
2665 &proof.grovedb_proof,
2666 &nullifiers,
2667 false,
2668 platform_version,
2669 )
2670 .map_drive_error(proof, mtd)?;
2671
2672 verify_tenderdash_proof(proof, mtd, &root_hash, provider)?;
2673
2674 let result = if statuses.is_empty() {
2675 None
2676 } else {
2677 Some(ShieldedNullifierStatuses(
2678 statuses
2679 .into_iter()
2680 .map(|(nullifier, is_spent)| {
2681 let nullifier: [u8; 32] =
2682 nullifier
2683 .try_into()
2684 .map_err(|_| Error::ResultEncodingError {
2685 error: "nullifier from Drive proof is not 32 bytes".to_string(),
2686 })?;
2687 Ok(ShieldedNullifierStatus {
2688 nullifier,
2689 is_spent,
2690 })
2691 })
2692 .collect::<Result<Vec<_>, Error>>()?,
2693 ))
2694 };
2695
2696 Ok((result, mtd.clone(), proof.clone()))
2697 }
2698}
2699
2700pub trait Length {
2702 fn count_some(&self) -> usize;
2704 fn count(&self) -> usize;
2706}
2707
2708impl<T: Length> Length for Option<T> {
2709 fn count_some(&self) -> usize {
2710 match self {
2711 None => 0,
2712 Some(i) => i.count_some(),
2713 }
2714 }
2715 fn count(&self) -> usize {
2716 match self {
2717 None => 0,
2718 Some(i) => i.count(),
2719 }
2720 }
2721}
2722
2723impl<T> Length for Vec<Option<T>> {
2724 fn count_some(&self) -> usize {
2725 self.iter().filter(|v| v.is_some()).count()
2726 }
2727
2728 fn count(&self) -> usize {
2729 self.len()
2730 }
2731}
2732
2733impl<K, T> Length for Vec<(K, Option<T>)> {
2734 fn count_some(&self) -> usize {
2735 self.iter().filter(|(_, v)| v.is_some()).count()
2736 }
2737
2738 fn count(&self) -> usize {
2739 self.len()
2740 }
2741}
2742
2743impl<K, T> Length for BTreeMap<K, Option<T>> {
2744 fn count_some(&self) -> usize {
2745 self.values().filter(|v| v.is_some()).count()
2746 }
2747
2748 fn count(&self) -> usize {
2749 self.len()
2750 }
2751}
2752
2753impl<K, T> Length for IndexMap<K, Option<T>> {
2754 fn count_some(&self) -> usize {
2755 self.values().filter(|v| v.is_some()).count()
2756 }
2757
2758 fn count(&self) -> usize {
2759 self.len()
2760 }
2761}
2762
2763macro_rules! define_length {
2770 ($object:ty,$some:expr,$counter:expr) => {
2771 impl Length for $object {
2772 fn count_some(&self) -> usize {
2773 #[allow(clippy::redundant_closure_call)]
2774 $some(self)
2775 }
2776
2777 fn count(&self) -> usize {
2778 #[allow(clippy::redundant_closure_call)]
2779 $counter(self)
2780 }
2781 }
2782 };
2783 ($object:ty,$some:expr) => {
2784 define_length!($object, $some, $some);
2785 };
2786 ($object:ty) => {
2787 define_length!($object, |_| 1, |_| 1);
2788 };
2789}
2790
2791define_length!(DataContract);
2792define_length!(DataContractHistory, |d: &DataContractHistory| d.len());
2793define_length!(DocumentHistory, |d: &DocumentHistory| d.len());
2794define_length!(Document);
2795define_length!(Identity);
2796define_length!(IdentityBalance);
2797define_length!(IdentityBalanceAndRevision);
2798define_length!(
2799 IdentitiesContractKeys,
2800 |x: &IdentitiesContractKeys| x.values().map(|v| v.count_some()).sum(),
2801 |x: &IdentitiesContractKeys| x.len()
2802);
2803define_length!(ContestedResources, |x: &ContestedResources| x.0.len());
2804define_length!(Contenders, |x: &Contenders| x.contenders.len());
2805define_length!(Voters, |x: &Voters| x.0.len());
2806define_length!(
2807 VotePollsGroupedByTimestamp,
2808 |x: &VotePollsGroupedByTimestamp| x.0.iter().map(|v| v.1.len()).sum(),
2809 |x: &VotePollsGroupedByTimestamp| x.0.len()
2810);
2811
2812trait IntoOption
2814where
2815 Self: Sized,
2816{
2817 fn into_option(self) -> Option<Self>;
2823}
2824
2825impl<L: Length> IntoOption for L {
2826 fn into_option(self) -> Option<Self>
2827 where
2828 Self: Sized,
2829 {
2830 if self.count() == 0 {
2831 None
2832 } else {
2833 Some(self)
2834 }
2835 }
2836}
2837
2838#[cfg(test)]
2839mod tests {
2840 use super::*;
2841
2842 #[test]
2843 fn try_u32_to_u16_succeeds_for_valid_values() {
2844 assert_eq!(try_u32_to_u16(0).unwrap(), 0u16);
2845 assert_eq!(try_u32_to_u16(1).unwrap(), 1u16);
2846 assert_eq!(try_u32_to_u16(42).unwrap(), 42u16);
2847 assert_eq!(try_u32_to_u16(u16::MAX as u32).unwrap(), u16::MAX);
2848 }
2849
2850 #[test]
2851 fn try_u32_to_u16_errors_on_overflow() {
2852 let result = try_u32_to_u16(65536);
2856 assert!(
2857 result.is_err(),
2858 "epoch 65536 must not silently truncate to 0"
2859 );
2860
2861 let result = try_u32_to_u16(u32::MAX);
2862 assert!(result.is_err(), "epoch u32::MAX must not silently truncate");
2863
2864 let result = try_u32_to_u16(100_000);
2865 assert!(result.is_err(), "epoch 100000 must not silently truncate");
2866 }
2867
2868 #[test]
2869 fn u32_to_u16_opt_succeeds_for_valid_values() {
2870 assert_eq!(u32_to_u16_opt(0).unwrap(), None);
2871 assert_eq!(u32_to_u16_opt(1).unwrap(), Some(1u16));
2872 assert_eq!(u32_to_u16_opt(u16::MAX as u32).unwrap(), Some(u16::MAX));
2873 }
2874
2875 #[test]
2876 fn u32_to_u16_opt_errors_on_overflow() {
2877 let result = u32_to_u16_opt(65536);
2878 assert!(
2879 result.is_err(),
2880 "value 65536 must not silently truncate to 0"
2881 );
2882
2883 let result = u32_to_u16_opt(u32::MAX);
2884 assert!(result.is_err(), "value u32::MAX must not silently truncate");
2885 }
2886
2887 #[test]
2892 fn length_vec_option_counts_some_and_total() {
2893 let v: Vec<Option<u32>> = vec![Some(1), None, Some(2), None, Some(3)];
2894 assert_eq!(v.count(), 5);
2895 assert_eq!(v.count_some(), 3);
2896
2897 let empty: Vec<Option<u32>> = vec![];
2898 assert_eq!(empty.count(), 0);
2899 assert_eq!(empty.count_some(), 0);
2900 }
2901
2902 #[test]
2903 fn length_option_of_length_delegates() {
2904 let inner: Vec<Option<u32>> = vec![Some(1), None];
2905 let some_inner: Option<Vec<Option<u32>>> = Some(inner);
2906 assert_eq!(some_inner.count(), 2);
2907 assert_eq!(some_inner.count_some(), 1);
2908
2909 let none_inner: Option<Vec<Option<u32>>> = None;
2910 assert_eq!(none_inner.count(), 0);
2911 assert_eq!(none_inner.count_some(), 0);
2912 }
2913
2914 #[test]
2915 fn length_vec_of_key_option_pair() {
2916 let v: Vec<(u8, Option<u32>)> = vec![(1, Some(10)), (2, None), (3, Some(30)), (4, None)];
2917 assert_eq!(v.count(), 4);
2918 assert_eq!(v.count_some(), 2);
2919 }
2920
2921 #[test]
2922 fn length_btreemap_of_option() {
2923 let mut m: BTreeMap<u8, Option<u32>> = BTreeMap::new();
2924 m.insert(1, Some(10));
2925 m.insert(2, None);
2926 m.insert(3, Some(30));
2927 assert_eq!(m.count(), 3);
2928 assert_eq!(m.count_some(), 2);
2929 }
2930
2931 #[test]
2932 fn length_indexmap_of_option() {
2933 let mut m: IndexMap<u8, Option<u32>> = IndexMap::new();
2934 m.insert(1, Some(10));
2935 m.insert(2, None);
2936 m.insert(3, Some(30));
2937 m.insert(4, None);
2938 assert_eq!(m.count(), 4);
2939 assert_eq!(m.count_some(), 2);
2940 }
2941
2942 #[test]
2943 fn into_option_returns_none_for_empty_and_some_for_nonempty() {
2944 let empty: Vec<Option<u32>> = vec![];
2946 assert!(empty.into_option().is_none());
2947
2948 let all_none: Vec<Option<u32>> = vec![None, None];
2950 let wrapped = all_none.into_option();
2951 assert!(wrapped.is_some());
2952 assert_eq!(wrapped.unwrap().len(), 2);
2953
2954 let mixed: Vec<Option<u32>> = vec![Some(1), None];
2956 assert!(mixed.into_option().is_some());
2957 }
2958
2959 #[test]
2960 fn into_option_for_indexmap() {
2961 let empty: IndexMap<u8, Option<u32>> = IndexMap::new();
2962 assert!(empty.into_option().is_none());
2963
2964 let mut m: IndexMap<u8, Option<u32>> = IndexMap::new();
2965 m.insert(1, None); let wrapped = m.into_option();
2967 assert!(
2968 wrapped.is_some(),
2969 "IntoOption must preserve maps that carry absence markers"
2970 );
2971 }
2972
2973 #[test]
2978 fn parse_key_request_type_missing_outer_request() {
2979 let err = parse_key_request_type(&None)
2980 .err()
2981 .expect("None input must error");
2982 match err {
2983 Error::RequestError { error } => {
2984 assert!(
2985 error.contains("missing key request type"),
2986 "unexpected error message: {error}"
2987 );
2988 }
2989 other => panic!("expected RequestError, got: {other:?}"),
2990 }
2991 }
2992
2993 #[test]
2994 fn parse_key_request_type_missing_inner_request_field() {
2995 let outer = Some(GrpcKeyType { request: None });
2997 let err = parse_key_request_type(&outer)
2998 .err()
2999 .expect("missing request must error");
3000 match err {
3001 Error::RequestError { error } => {
3002 assert!(
3003 error.contains("empty request field"),
3004 "unexpected error message: {error}"
3005 );
3006 }
3007 other => panic!("expected RequestError, got: {other:?}"),
3008 }
3009 }
3010
3011 #[test]
3012 fn parse_key_request_type_all_keys_variant() {
3013 use dapi_grpc::platform::v0::AllKeys;
3014 let outer = Some(GrpcKeyType {
3015 request: Some(key_request_type::Request::AllKeys(AllKeys {})),
3016 });
3017 let parsed = parse_key_request_type(&outer).unwrap();
3018 assert!(matches!(parsed, KeyRequestType::AllKeys));
3019 }
3020
3021 #[test]
3022 fn parse_key_request_type_specific_keys_variant() {
3023 use dapi_grpc::platform::v0::SpecificKeys;
3024 let outer = Some(GrpcKeyType {
3025 request: Some(key_request_type::Request::SpecificKeys(SpecificKeys {
3026 key_ids: vec![1, 2, 3],
3027 })),
3028 });
3029 let parsed = parse_key_request_type(&outer).unwrap();
3030 match parsed {
3031 KeyRequestType::SpecificKeys(ids) => assert_eq!(ids, vec![1, 2, 3]),
3032 _ => panic!("expected SpecificKeys variant"),
3033 }
3034 }
3035
3036 #[test]
3037 fn parse_key_request_type_search_key_rejects_invalid_kind() {
3038 use dapi_grpc::platform::v0::{SearchKey, SecurityLevelMap};
3039 let mut sec_map: std::collections::HashMap<u32, i32> = std::collections::HashMap::new();
3040 sec_map.insert(0, 99);
3042
3043 let mut purpose_map = std::collections::HashMap::new();
3044 purpose_map.insert(
3045 0u32,
3046 SecurityLevelMap {
3047 security_level_map: sec_map,
3048 },
3049 );
3050
3051 let outer = Some(GrpcKeyType {
3052 request: Some(key_request_type::Request::SearchKey(SearchKey {
3053 purpose_map,
3054 })),
3055 });
3056
3057 let err = parse_key_request_type(&outer)
3058 .err()
3059 .expect("bad key kind must error");
3060 match err {
3061 Error::RequestError { error } => assert!(
3062 error.contains("missing requested key type"),
3063 "unexpected error: {error}"
3064 ),
3065 other => panic!("expected RequestError for bad key kind, got: {other:?}"),
3066 }
3067 }
3068
3069 #[test]
3070 fn parse_key_request_type_search_key_accepts_valid_kinds() {
3071 use dapi_grpc::platform::v0::{SearchKey, SecurityLevelMap};
3072 let mut sec_map: std::collections::HashMap<u32, i32> = std::collections::HashMap::new();
3073 sec_map.insert(0, GrpcKeyKind::CurrentKeyOfKindRequest as i32);
3074 sec_map.insert(1, GrpcKeyKind::AllKeysOfKindRequest as i32);
3075
3076 let mut purpose_map = std::collections::HashMap::new();
3077 purpose_map.insert(
3078 0u32,
3079 SecurityLevelMap {
3080 security_level_map: sec_map,
3081 },
3082 );
3083
3084 let outer = Some(GrpcKeyType {
3085 request: Some(key_request_type::Request::SearchKey(SearchKey {
3086 purpose_map,
3087 })),
3088 });
3089
3090 let parsed = parse_key_request_type(&outer).unwrap();
3091 match parsed {
3092 KeyRequestType::SearchKey(purposes) => {
3093 let inner = purposes.get(&0u8).expect("purpose 0 parsed");
3094 assert_eq!(inner.len(), 2);
3095 assert!(matches!(
3096 inner.get(&0u8),
3097 Some(KeyKindRequestType::CurrentKeyOfKindRequest)
3098 ));
3099 assert!(matches!(
3100 inner.get(&1u8),
3101 Some(KeyKindRequestType::AllKeysOfKindRequest)
3102 ));
3103 }
3104 _ => panic!("expected SearchKey variant"),
3105 }
3106 }
3107
3108 struct UnreachableContextProvider;
3120
3121 impl dash_context_provider::ContextProvider for UnreachableContextProvider {
3122 fn get_data_contract(
3123 &self,
3124 _id: &dpp::prelude::Identifier,
3125 _platform_version: &PlatformVersion,
3126 ) -> Result<Option<std::sync::Arc<DataContract>>, dash_context_provider::ContextProviderError>
3127 {
3128 panic!("context provider should not be called on decode-error test")
3129 }
3130
3131 fn get_token_configuration(
3132 &self,
3133 _token_id: &dpp::prelude::Identifier,
3134 ) -> Result<
3135 Option<dpp::data_contract::TokenConfiguration>,
3136 dash_context_provider::ContextProviderError,
3137 > {
3138 panic!("context provider should not be called on decode-error test")
3139 }
3140
3141 fn get_quorum_public_key(
3142 &self,
3143 _quorum_type: u32,
3144 _quorum_hash: [u8; 32],
3145 _core_chain_locked_height: u32,
3146 ) -> Result<[u8; 48], dash_context_provider::ContextProviderError> {
3147 panic!("context provider should not be called on decode-error test")
3148 }
3149
3150 fn get_platform_activation_height(
3151 &self,
3152 ) -> Result<dpp::prelude::CoreBlockHeight, dash_context_provider::ContextProviderError>
3153 {
3154 panic!("context provider should not be called on decode-error test")
3155 }
3156 }
3157
3158 fn unreachable_provider() -> UnreachableContextProvider {
3159 UnreachableContextProvider
3160 }
3161
3162 fn default_platform_version() -> &'static PlatformVersion {
3163 PlatformVersion::latest()
3164 }
3165
3166 struct NoDataContractProvider;
3167
3168 impl dash_context_provider::ContextProvider for NoDataContractProvider {
3169 fn get_data_contract(
3170 &self,
3171 _id: &dpp::prelude::Identifier,
3172 _platform_version: &PlatformVersion,
3173 ) -> Result<Option<std::sync::Arc<DataContract>>, dash_context_provider::ContextProviderError>
3174 {
3175 Ok(None)
3176 }
3177
3178 fn get_token_configuration(
3179 &self,
3180 _token_id: &dpp::prelude::Identifier,
3181 ) -> Result<
3182 Option<dpp::data_contract::TokenConfiguration>,
3183 dash_context_provider::ContextProviderError,
3184 > {
3185 panic!("token configuration should not be requested")
3186 }
3187
3188 fn get_quorum_public_key(
3189 &self,
3190 _quorum_type: u32,
3191 _quorum_hash: [u8; 32],
3192 _core_chain_locked_height: u32,
3193 ) -> Result<[u8; 48], dash_context_provider::ContextProviderError> {
3194 panic!("quorum public key should not be requested")
3195 }
3196
3197 fn get_platform_activation_height(
3198 &self,
3199 ) -> Result<dpp::prelude::CoreBlockHeight, dash_context_provider::ContextProviderError>
3200 {
3201 panic!("platform activation height should not be requested")
3202 }
3203 }
3204
3205 struct StaticDataContractProvider {
3206 data_contract: std::sync::Arc<DataContract>,
3207 }
3208
3209 impl dash_context_provider::ContextProvider for StaticDataContractProvider {
3210 fn get_data_contract(
3211 &self,
3212 id: &dpp::prelude::Identifier,
3213 _platform_version: &PlatformVersion,
3214 ) -> Result<Option<std::sync::Arc<DataContract>>, dash_context_provider::ContextProviderError>
3215 {
3216 if self.data_contract.id() == *id {
3217 Ok(Some(self.data_contract.clone()))
3218 } else {
3219 Ok(None)
3220 }
3221 }
3222
3223 fn get_token_configuration(
3224 &self,
3225 _token_id: &dpp::prelude::Identifier,
3226 ) -> Result<
3227 Option<dpp::data_contract::TokenConfiguration>,
3228 dash_context_provider::ContextProviderError,
3229 > {
3230 panic!("token configuration should not be requested")
3231 }
3232
3233 fn get_quorum_public_key(
3234 &self,
3235 _quorum_type: u32,
3236 _quorum_hash: [u8; 32],
3237 _core_chain_locked_height: u32,
3238 ) -> Result<[u8; 48], dash_context_provider::ContextProviderError> {
3239 panic!("quorum public key should not be requested")
3240 }
3241
3242 fn get_platform_activation_height(
3243 &self,
3244 ) -> Result<dpp::prelude::CoreBlockHeight, dash_context_provider::ContextProviderError>
3245 {
3246 panic!("platform activation height should not be requested")
3247 }
3248 }
3249
3250 fn identity_response_with_proof_and_metadata() -> platform::GetIdentityResponse {
3255 use platform::get_identity_response::{
3256 get_identity_response_v0::Result as V0Result, GetIdentityResponseV0, Version,
3257 };
3258 platform::GetIdentityResponse {
3259 version: Some(Version::V0(GetIdentityResponseV0 {
3260 result: Some(V0Result::Proof(Proof::default())),
3261 metadata: Some(ResponseMetadata::default()),
3262 })),
3263 }
3264 }
3265
3266 fn document_history_response_with_proof_and_metadata() -> platform::GetDocumentHistoryResponse {
3267 use platform::get_document_history_response::{
3268 get_document_history_response_v0::Result as V0Result, GetDocumentHistoryResponseV0,
3269 Version,
3270 };
3271 platform::GetDocumentHistoryResponse {
3272 version: Some(Version::V0(GetDocumentHistoryResponseV0 {
3273 result: Some(V0Result::Proof(Proof::default())),
3274 metadata: Some(ResponseMetadata::default()),
3275 })),
3276 }
3277 }
3278
3279 fn document_history_request(
3280 data_contract_id: Vec<u8>,
3281 document_type_name: &str,
3282 document_id: Vec<u8>,
3283 limit: Option<u32>,
3284 offset: Option<u32>,
3285 ) -> platform::GetDocumentHistoryRequest {
3286 use dapi_grpc::platform::v0::get_document_history_request::GetDocumentHistoryRequestV0;
3287 GetDocumentHistoryRequestV0 {
3288 data_contract_id,
3289 document_type_name: document_type_name.to_string(),
3290 document_id,
3291 limit,
3292 offset,
3293 start_at_ms: 0,
3294 prove: true,
3295 }
3296 .into()
3297 }
3298
3299 fn document_history_error(
3300 request: platform::GetDocumentHistoryRequest,
3301 response: platform::GetDocumentHistoryResponse,
3302 provider: &dyn ContextProvider,
3303 ) -> Error {
3304 <DocumentHistory as FromProof<
3305 platform::GetDocumentHistoryRequest,
3306 >>::maybe_from_proof_with_metadata(
3307 request,
3308 response,
3309 Network::Testnet,
3310 default_platform_version(),
3311 provider,
3312 )
3313 .unwrap_err()
3314 }
3315
3316 #[test]
3317 fn identity_from_proof_no_proof_when_response_empty() {
3318 let request = platform::GetIdentityRequest::default();
3321 let response = platform::GetIdentityResponse::default();
3322
3323 let provider = unreachable_provider();
3324 let err = <Identity as FromProof<platform::GetIdentityRequest>>::maybe_from_proof(
3325 request,
3326 response,
3327 Network::Testnet,
3328 default_platform_version(),
3329 &provider,
3330 )
3331 .unwrap_err();
3332
3333 assert!(
3334 matches!(err, Error::NoProofInResult),
3335 "expected NoProofInResult, got: {err:?}"
3336 );
3337 }
3338
3339 #[test]
3340 fn identity_from_proof_empty_metadata_when_metadata_missing() {
3341 use platform::get_identity_response::{
3342 get_identity_response_v0::Result as V0Result, GetIdentityResponseV0, Version,
3343 };
3344 let response = platform::GetIdentityResponse {
3346 version: Some(Version::V0(GetIdentityResponseV0 {
3347 result: Some(V0Result::Proof(Proof::default())),
3348 metadata: None,
3349 })),
3350 };
3351 let request = platform::GetIdentityRequest::default();
3352 let provider = unreachable_provider();
3353 let err = <Identity as FromProof<platform::GetIdentityRequest>>::maybe_from_proof(
3354 request,
3355 response,
3356 Network::Testnet,
3357 default_platform_version(),
3358 &provider,
3359 )
3360 .unwrap_err();
3361 assert!(matches!(err, Error::EmptyResponseMetadata), "got: {err:?}");
3362 }
3363
3364 #[test]
3365 fn identity_from_proof_empty_version_when_request_has_no_version() {
3366 let response = identity_response_with_proof_and_metadata();
3368 let request = platform::GetIdentityRequest { version: None };
3369 let provider = unreachable_provider();
3370 let err = <Identity as FromProof<platform::GetIdentityRequest>>::maybe_from_proof(
3371 request,
3372 response,
3373 Network::Testnet,
3374 default_platform_version(),
3375 &provider,
3376 )
3377 .unwrap_err();
3378 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
3379 }
3380
3381 #[test]
3382 fn identity_from_proof_protocol_error_on_bad_id_length() {
3383 use dapi_grpc::platform::v0::get_identity_request::GetIdentityRequestV0;
3384 let request: platform::GetIdentityRequest = GetIdentityRequestV0 {
3386 id: vec![0u8; 8],
3387 prove: true,
3388 }
3389 .into();
3390 let response = identity_response_with_proof_and_metadata();
3391 let provider = unreachable_provider();
3392 let err = <Identity as FromProof<platform::GetIdentityRequest>>::maybe_from_proof(
3393 request,
3394 response,
3395 Network::Testnet,
3396 default_platform_version(),
3397 &provider,
3398 )
3399 .unwrap_err();
3400 assert!(
3401 matches!(err, Error::ProtocolError { .. }),
3402 "expected ProtocolError on bad id length, got: {err:?}"
3403 );
3404 }
3405
3406 #[derive(Debug)]
3410 struct MissingFromProof;
3411
3412 impl FromProof<()> for MissingFromProof {
3413 type Request = ();
3414 type Response = ();
3415
3416 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
3417 _request: I,
3418 _response: O,
3419 _network: Network,
3420 _platform_version: &PlatformVersion,
3421 _provider: &'a dyn ContextProvider,
3422 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
3423 where
3424 Self: Sized + 'a,
3425 {
3426 Ok((None, ResponseMetadata::default(), Proof::default()))
3427 }
3428 }
3429
3430 #[test]
3431 fn from_proof_maps_none_to_not_found() {
3432 let provider = unreachable_provider();
3436 let err = <MissingFromProof as FromProof<()>>::from_proof(
3437 (),
3438 (),
3439 Network::Testnet,
3440 default_platform_version(),
3441 &provider,
3442 )
3443 .unwrap_err();
3444 assert!(
3445 matches!(err, Error::NotFound),
3446 "expected NotFound when maybe_from_proof returns None, got: {err:?}"
3447 );
3448 }
3449
3450 #[test]
3451 fn identity_by_public_key_hash_invalid_length_yields_drive_error() {
3452 use dapi_grpc::platform::v0::get_identity_by_public_key_hash_request::GetIdentityByPublicKeyHashRequestV0;
3453
3454 let request: platform::GetIdentityByPublicKeyHashRequest =
3456 GetIdentityByPublicKeyHashRequestV0 {
3457 public_key_hash: vec![0u8; 10],
3458 prove: true,
3459 }
3460 .into();
3461
3462 use platform::get_identity_by_public_key_hash_response::{
3464 get_identity_by_public_key_hash_response_v0::Result as V0Result,
3465 GetIdentityByPublicKeyHashResponseV0, Version,
3466 };
3467 let response = platform::GetIdentityByPublicKeyHashResponse {
3468 version: Some(Version::V0(GetIdentityByPublicKeyHashResponseV0 {
3469 result: Some(V0Result::Proof(Proof::default())),
3470 metadata: Some(ResponseMetadata::default()),
3471 })),
3472 };
3473
3474 let provider = unreachable_provider();
3475 let err =
3476 <Identity as FromProof<platform::GetIdentityByPublicKeyHashRequest>>::maybe_from_proof(
3477 request,
3478 response,
3479 Network::Testnet,
3480 default_platform_version(),
3481 &provider,
3482 )
3483 .unwrap_err();
3484
3485 match err {
3486 Error::DriveError { error } => {
3487 assert!(
3488 error.contains("Invalid public key hash length"),
3489 "unexpected error body: {error}"
3490 );
3491 }
3492 other => panic!("expected DriveError, got: {other:?}"),
3493 }
3494 }
3495
3496 #[test]
3497 fn identity_by_non_unique_public_key_hash_rejects_bad_key_hash_length() {
3498 use dapi_grpc::platform::v0::get_identity_by_non_unique_public_key_hash_request::GetIdentityByNonUniquePublicKeyHashRequestV0;
3499 use platform::get_identity_by_non_unique_public_key_hash_response::{
3500 get_identity_by_non_unique_public_key_hash_response_v0::Result as V0Result,
3501 GetIdentityByNonUniquePublicKeyHashResponseV0, Version,
3502 };
3503
3504 let response = platform::GetIdentityByNonUniquePublicKeyHashResponse {
3507 version: Some(Version::V0(
3508 GetIdentityByNonUniquePublicKeyHashResponseV0 {
3509 result: Some(V0Result::Proof(
3510 dapi_grpc::platform::v0::get_identity_by_non_unique_public_key_hash_response::get_identity_by_non_unique_public_key_hash_response_v0::IdentityProvedResponse {
3511 identity_proof_bytes: None,
3512 grovedb_identity_public_key_hash_proof: Some(Proof::default()),
3513 },
3514 )),
3515 metadata: Some(ResponseMetadata::default()),
3516 },
3517 )),
3518 };
3519
3520 let request: platform::GetIdentityByNonUniquePublicKeyHashRequest =
3521 GetIdentityByNonUniquePublicKeyHashRequestV0 {
3522 public_key_hash: vec![0u8; 3], start_after: None,
3524 prove: true,
3525 }
3526 .into();
3527
3528 let provider = unreachable_provider();
3529 let err = <Identity as FromProof<platform::GetIdentityByNonUniquePublicKeyHashRequest>>::maybe_from_proof(
3530 request,
3531 response,
3532 Network::Testnet,
3533 default_platform_version(),
3534 &provider,
3535 )
3536 .unwrap_err();
3537
3538 match err {
3539 Error::RequestError { error } => {
3540 assert!(
3541 error.contains("Invalid public key hash length"),
3542 "got: {error}"
3543 );
3544 }
3545 other => panic!("expected RequestError, got: {other:?}"),
3546 }
3547 }
3548
3549 #[test]
3550 fn identity_by_non_unique_public_key_hash_rejects_bad_start_after_length() {
3551 use dapi_grpc::platform::v0::get_identity_by_non_unique_public_key_hash_request::GetIdentityByNonUniquePublicKeyHashRequestV0;
3552 use platform::get_identity_by_non_unique_public_key_hash_response::{
3553 get_identity_by_non_unique_public_key_hash_response_v0::Result as V0Result,
3554 GetIdentityByNonUniquePublicKeyHashResponseV0, Version,
3555 };
3556
3557 let response = platform::GetIdentityByNonUniquePublicKeyHashResponse {
3558 version: Some(Version::V0(
3559 GetIdentityByNonUniquePublicKeyHashResponseV0 {
3560 result: Some(V0Result::Proof(
3561 dapi_grpc::platform::v0::get_identity_by_non_unique_public_key_hash_response::get_identity_by_non_unique_public_key_hash_response_v0::IdentityProvedResponse {
3562 identity_proof_bytes: None,
3563 grovedb_identity_public_key_hash_proof: Some(Proof::default()),
3564 },
3565 )),
3566 metadata: Some(ResponseMetadata::default()),
3567 },
3568 )),
3569 };
3570
3571 let request: platform::GetIdentityByNonUniquePublicKeyHashRequest =
3572 GetIdentityByNonUniquePublicKeyHashRequestV0 {
3573 public_key_hash: vec![0u8; 20], start_after: Some(vec![0u8; 10]), prove: true,
3576 }
3577 .into();
3578
3579 let provider = unreachable_provider();
3580 let err = <Identity as FromProof<platform::GetIdentityByNonUniquePublicKeyHashRequest>>::maybe_from_proof(
3581 request,
3582 response,
3583 Network::Testnet,
3584 default_platform_version(),
3585 &provider,
3586 )
3587 .unwrap_err();
3588
3589 match err {
3590 Error::RequestError { error } => {
3591 assert!(error.contains("Invalid start_after length"), "got: {error}");
3592 }
3593 other => panic!("expected RequestError for start_after, got: {other:?}"),
3594 }
3595 }
3596
3597 #[test]
3598 fn identity_by_non_unique_response_with_no_result_yields_no_proof() {
3599 use dapi_grpc::platform::v0::get_identity_by_non_unique_public_key_hash_request::GetIdentityByNonUniquePublicKeyHashRequestV0;
3600 use platform::get_identity_by_non_unique_public_key_hash_response::{
3601 GetIdentityByNonUniquePublicKeyHashResponseV0, Version,
3602 };
3603
3604 let response = platform::GetIdentityByNonUniquePublicKeyHashResponse {
3606 version: Some(Version::V0(GetIdentityByNonUniquePublicKeyHashResponseV0 {
3607 result: None,
3608 metadata: None,
3609 })),
3610 };
3611 let request: platform::GetIdentityByNonUniquePublicKeyHashRequest =
3612 GetIdentityByNonUniquePublicKeyHashRequestV0 {
3613 public_key_hash: vec![0u8; 20],
3614 start_after: None,
3615 prove: true,
3616 }
3617 .into();
3618 let provider = unreachable_provider();
3619 let err = <Identity as FromProof<platform::GetIdentityByNonUniquePublicKeyHashRequest>>::maybe_from_proof(
3620 request,
3621 response,
3622 Network::Testnet,
3623 default_platform_version(),
3624 &provider,
3625 )
3626 .unwrap_err();
3627 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
3628 }
3629
3630 #[test]
3631 fn identity_by_non_unique_response_with_no_version_yields_empty_metadata() {
3632 use dapi_grpc::platform::v0::get_identity_by_non_unique_public_key_hash_request::GetIdentityByNonUniquePublicKeyHashRequestV0;
3634 let response = platform::GetIdentityByNonUniquePublicKeyHashResponse { version: None };
3635 let request: platform::GetIdentityByNonUniquePublicKeyHashRequest =
3636 GetIdentityByNonUniquePublicKeyHashRequestV0 {
3637 public_key_hash: vec![0u8; 20],
3638 start_after: None,
3639 prove: true,
3640 }
3641 .into();
3642 let provider = unreachable_provider();
3643 let err = <Identity as FromProof<platform::GetIdentityByNonUniquePublicKeyHashRequest>>::maybe_from_proof(
3644 request,
3645 response,
3646 Network::Testnet,
3647 default_platform_version(),
3648 &provider,
3649 )
3650 .unwrap_err();
3651 assert!(matches!(err, Error::EmptyResponseMetadata), "got: {err:?}");
3652 }
3653
3654 #[test]
3655 fn identities_balances_rejects_non_32_byte_id() {
3656 use dapi_grpc::platform::v0::get_identities_balances_request::GetIdentitiesBalancesRequestV0;
3657 use platform::get_identities_balances_response::{
3658 get_identities_balances_response_v0::Result as V0Result,
3659 GetIdentitiesBalancesResponseV0, Version,
3660 };
3661
3662 let response = platform::GetIdentitiesBalancesResponse {
3663 version: Some(Version::V0(GetIdentitiesBalancesResponseV0 {
3664 result: Some(V0Result::Proof(Proof::default())),
3665 metadata: Some(ResponseMetadata::default()),
3666 })),
3667 };
3668
3669 let request: platform::GetIdentitiesBalancesRequest = GetIdentitiesBalancesRequestV0 {
3670 ids: vec![vec![0u8; 10]], prove: true,
3672 }
3673 .into();
3674
3675 let provider = unreachable_provider();
3676 let err =
3677 <IdentityBalances as FromProof<platform::GetIdentitiesBalancesRequest>>::maybe_from_proof(
3678 request,
3679 response,
3680 Network::Testnet,
3681 default_platform_version(),
3682 &provider,
3683 )
3684 .unwrap_err();
3685 match err {
3686 Error::RequestError { error } => {
3687 assert!(error.contains("all 32 bytes"), "got: {error}");
3688 }
3689 other => panic!("expected RequestError, got: {other:?}"),
3690 }
3691 }
3692
3693 #[test]
3694 fn data_contracts_rejects_wrong_size_id() {
3695 use dapi_grpc::platform::v0::get_data_contracts_request::GetDataContractsRequestV0;
3696 use platform::get_data_contracts_response::{
3697 get_data_contracts_response_v0::Result as V0Result, GetDataContractsResponseV0, Version,
3698 };
3699
3700 let response = platform::GetDataContractsResponse {
3701 version: Some(Version::V0(GetDataContractsResponseV0 {
3702 result: Some(V0Result::Proof(Proof::default())),
3703 metadata: Some(ResponseMetadata::default()),
3704 })),
3705 };
3706 let request: platform::GetDataContractsRequest = GetDataContractsRequestV0 {
3707 ids: vec![vec![0u8; 20]], prove: true,
3709 }
3710 .into();
3711 let provider = unreachable_provider();
3712 let err =
3713 <DataContracts as FromProof<platform::GetDataContractsRequest>>::maybe_from_proof(
3714 request,
3715 response,
3716 Network::Testnet,
3717 default_platform_version(),
3718 &provider,
3719 )
3720 .unwrap_err();
3721 match err {
3722 Error::RequestError { error } => {
3723 assert!(error.contains("wrong id size"), "got: {error}");
3724 }
3725 other => panic!("expected RequestError, got: {other:?}"),
3726 }
3727 }
3728
3729 #[test]
3730 fn upgrade_vote_status_rejects_bad_start_pro_tx_hash_length() {
3731 use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_request::GetProtocolVersionUpgradeVoteStatusRequestV0;
3732 use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_response::{
3733 get_protocol_version_upgrade_vote_status_response_v0::Result as V0Result,
3734 GetProtocolVersionUpgradeVoteStatusResponseV0, Version,
3735 };
3736
3737 let response = GetProtocolVersionUpgradeVoteStatusResponse {
3738 version: Some(Version::V0(GetProtocolVersionUpgradeVoteStatusResponseV0 {
3739 result: Some(V0Result::Proof(Proof::default())),
3740 metadata: Some(ResponseMetadata::default()),
3741 })),
3742 };
3743 let request: GetProtocolVersionUpgradeVoteStatusRequest =
3745 GetProtocolVersionUpgradeVoteStatusRequestV0 {
3746 start_pro_tx_hash: vec![0u8; 5],
3747 count: 10,
3748 prove: true,
3749 }
3750 .into();
3751 let provider = unreachable_provider();
3752 let err = <MasternodeProtocolVotes as FromProof<
3753 GetProtocolVersionUpgradeVoteStatusRequest,
3754 >>::maybe_from_proof(
3755 request,
3756 response,
3757 Network::Testnet,
3758 default_platform_version(),
3759 &provider,
3760 )
3761 .unwrap_err();
3762 match err {
3763 Error::RequestError { .. } => {}
3764 other => panic!("expected RequestError for bad pro_tx_hash length, got: {other:?}"),
3765 }
3766 }
3767
3768 #[test]
3769 fn upgrade_vote_status_empty_version_on_request_none() {
3770 use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_response::{
3771 get_protocol_version_upgrade_vote_status_response_v0::Result as V0Result,
3772 GetProtocolVersionUpgradeVoteStatusResponseV0, Version,
3773 };
3774 let response = GetProtocolVersionUpgradeVoteStatusResponse {
3775 version: Some(Version::V0(GetProtocolVersionUpgradeVoteStatusResponseV0 {
3776 result: Some(V0Result::Proof(Proof::default())),
3777 metadata: Some(ResponseMetadata::default()),
3778 })),
3779 };
3780 let request = GetProtocolVersionUpgradeVoteStatusRequest { version: None };
3781 let provider = unreachable_provider();
3782 let err = <MasternodeProtocolVotes as FromProof<
3783 GetProtocolVersionUpgradeVoteStatusRequest,
3784 >>::maybe_from_proof(
3785 request,
3786 response,
3787 Network::Testnet,
3788 default_platform_version(),
3789 &provider,
3790 )
3791 .unwrap_err();
3792 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
3793 }
3794
3795 #[test]
3796 fn path_elements_no_proof_without_response() {
3797 let request = GetPathElementsRequest::default();
3798 let response = GetPathElementsResponse::default();
3799 let provider = unreachable_provider();
3800 let err = <Elements as FromProof<GetPathElementsRequest>>::maybe_from_proof(
3801 request,
3802 response,
3803 Network::Testnet,
3804 default_platform_version(),
3805 &provider,
3806 )
3807 .unwrap_err();
3808 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
3809 }
3810
3811 #[test]
3812 fn prefunded_balance_rejects_bad_id_length() {
3813 use dapi_grpc::platform::v0::get_prefunded_specialized_balance_request::GetPrefundedSpecializedBalanceRequestV0;
3814 use platform::get_prefunded_specialized_balance_response::{
3815 get_prefunded_specialized_balance_response_v0::Result as V0Result,
3816 GetPrefundedSpecializedBalanceResponseV0, Version,
3817 };
3818 let response = platform::GetPrefundedSpecializedBalanceResponse {
3819 version: Some(Version::V0(GetPrefundedSpecializedBalanceResponseV0 {
3820 result: Some(V0Result::Proof(Proof::default())),
3821 metadata: Some(ResponseMetadata::default()),
3822 })),
3823 };
3824 let request: platform::GetPrefundedSpecializedBalanceRequest =
3825 GetPrefundedSpecializedBalanceRequestV0 {
3826 id: vec![0u8; 3], prove: true,
3828 }
3829 .into();
3830 let provider = unreachable_provider();
3831 let err = <PrefundedSpecializedBalance as FromProof<
3832 platform::GetPrefundedSpecializedBalanceRequest,
3833 >>::maybe_from_proof(
3834 request,
3835 response,
3836 Network::Testnet,
3837 default_platform_version(),
3838 &provider,
3839 )
3840 .unwrap_err();
3841 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
3842 }
3843
3844 #[test]
3845 fn epochs_info_rejects_overflowing_start_epoch() {
3846 use dapi_grpc::platform::v0::get_epochs_info_request::GetEpochsInfoRequestV0;
3847 use platform::get_epochs_info_response::{
3848 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
3849 };
3850 let response = platform::GetEpochsInfoResponse {
3851 version: Some(Version::V0(GetEpochsInfoResponseV0 {
3852 result: Some(V0Result::Proof(Proof::default())),
3853 metadata: Some(ResponseMetadata {
3854 epoch: 10,
3855 ..Default::default()
3856 }),
3857 })),
3858 };
3859 let request = platform::GetEpochsInfoRequest {
3861 version: Some(platform::get_epochs_info_request::Version::V0(
3862 GetEpochsInfoRequestV0 {
3863 start_epoch: Some(100_000),
3864 count: 1,
3865 ascending: true,
3866 prove: true,
3867 },
3868 )),
3869 };
3870 let provider = unreachable_provider();
3871 let err =
3872 <ExtendedEpochInfos as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
3873 request,
3874 response,
3875 Network::Testnet,
3876 default_platform_version(),
3877 &provider,
3878 )
3879 .unwrap_err();
3880 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
3881 }
3882
3883 #[test]
3884 fn broadcast_state_transition_rejects_garbage_payload() {
3885 let request = platform::BroadcastStateTransitionRequest {
3888 state_transition: vec![0xFFu8; 16], };
3890 use platform::wait_for_state_transition_result_response::{
3893 wait_for_state_transition_result_response_v0::Result as V0Result, Version,
3894 WaitForStateTransitionResultResponseV0,
3895 };
3896 let response = platform::WaitForStateTransitionResultResponse {
3897 version: Some(Version::V0(WaitForStateTransitionResultResponseV0 {
3898 result: Some(V0Result::Proof(Proof::default())),
3899 metadata: Some(ResponseMetadata::default()),
3900 })),
3901 };
3902 let provider = unreachable_provider();
3903 let err = <StateTransitionProofResult as FromProof<
3904 platform::BroadcastStateTransitionRequest,
3905 >>::maybe_from_proof(
3906 request,
3907 response,
3908 Network::Testnet,
3909 default_platform_version(),
3910 &provider,
3911 )
3912 .unwrap_err();
3913 assert!(
3914 matches!(err, Error::ProtocolError { .. }),
3915 "expected ProtocolError from StateTransition decode, got: {err:?}"
3916 );
3917 }
3918
3919 #[test]
3924 fn u32_to_u16_opt_zero_maps_to_none() {
3925 let parsed = u32_to_u16_opt(0).unwrap();
3928 assert!(parsed.is_none(), "value 0 must decode to None");
3929 }
3930
3931 #[test]
3932 fn u32_to_u16_opt_at_boundary() {
3933 let parsed = u32_to_u16_opt(u16::MAX as u32).unwrap();
3934 assert_eq!(parsed, Some(u16::MAX));
3935 }
3936
3937 #[test]
3938 fn u32_to_u16_opt_error_just_above_boundary() {
3939 let err = u32_to_u16_opt((u16::MAX as u32) + 1).unwrap_err();
3941 match err {
3942 Error::RequestError { error } => {
3943 assert!(error.contains("out of range"), "got: {error}");
3944 }
3945 other => panic!("expected RequestError, got: {other:?}"),
3946 }
3947 }
3948
3949 #[test]
3950 fn try_u32_to_u16_at_boundary_plus_one() {
3951 assert!(try_u32_to_u16(u16::MAX as u32).is_ok());
3953 assert!(try_u32_to_u16((u16::MAX as u32) + 1).is_err());
3954 }
3955
3956 #[test]
3961 fn length_option_of_length_none_counts_zero() {
3962 let none_opt: Option<Vec<Option<u32>>> = None;
3963 assert_eq!(none_opt.count(), 0);
3964 assert_eq!(none_opt.count_some(), 0);
3965 }
3966
3967 #[test]
3968 fn length_vec_of_key_option_pair_only_none_values() {
3969 let v: Vec<(u8, Option<u32>)> = vec![(1, None), (2, None)];
3970 assert_eq!(v.count(), 2);
3971 assert_eq!(
3972 v.count_some(),
3973 0,
3974 "count_some must only count entries whose value is Some"
3975 );
3976 }
3977
3978 #[test]
3979 fn length_btreemap_only_none_values() {
3980 let mut m: BTreeMap<u8, Option<u32>> = BTreeMap::new();
3981 m.insert(1, None);
3982 m.insert(2, None);
3983 assert_eq!(m.count(), 2);
3984 assert_eq!(m.count_some(), 0);
3985 }
3986
3987 #[test]
3988 fn into_option_for_vec_of_key_option_pair_empty_and_nonempty() {
3989 let empty: Vec<(u8, Option<u32>)> = vec![];
3990 assert!(
3991 empty.into_option().is_none(),
3992 "empty vec must decode to None"
3993 );
3994
3995 let single: Vec<(u8, Option<u32>)> = vec![(1, None)];
3996 assert!(
3997 single.into_option().is_some(),
3998 "non-empty vec with only None values must still be Some"
3999 );
4000 }
4001
4002 #[test]
4003 fn into_option_for_btreemap_empty_and_nonempty() {
4004 let empty: BTreeMap<u8, Option<u32>> = BTreeMap::new();
4005 assert!(empty.into_option().is_none());
4006
4007 let mut m: BTreeMap<u8, Option<u32>> = BTreeMap::new();
4008 m.insert(1, None);
4009 assert!(m.into_option().is_some());
4010 }
4011
4012 #[test]
4017 fn parse_key_request_type_specific_keys_empty_ids() {
4018 use dapi_grpc::platform::v0::SpecificKeys;
4020 let outer = Some(GrpcKeyType {
4021 request: Some(key_request_type::Request::SpecificKeys(SpecificKeys {
4022 key_ids: vec![],
4023 })),
4024 });
4025 let parsed = parse_key_request_type(&outer).unwrap();
4026 match parsed {
4027 KeyRequestType::SpecificKeys(ids) => {
4028 assert!(ids.is_empty(), "empty ids must round-trip as empty");
4029 }
4030 _ => panic!("expected SpecificKeys variant"),
4031 }
4032 }
4033
4034 #[test]
4035 fn parse_key_request_type_search_key_empty_purpose_map() {
4036 use dapi_grpc::platform::v0::SearchKey;
4038 let outer = Some(GrpcKeyType {
4039 request: Some(key_request_type::Request::SearchKey(SearchKey {
4040 purpose_map: std::collections::HashMap::new(),
4041 })),
4042 });
4043 let parsed = parse_key_request_type(&outer).unwrap();
4044 match parsed {
4045 KeyRequestType::SearchKey(m) => {
4046 assert!(m.is_empty(), "empty map must round-trip as empty");
4047 }
4048 _ => panic!("expected SearchKey variant"),
4049 }
4050 }
4051
4052 #[test]
4053 fn parse_key_request_type_search_key_negative_kind_rejected() {
4054 use dapi_grpc::platform::v0::{SearchKey, SecurityLevelMap};
4056 let mut sec_map: std::collections::HashMap<u32, i32> = std::collections::HashMap::new();
4057 sec_map.insert(0, -1);
4058 let mut purpose_map = std::collections::HashMap::new();
4059 purpose_map.insert(
4060 0u32,
4061 SecurityLevelMap {
4062 security_level_map: sec_map,
4063 },
4064 );
4065 let outer = Some(GrpcKeyType {
4066 request: Some(key_request_type::Request::SearchKey(SearchKey {
4067 purpose_map,
4068 })),
4069 });
4070 let err = parse_key_request_type(&outer)
4073 .err()
4074 .expect("negative kind must error");
4075 match err {
4076 Error::RequestError { error } => {
4077 assert!(error.contains("missing requested key type"), "got: {error}");
4078 }
4079 other => panic!("expected RequestError, got: {other:?}"),
4080 }
4081 }
4082
4083 #[derive(Debug, PartialEq)]
4090 struct PresentFromProof(u32);
4091
4092 impl FromProof<()> for PresentFromProof {
4093 type Request = ();
4094 type Response = ();
4095
4096 fn maybe_from_proof_with_metadata<'a, I: Into<Self::Request>, O: Into<Self::Response>>(
4097 _request: I,
4098 _response: O,
4099 _network: Network,
4100 _platform_version: &PlatformVersion,
4101 _provider: &'a dyn ContextProvider,
4102 ) -> Result<(Option<Self>, ResponseMetadata, Proof), Error>
4103 where
4104 Self: Sized + 'a,
4105 {
4106 Ok((
4107 Some(PresentFromProof(7)),
4108 ResponseMetadata {
4109 height: 123,
4110 ..Default::default()
4111 },
4112 Proof::default(),
4113 ))
4114 }
4115 }
4116
4117 #[test]
4118 fn from_proof_with_metadata_returns_value_and_metadata() {
4119 let provider = unreachable_provider();
4121 let (value, mtd) = <PresentFromProof as FromProof<()>>::from_proof_with_metadata(
4122 (),
4123 (),
4124 Network::Testnet,
4125 default_platform_version(),
4126 &provider,
4127 )
4128 .unwrap();
4129 assert_eq!(value, PresentFromProof(7));
4130 assert_eq!(mtd.height, 123);
4131 }
4132
4133 #[test]
4134 fn from_proof_with_metadata_and_proof_returns_all_three() {
4135 let provider = unreachable_provider();
4136 let (value, mtd, _proof) =
4137 <PresentFromProof as FromProof<()>>::from_proof_with_metadata_and_proof(
4138 (),
4139 (),
4140 Network::Testnet,
4141 default_platform_version(),
4142 &provider,
4143 )
4144 .unwrap();
4145 assert_eq!(value, PresentFromProof(7));
4146 assert_eq!(mtd.height, 123);
4147 }
4148
4149 #[test]
4150 fn from_proof_on_missing_returns_not_found_via_wrapper() {
4151 let provider = unreachable_provider();
4153 let err = <MissingFromProof as FromProof<()>>::from_proof_with_metadata(
4154 (),
4155 (),
4156 Network::Testnet,
4157 default_platform_version(),
4158 &provider,
4159 )
4160 .unwrap_err();
4161 assert!(matches!(err, Error::NotFound), "got: {err:?}");
4162 }
4163
4164 #[test]
4165 fn from_proof_with_metadata_and_proof_missing_returns_not_found() {
4166 let provider = unreachable_provider();
4167 let err = <MissingFromProof as FromProof<()>>::from_proof_with_metadata_and_proof(
4168 (),
4169 (),
4170 Network::Testnet,
4171 default_platform_version(),
4172 &provider,
4173 )
4174 .unwrap_err();
4175 assert!(matches!(err, Error::NotFound), "got: {err:?}");
4176 }
4177
4178 #[test]
4179 fn maybe_from_proof_delegates_to_with_metadata_and_forwards_none() {
4180 let provider = unreachable_provider();
4183 let result = <MissingFromProof as FromProof<()>>::maybe_from_proof(
4184 (),
4185 (),
4186 Network::Testnet,
4187 default_platform_version(),
4188 &provider,
4189 )
4190 .unwrap();
4191 assert!(result.is_none(), "MissingFromProof must bubble None");
4192 }
4193
4194 fn default_metadata_with_epoch(epoch: u32) -> ResponseMetadata {
4199 ResponseMetadata {
4200 epoch,
4201 ..Default::default()
4202 }
4203 }
4204
4205 #[test]
4206 fn identity_keys_rejects_bad_identity_id_length() {
4207 use dapi_grpc::platform::v0::get_identity_keys_request::GetIdentityKeysRequestV0;
4208 use platform::get_identity_keys_response::{
4209 get_identity_keys_response_v0::Result as V0Result, GetIdentityKeysResponseV0, Version,
4210 };
4211
4212 let response = platform::GetIdentityKeysResponse {
4213 version: Some(Version::V0(GetIdentityKeysResponseV0 {
4214 result: Some(V0Result::Proof(Proof::default())),
4215 metadata: Some(ResponseMetadata::default()),
4216 })),
4217 };
4218 let request: platform::GetIdentityKeysRequest = GetIdentityKeysRequestV0 {
4219 identity_id: vec![0u8; 5], request_type: None,
4221 limit: None,
4222 offset: None,
4223 prove: true,
4224 }
4225 .into();
4226 let provider = unreachable_provider();
4227 let err =
4228 <IdentityPublicKeys as FromProof<platform::GetIdentityKeysRequest>>::maybe_from_proof(
4229 request,
4230 response,
4231 Network::Testnet,
4232 default_platform_version(),
4233 &provider,
4234 )
4235 .unwrap_err();
4236 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4237 }
4238
4239 #[test]
4240 fn identity_keys_rejects_overflowing_limit() {
4241 use dapi_grpc::platform::v0::get_identity_keys_request::GetIdentityKeysRequestV0;
4242 use platform::get_identity_keys_response::{
4243 get_identity_keys_response_v0::Result as V0Result, GetIdentityKeysResponseV0, Version,
4244 };
4245
4246 let response = platform::GetIdentityKeysResponse {
4247 version: Some(Version::V0(GetIdentityKeysResponseV0 {
4248 result: Some(V0Result::Proof(Proof::default())),
4249 metadata: Some(ResponseMetadata::default()),
4250 })),
4251 };
4252 let request: platform::GetIdentityKeysRequest = GetIdentityKeysRequestV0 {
4253 identity_id: vec![0u8; 32], request_type: None,
4255 limit: Some(100_000),
4256 offset: None,
4257 prove: true,
4258 }
4259 .into();
4260 let provider = unreachable_provider();
4261 let err =
4262 <IdentityPublicKeys as FromProof<platform::GetIdentityKeysRequest>>::maybe_from_proof(
4263 request,
4264 response,
4265 Network::Testnet,
4266 default_platform_version(),
4267 &provider,
4268 )
4269 .unwrap_err();
4270 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
4271 }
4272
4273 #[test]
4274 fn identity_keys_rejects_overflowing_offset() {
4275 use dapi_grpc::platform::v0::get_identity_keys_request::GetIdentityKeysRequestV0;
4276 use platform::get_identity_keys_response::{
4277 get_identity_keys_response_v0::Result as V0Result, GetIdentityKeysResponseV0, Version,
4278 };
4279
4280 let response = platform::GetIdentityKeysResponse {
4281 version: Some(Version::V0(GetIdentityKeysResponseV0 {
4282 result: Some(V0Result::Proof(Proof::default())),
4283 metadata: Some(ResponseMetadata::default()),
4284 })),
4285 };
4286 let request: platform::GetIdentityKeysRequest = GetIdentityKeysRequestV0 {
4287 identity_id: vec![0u8; 32],
4288 request_type: None,
4289 limit: None,
4290 offset: Some(100_000),
4291 prove: true,
4292 }
4293 .into();
4294 let provider = unreachable_provider();
4295 let err =
4296 <IdentityPublicKeys as FromProof<platform::GetIdentityKeysRequest>>::maybe_from_proof(
4297 request,
4298 response,
4299 Network::Testnet,
4300 default_platform_version(),
4301 &provider,
4302 )
4303 .unwrap_err();
4304 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
4305 }
4306
4307 #[test]
4308 fn identity_keys_rejects_missing_key_request_type() {
4309 use dapi_grpc::platform::v0::get_identity_keys_request::GetIdentityKeysRequestV0;
4312 use platform::get_identity_keys_response::{
4313 get_identity_keys_response_v0::Result as V0Result, GetIdentityKeysResponseV0, Version,
4314 };
4315
4316 let response = platform::GetIdentityKeysResponse {
4317 version: Some(Version::V0(GetIdentityKeysResponseV0 {
4318 result: Some(V0Result::Proof(Proof::default())),
4319 metadata: Some(ResponseMetadata::default()),
4320 })),
4321 };
4322 let request: platform::GetIdentityKeysRequest = GetIdentityKeysRequestV0 {
4323 identity_id: vec![0u8; 32],
4324 request_type: None,
4325 limit: None,
4326 offset: None,
4327 prove: true,
4328 }
4329 .into();
4330 let provider = unreachable_provider();
4331 let err =
4332 <IdentityPublicKeys as FromProof<platform::GetIdentityKeysRequest>>::maybe_from_proof(
4333 request,
4334 response,
4335 Network::Testnet,
4336 default_platform_version(),
4337 &provider,
4338 )
4339 .unwrap_err();
4340 match err {
4341 Error::RequestError { error } => {
4342 assert!(error.contains("missing key request type"), "got: {error}");
4343 }
4344 other => panic!("expected RequestError, got: {other:?}"),
4345 }
4346 }
4347
4348 #[test]
4349 fn identity_keys_no_proof_when_response_empty() {
4350 let request = platform::GetIdentityKeysRequest::default();
4351 let response = platform::GetIdentityKeysResponse::default();
4352 let provider = unreachable_provider();
4353 let err =
4354 <IdentityPublicKeys as FromProof<platform::GetIdentityKeysRequest>>::maybe_from_proof(
4355 request,
4356 response,
4357 Network::Testnet,
4358 default_platform_version(),
4359 &provider,
4360 )
4361 .unwrap_err();
4362 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
4363 }
4364
4365 #[test]
4366 fn identity_nonce_rejects_bad_identity_id_length() {
4367 use dapi_grpc::platform::v0::get_identity_nonce_request::GetIdentityNonceRequestV0;
4368 use platform::get_identity_nonce_response::{
4369 get_identity_nonce_response_v0::Result as V0Result, GetIdentityNonceResponseV0, Version,
4370 };
4371
4372 let response = platform::GetIdentityNonceResponse {
4373 version: Some(Version::V0(GetIdentityNonceResponseV0 {
4374 result: Some(V0Result::Proof(Proof::default())),
4375 metadata: Some(ResponseMetadata::default()),
4376 })),
4377 };
4378 let request: platform::GetIdentityNonceRequest = GetIdentityNonceRequestV0 {
4379 identity_id: vec![0u8; 1], prove: true,
4381 }
4382 .into();
4383 let provider = unreachable_provider();
4384 let err = <IdentityNonceFetcher as FromProof<
4385 platform::GetIdentityNonceRequest,
4386 >>::maybe_from_proof(
4387 request,
4388 response,
4389 Network::Testnet,
4390 default_platform_version(),
4391 &provider,
4392 )
4393 .unwrap_err();
4394 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4395 }
4396
4397 #[test]
4398 fn identity_nonce_no_proof_when_response_empty() {
4399 let request = platform::GetIdentityNonceRequest::default();
4400 let response = platform::GetIdentityNonceResponse::default();
4401 let provider = unreachable_provider();
4402 let err = <IdentityNonceFetcher as FromProof<
4403 platform::GetIdentityNonceRequest,
4404 >>::maybe_from_proof(
4405 request,
4406 response,
4407 Network::Testnet,
4408 default_platform_version(),
4409 &provider,
4410 )
4411 .unwrap_err();
4412 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
4413 }
4414
4415 #[test]
4416 fn identity_contract_nonce_rejects_bad_identity_id_length() {
4417 use dapi_grpc::platform::v0::get_identity_contract_nonce_request::GetIdentityContractNonceRequestV0;
4418 use platform::get_identity_contract_nonce_response::{
4419 get_identity_contract_nonce_response_v0::Result as V0Result,
4420 GetIdentityContractNonceResponseV0, Version,
4421 };
4422
4423 let response = platform::GetIdentityContractNonceResponse {
4424 version: Some(Version::V0(GetIdentityContractNonceResponseV0 {
4425 result: Some(V0Result::Proof(Proof::default())),
4426 metadata: Some(ResponseMetadata::default()),
4427 })),
4428 };
4429 let request: platform::GetIdentityContractNonceRequest =
4430 GetIdentityContractNonceRequestV0 {
4431 identity_id: vec![0u8; 10], contract_id: vec![0u8; 32],
4433 prove: true,
4434 }
4435 .into();
4436 let provider = unreachable_provider();
4437 let err = <IdentityContractNonceFetcher as FromProof<
4438 platform::GetIdentityContractNonceRequest,
4439 >>::maybe_from_proof(
4440 request,
4441 response,
4442 Network::Testnet,
4443 default_platform_version(),
4444 &provider,
4445 )
4446 .unwrap_err();
4447 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4448 }
4449
4450 #[test]
4451 fn identity_contract_nonce_rejects_bad_contract_id_length() {
4452 use dapi_grpc::platform::v0::get_identity_contract_nonce_request::GetIdentityContractNonceRequestV0;
4453 use platform::get_identity_contract_nonce_response::{
4454 get_identity_contract_nonce_response_v0::Result as V0Result,
4455 GetIdentityContractNonceResponseV0, Version,
4456 };
4457
4458 let response = platform::GetIdentityContractNonceResponse {
4459 version: Some(Version::V0(GetIdentityContractNonceResponseV0 {
4460 result: Some(V0Result::Proof(Proof::default())),
4461 metadata: Some(ResponseMetadata::default()),
4462 })),
4463 };
4464 let request: platform::GetIdentityContractNonceRequest =
4465 GetIdentityContractNonceRequestV0 {
4466 identity_id: vec![0u8; 32],
4467 contract_id: vec![0u8; 10], prove: true,
4469 }
4470 .into();
4471 let provider = unreachable_provider();
4472 let err = <IdentityContractNonceFetcher as FromProof<
4473 platform::GetIdentityContractNonceRequest,
4474 >>::maybe_from_proof(
4475 request,
4476 response,
4477 Network::Testnet,
4478 default_platform_version(),
4479 &provider,
4480 )
4481 .unwrap_err();
4482 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4483 }
4484
4485 #[test]
4486 fn identity_balance_rejects_bad_id_length() {
4487 use dapi_grpc::platform::v0::get_identity_balance_request::GetIdentityBalanceRequestV0;
4488 use platform::get_identity_balance_response::{
4489 get_identity_balance_response_v0::Result as V0Result, GetIdentityBalanceResponseV0,
4490 Version,
4491 };
4492
4493 let response = platform::GetIdentityBalanceResponse {
4494 version: Some(Version::V0(GetIdentityBalanceResponseV0 {
4495 result: Some(V0Result::Proof(Proof::default())),
4496 metadata: Some(ResponseMetadata::default()),
4497 })),
4498 };
4499 let request: platform::GetIdentityBalanceRequest = GetIdentityBalanceRequestV0 {
4500 id: vec![0u8; 5],
4501 prove: true,
4502 }
4503 .into();
4504 let provider = unreachable_provider();
4505 let err =
4506 <IdentityBalance as FromProof<platform::GetIdentityBalanceRequest>>::maybe_from_proof(
4507 request,
4508 response,
4509 Network::Testnet,
4510 default_platform_version(),
4511 &provider,
4512 )
4513 .unwrap_err();
4514 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4515 }
4516
4517 #[test]
4518 fn identity_balance_empty_version_on_request_version_none() {
4519 use platform::get_identity_balance_response::{
4521 get_identity_balance_response_v0::Result as V0Result, GetIdentityBalanceResponseV0,
4522 Version,
4523 };
4524 let response = platform::GetIdentityBalanceResponse {
4525 version: Some(Version::V0(GetIdentityBalanceResponseV0 {
4526 result: Some(V0Result::Proof(Proof::default())),
4527 metadata: Some(ResponseMetadata::default()),
4528 })),
4529 };
4530 let request = platform::GetIdentityBalanceRequest { version: None };
4531 let provider = unreachable_provider();
4532 let err =
4533 <IdentityBalance as FromProof<platform::GetIdentityBalanceRequest>>::maybe_from_proof(
4534 request,
4535 response,
4536 Network::Testnet,
4537 default_platform_version(),
4538 &provider,
4539 )
4540 .unwrap_err();
4541 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
4542 }
4543
4544 #[test]
4545 fn identity_balance_and_revision_rejects_bad_id_length() {
4546 use dapi_grpc::platform::v0::get_identity_balance_and_revision_request::GetIdentityBalanceAndRevisionRequestV0;
4547 use platform::get_identity_balance_and_revision_response::{
4548 get_identity_balance_and_revision_response_v0::Result as V0Result,
4549 GetIdentityBalanceAndRevisionResponseV0, Version,
4550 };
4551 let response = platform::GetIdentityBalanceAndRevisionResponse {
4552 version: Some(Version::V0(GetIdentityBalanceAndRevisionResponseV0 {
4553 result: Some(V0Result::Proof(Proof::default())),
4554 metadata: Some(ResponseMetadata::default()),
4555 })),
4556 };
4557 let request: platform::GetIdentityBalanceAndRevisionRequest =
4558 GetIdentityBalanceAndRevisionRequestV0 {
4559 id: vec![0u8; 5],
4560 prove: true,
4561 }
4562 .into();
4563 let provider = unreachable_provider();
4564 let err = <IdentityBalanceAndRevision as FromProof<
4565 platform::GetIdentityBalanceAndRevisionRequest,
4566 >>::maybe_from_proof(
4567 request,
4568 response,
4569 Network::Testnet,
4570 default_platform_version(),
4571 &provider,
4572 )
4573 .unwrap_err();
4574 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4575 }
4576
4577 #[test]
4578 fn identities_balances_empty_version_none() {
4579 use platform::get_identities_balances_response::{
4580 get_identities_balances_response_v0::Result as V0Result,
4581 GetIdentitiesBalancesResponseV0, Version,
4582 };
4583 let response = platform::GetIdentitiesBalancesResponse {
4584 version: Some(Version::V0(GetIdentitiesBalancesResponseV0 {
4585 result: Some(V0Result::Proof(Proof::default())),
4586 metadata: Some(ResponseMetadata::default()),
4587 })),
4588 };
4589 let request = platform::GetIdentitiesBalancesRequest { version: None };
4590 let provider = unreachable_provider();
4591 let err =
4592 <IdentityBalances as FromProof<platform::GetIdentitiesBalancesRequest>>::maybe_from_proof(
4593 request,
4594 response,
4595 Network::Testnet,
4596 default_platform_version(),
4597 &provider,
4598 )
4599 .unwrap_err();
4600 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
4601 }
4602
4603 #[test]
4604 fn data_contract_rejects_bad_id_length() {
4605 use dapi_grpc::platform::v0::get_data_contract_request::GetDataContractRequestV0;
4606 use platform::get_data_contract_response::{
4607 get_data_contract_response_v0::Result as V0Result, GetDataContractResponseV0, Version,
4608 };
4609 let response = platform::GetDataContractResponse {
4610 version: Some(Version::V0(GetDataContractResponseV0 {
4611 result: Some(V0Result::Proof(Proof::default())),
4612 metadata: Some(ResponseMetadata::default()),
4613 })),
4614 };
4615 let request: platform::GetDataContractRequest = GetDataContractRequestV0 {
4616 id: vec![0u8; 5],
4617 prove: true,
4618 }
4619 .into();
4620 let provider = unreachable_provider();
4621 let err = <DataContract as FromProof<platform::GetDataContractRequest>>::maybe_from_proof(
4622 request,
4623 response,
4624 Network::Testnet,
4625 default_platform_version(),
4626 &provider,
4627 )
4628 .unwrap_err();
4629 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4630 }
4631
4632 #[test]
4633 fn data_contract_no_proof_when_response_empty() {
4634 let request = platform::GetDataContractRequest::default();
4635 let response = platform::GetDataContractResponse::default();
4636 let provider = unreachable_provider();
4637 let err = <DataContract as FromProof<platform::GetDataContractRequest>>::maybe_from_proof(
4638 request,
4639 response,
4640 Network::Testnet,
4641 default_platform_version(),
4642 &provider,
4643 )
4644 .unwrap_err();
4645 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
4646 }
4647
4648 #[test]
4649 fn data_contract_with_serialization_rejects_bad_id_length() {
4650 use dapi_grpc::platform::v0::get_data_contract_request::GetDataContractRequestV0;
4652 use platform::get_data_contract_response::{
4653 get_data_contract_response_v0::Result as V0Result, GetDataContractResponseV0, Version,
4654 };
4655 let response = platform::GetDataContractResponse {
4656 version: Some(Version::V0(GetDataContractResponseV0 {
4657 result: Some(V0Result::Proof(Proof::default())),
4658 metadata: Some(ResponseMetadata::default()),
4659 })),
4660 };
4661 let request: platform::GetDataContractRequest = GetDataContractRequestV0 {
4662 id: vec![0u8; 5],
4663 prove: true,
4664 }
4665 .into();
4666 let provider = unreachable_provider();
4667 let err =
4668 <(DataContract, Vec<u8>) as FromProof<platform::GetDataContractRequest>>::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 data_contract_history_rejects_bad_id_length() {
4681 use dapi_grpc::platform::v0::get_data_contract_history_request::GetDataContractHistoryRequestV0;
4682 use platform::get_data_contract_history_response::{
4683 get_data_contract_history_response_v0::Result as V0Result,
4684 GetDataContractHistoryResponseV0, Version,
4685 };
4686 let response = platform::GetDataContractHistoryResponse {
4687 version: Some(Version::V0(GetDataContractHistoryResponseV0 {
4688 result: Some(V0Result::Proof(Proof::default())),
4689 metadata: Some(ResponseMetadata::default()),
4690 })),
4691 };
4692 let request: platform::GetDataContractHistoryRequest = GetDataContractHistoryRequestV0 {
4693 id: vec![0u8; 5],
4694 limit: None,
4695 offset: None,
4696 start_at_ms: 0,
4697 prove: true,
4698 }
4699 .into();
4700 let provider = unreachable_provider();
4701 let err = <DataContractHistory as FromProof<
4702 platform::GetDataContractHistoryRequest,
4703 >>::maybe_from_proof(
4704 request,
4705 response,
4706 Network::Testnet,
4707 default_platform_version(),
4708 &provider,
4709 )
4710 .unwrap_err();
4711 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4712 }
4713
4714 #[test]
4715 fn data_contract_history_rejects_overflowing_limit() {
4716 use dapi_grpc::platform::v0::get_data_contract_history_request::GetDataContractHistoryRequestV0;
4717 use platform::get_data_contract_history_response::{
4718 get_data_contract_history_response_v0::Result as V0Result,
4719 GetDataContractHistoryResponseV0, Version,
4720 };
4721 let response = platform::GetDataContractHistoryResponse {
4722 version: Some(Version::V0(GetDataContractHistoryResponseV0 {
4723 result: Some(V0Result::Proof(Proof::default())),
4724 metadata: Some(ResponseMetadata::default()),
4725 })),
4726 };
4727 let request: platform::GetDataContractHistoryRequest = GetDataContractHistoryRequestV0 {
4728 id: vec![0u8; 32],
4729 limit: Some(100_000),
4730 offset: None,
4731 start_at_ms: 0,
4732 prove: true,
4733 }
4734 .into();
4735 let provider = unreachable_provider();
4736 let err = <DataContractHistory as FromProof<
4737 platform::GetDataContractHistoryRequest,
4738 >>::maybe_from_proof(
4739 request,
4740 response,
4741 Network::Testnet,
4742 default_platform_version(),
4743 &provider,
4744 )
4745 .unwrap_err();
4746 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
4747 }
4748
4749 #[test]
4750 fn document_history_no_proof_when_response_empty() {
4751 let request = platform::GetDocumentHistoryRequest::default();
4752 let response = platform::GetDocumentHistoryResponse::default();
4753 let provider = unreachable_provider();
4754
4755 let err = document_history_error(request, response, &provider);
4756
4757 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
4758 }
4759
4760 #[test]
4761 fn document_history_empty_response_metadata() {
4762 use platform::get_document_history_response::{
4763 get_document_history_response_v0::Result as V0Result, GetDocumentHistoryResponseV0,
4764 Version,
4765 };
4766 let request = platform::GetDocumentHistoryRequest::default();
4767 let response = platform::GetDocumentHistoryResponse {
4768 version: Some(Version::V0(GetDocumentHistoryResponseV0 {
4769 result: Some(V0Result::Proof(Proof::default())),
4770 metadata: None,
4771 })),
4772 };
4773 let provider = unreachable_provider();
4774
4775 let err = document_history_error(request, response, &provider);
4776
4777 assert!(matches!(err, Error::EmptyResponseMetadata), "got: {err:?}");
4778 }
4779
4780 #[test]
4781 fn document_history_empty_version() {
4782 let request = platform::GetDocumentHistoryRequest { version: None };
4783 let response = document_history_response_with_proof_and_metadata();
4784 let provider = unreachable_provider();
4785
4786 let err = document_history_error(request, response, &provider);
4787
4788 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
4789 }
4790
4791 #[test]
4792 fn document_history_rejects_bad_contract_id_length() {
4793 let request =
4794 document_history_request(vec![0u8; 5], "niceDocument", vec![1u8; 32], None, None);
4795 let response = document_history_response_with_proof_and_metadata();
4796 let provider = unreachable_provider();
4797
4798 let err = document_history_error(request, response, &provider);
4799
4800 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4801 }
4802
4803 #[test]
4804 fn document_history_rejects_bad_document_id_length() {
4805 let request =
4806 document_history_request(vec![0u8; 32], "niceDocument", vec![1u8; 5], None, None);
4807 let response = document_history_response_with_proof_and_metadata();
4808 let provider = unreachable_provider();
4809
4810 let err = document_history_error(request, response, &provider);
4811
4812 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4813 }
4814
4815 #[test]
4816 fn document_history_rejects_overflowing_limit() {
4817 let request = document_history_request(
4818 vec![0u8; 32],
4819 "niceDocument",
4820 vec![1u8; 32],
4821 Some(100_000),
4822 None,
4823 );
4824 let response = document_history_response_with_proof_and_metadata();
4825 let provider = unreachable_provider();
4826
4827 let err = document_history_error(request, response, &provider);
4828
4829 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
4830 }
4831
4832 #[test]
4833 fn document_history_returns_not_found_when_contract_provider_misses() {
4834 let request =
4835 document_history_request(vec![0u8; 32], "niceDocument", vec![1u8; 32], None, None);
4836 let response = document_history_response_with_proof_and_metadata();
4837 let provider = NoDataContractProvider;
4838
4839 let err = document_history_error(request, response, &provider);
4840
4841 assert!(matches!(err, Error::NotFound), "got: {err:?}");
4842 }
4843
4844 #[test]
4845 fn document_history_rejects_unknown_document_type() {
4846 let data_contract = dpp::tests::fixtures::get_data_contract_fixture(
4847 None,
4848 0,
4849 default_platform_version().protocol_version,
4850 )
4851 .data_contract_owned();
4852 let contract_id = data_contract.id().to_vec();
4853 let provider = StaticDataContractProvider {
4854 data_contract: std::sync::Arc::new(data_contract),
4855 };
4856 let request =
4857 document_history_request(contract_id, "missingDocument", vec![1u8; 32], None, None);
4858 let response = document_history_response_with_proof_and_metadata();
4859
4860 let err = document_history_error(request, response, &provider);
4861
4862 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
4863 }
4864
4865 #[test]
4866 fn address_info_rejects_bad_address_bytes() {
4867 use dapi_grpc::platform::v0::get_address_info_request::GetAddressInfoRequestV0;
4869 use platform::get_address_info_response::{
4870 get_address_info_response_v0::Result as V0Result, GetAddressInfoResponseV0, Version,
4871 };
4872 let response = platform::GetAddressInfoResponse {
4873 version: Some(Version::V0(GetAddressInfoResponseV0 {
4874 result: Some(V0Result::Proof(Proof::default())),
4875 metadata: Some(ResponseMetadata::default()),
4876 })),
4877 };
4878 let request: platform::GetAddressInfoRequest = GetAddressInfoRequestV0 {
4879 address: vec![0u8; 3], prove: true,
4881 }
4882 .into();
4883 let provider = unreachable_provider();
4884 let err = <AddressInfo as FromProof<platform::GetAddressInfoRequest>>::maybe_from_proof(
4885 request,
4886 response,
4887 Network::Testnet,
4888 default_platform_version(),
4889 &provider,
4890 )
4891 .unwrap_err();
4892 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
4893 }
4894
4895 #[test]
4896 fn addresses_infos_rejects_bad_address_bytes() {
4897 use dapi_grpc::platform::v0::get_addresses_infos_request::GetAddressesInfosRequestV0;
4898 use platform::get_addresses_infos_response::{
4899 get_addresses_infos_response_v0::Result as V0Result, GetAddressesInfosResponseV0,
4900 Version,
4901 };
4902 let response = platform::GetAddressesInfosResponse {
4903 version: Some(Version::V0(GetAddressesInfosResponseV0 {
4904 result: Some(V0Result::Proof(Proof::default())),
4905 metadata: Some(ResponseMetadata::default()),
4906 })),
4907 };
4908 let request: platform::GetAddressesInfosRequest = GetAddressesInfosRequestV0 {
4909 addresses: vec![vec![0u8; 3]],
4910 prove: true,
4911 }
4912 .into();
4913 let provider = unreachable_provider();
4914 let err =
4915 <AddressInfos as FromProof<platform::GetAddressesInfosRequest>>::maybe_from_proof(
4916 request,
4917 response,
4918 Network::Testnet,
4919 default_platform_version(),
4920 &provider,
4921 )
4922 .unwrap_err();
4923 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
4924 }
4925
4926 #[test]
4927 fn addresses_trunk_state_grove_no_proof() {
4928 let response = platform::GetAddressesTrunkStateResponse::default();
4931 let request = platform::GetAddressesTrunkStateRequest::default();
4932 let provider = unreachable_provider();
4933 let err = <GroveTrunkQueryResult as FromProof<
4934 platform::GetAddressesTrunkStateRequest,
4935 >>::maybe_from_proof(
4936 request,
4937 response,
4938 Network::Testnet,
4939 default_platform_version(),
4940 &provider,
4941 )
4942 .unwrap_err();
4943 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
4944 }
4945
4946 #[test]
4947 fn platform_address_trunk_state_no_proof() {
4948 let response = platform::GetAddressesTrunkStateResponse::default();
4950 let request = platform::GetAddressesTrunkStateRequest::default();
4951 let provider = unreachable_provider();
4952 let err = <PlatformAddressTrunkState as FromProof<
4953 platform::GetAddressesTrunkStateRequest,
4954 >>::maybe_from_proof(
4955 request,
4956 response,
4957 Network::Testnet,
4958 default_platform_version(),
4959 &provider,
4960 )
4961 .unwrap_err();
4962 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
4963 }
4964
4965 #[test]
4966 fn epochs_info_empty_version_none() {
4967 use platform::get_epochs_info_response::{
4968 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
4969 };
4970 let response = platform::GetEpochsInfoResponse {
4971 version: Some(Version::V0(GetEpochsInfoResponseV0 {
4972 result: Some(V0Result::Proof(Proof::default())),
4973 metadata: Some(ResponseMetadata::default()),
4974 })),
4975 };
4976 let request = platform::GetEpochsInfoRequest { version: None };
4977 let provider = unreachable_provider();
4978 let err =
4979 <ExtendedEpochInfos as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
4980 request,
4981 response,
4982 Network::Testnet,
4983 default_platform_version(),
4984 &provider,
4985 )
4986 .unwrap_err();
4987 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
4988 }
4989
4990 #[test]
4991 fn epochs_info_rejects_overflowing_count() {
4992 use dapi_grpc::platform::v0::get_epochs_info_request::GetEpochsInfoRequestV0;
4994 use platform::get_epochs_info_response::{
4995 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
4996 };
4997 let response = platform::GetEpochsInfoResponse {
4998 version: Some(Version::V0(GetEpochsInfoResponseV0 {
4999 result: Some(V0Result::Proof(Proof::default())),
5000 metadata: Some(default_metadata_with_epoch(10)),
5001 })),
5002 };
5003 let request = platform::GetEpochsInfoRequest {
5004 version: Some(platform::get_epochs_info_request::Version::V0(
5005 GetEpochsInfoRequestV0 {
5006 start_epoch: Some(0),
5007 count: 100_000,
5008 ascending: true,
5009 prove: true,
5010 },
5011 )),
5012 };
5013 let provider = unreachable_provider();
5014 let err =
5015 <ExtendedEpochInfos as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
5016 request,
5017 response,
5018 Network::Testnet,
5019 default_platform_version(),
5020 &provider,
5021 )
5022 .unwrap_err();
5023 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5024 }
5025
5026 #[test]
5027 fn epochs_info_rejects_overflowing_metadata_epoch() {
5028 use dapi_grpc::platform::v0::get_epochs_info_request::GetEpochsInfoRequestV0;
5031 use platform::get_epochs_info_response::{
5032 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
5033 };
5034 let response = platform::GetEpochsInfoResponse {
5035 version: Some(Version::V0(GetEpochsInfoResponseV0 {
5036 result: Some(V0Result::Proof(Proof::default())),
5037 metadata: Some(default_metadata_with_epoch(70_000)),
5038 })),
5039 };
5040 let request = platform::GetEpochsInfoRequest {
5041 version: Some(platform::get_epochs_info_request::Version::V0(
5042 GetEpochsInfoRequestV0 {
5043 start_epoch: None,
5044 count: 1,
5045 ascending: true,
5046 prove: true,
5047 },
5048 )),
5049 };
5050 let provider = unreachable_provider();
5051 let err =
5052 <ExtendedEpochInfos as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
5053 request,
5054 response,
5055 Network::Testnet,
5056 default_platform_version(),
5057 &provider,
5058 )
5059 .unwrap_err();
5060 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5061 }
5062
5063 #[test]
5064 fn extended_epoch_info_single_bubbles_empty_version() {
5065 use platform::get_epochs_info_response::{
5067 get_epochs_info_response_v0::Result as V0Result, GetEpochsInfoResponseV0, Version,
5068 };
5069 let response = platform::GetEpochsInfoResponse {
5070 version: Some(Version::V0(GetEpochsInfoResponseV0 {
5071 result: Some(V0Result::Proof(Proof::default())),
5072 metadata: Some(ResponseMetadata::default()),
5073 })),
5074 };
5075 let request = platform::GetEpochsInfoRequest { version: None };
5076 let provider = unreachable_provider();
5077 let err =
5078 <ExtendedEpochInfo as FromProof<platform::GetEpochsInfoRequest>>::maybe_from_proof(
5079 request,
5080 response,
5081 Network::Testnet,
5082 default_platform_version(),
5083 &provider,
5084 )
5085 .unwrap_err();
5086 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5087 }
5088
5089 #[test]
5090 fn finalized_epoch_infos_rejects_overflowing_start_index() {
5091 use dapi_grpc::platform::v0::get_finalized_epoch_infos_request::GetFinalizedEpochInfosRequestV0;
5092 use platform::get_finalized_epoch_infos_response::{
5093 get_finalized_epoch_infos_response_v0::Result as V0Result,
5094 GetFinalizedEpochInfosResponseV0, Version,
5095 };
5096 let response = platform::GetFinalizedEpochInfosResponse {
5097 version: Some(Version::V0(GetFinalizedEpochInfosResponseV0 {
5098 result: Some(V0Result::Proof(Proof::default())),
5099 metadata: Some(ResponseMetadata::default()),
5100 })),
5101 };
5102 let request: platform::GetFinalizedEpochInfosRequest = GetFinalizedEpochInfosRequestV0 {
5103 start_epoch_index: 100_000,
5104 start_epoch_index_included: true,
5105 end_epoch_index: 1,
5106 end_epoch_index_included: true,
5107 prove: true,
5108 }
5109 .into();
5110 let provider = unreachable_provider();
5111 let err = <FinalizedEpochInfos as FromProof<
5112 platform::GetFinalizedEpochInfosRequest,
5113 >>::maybe_from_proof(
5114 request,
5115 response,
5116 Network::Testnet,
5117 default_platform_version(),
5118 &provider,
5119 )
5120 .unwrap_err();
5121 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5122 }
5123
5124 #[test]
5125 fn finalized_epoch_infos_rejects_overflowing_end_index() {
5126 use dapi_grpc::platform::v0::get_finalized_epoch_infos_request::GetFinalizedEpochInfosRequestV0;
5127 use platform::get_finalized_epoch_infos_response::{
5128 get_finalized_epoch_infos_response_v0::Result as V0Result,
5129 GetFinalizedEpochInfosResponseV0, Version,
5130 };
5131 let response = platform::GetFinalizedEpochInfosResponse {
5132 version: Some(Version::V0(GetFinalizedEpochInfosResponseV0 {
5133 result: Some(V0Result::Proof(Proof::default())),
5134 metadata: Some(ResponseMetadata::default()),
5135 })),
5136 };
5137 let request: platform::GetFinalizedEpochInfosRequest = GetFinalizedEpochInfosRequestV0 {
5138 start_epoch_index: 1,
5139 start_epoch_index_included: true,
5140 end_epoch_index: 100_000,
5141 end_epoch_index_included: true,
5142 prove: true,
5143 }
5144 .into();
5145 let provider = unreachable_provider();
5146 let err = <FinalizedEpochInfos as FromProof<
5147 platform::GetFinalizedEpochInfosRequest,
5148 >>::maybe_from_proof(
5149 request,
5150 response,
5151 Network::Testnet,
5152 default_platform_version(),
5153 &provider,
5154 )
5155 .unwrap_err();
5156 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5157 }
5158
5159 #[test]
5160 fn upgrade_state_no_proof_when_response_empty() {
5161 let response = GetProtocolVersionUpgradeStateResponse::default();
5163 let request = GetProtocolVersionUpgradeStateRequest::default();
5164 let provider = unreachable_provider();
5165 let err = <ProtocolVersionUpgrades as FromProof<
5166 GetProtocolVersionUpgradeStateRequest,
5167 >>::maybe_from_proof(
5168 request,
5169 response,
5170 Network::Testnet,
5171 default_platform_version(),
5172 &provider,
5173 )
5174 .unwrap_err();
5175 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5176 }
5177
5178 #[test]
5179 fn upgrade_vote_status_no_proof_when_response_empty() {
5180 let response = GetProtocolVersionUpgradeVoteStatusResponse::default();
5181 let request = GetProtocolVersionUpgradeVoteStatusRequest::default();
5182 let provider = unreachable_provider();
5183 let err = <MasternodeProtocolVotes as FromProof<
5184 GetProtocolVersionUpgradeVoteStatusRequest,
5185 >>::maybe_from_proof(
5186 request,
5187 response,
5188 Network::Testnet,
5189 default_platform_version(),
5190 &provider,
5191 )
5192 .unwrap_err();
5193 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5194 }
5195
5196 #[test]
5197 fn upgrade_vote_status_rejects_overflowing_count() {
5198 use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_request::GetProtocolVersionUpgradeVoteStatusRequestV0;
5199 use dapi_grpc::platform::v0::get_protocol_version_upgrade_vote_status_response::{
5200 get_protocol_version_upgrade_vote_status_response_v0::Result as V0Result,
5201 GetProtocolVersionUpgradeVoteStatusResponseV0, Version,
5202 };
5203
5204 let response = GetProtocolVersionUpgradeVoteStatusResponse {
5205 version: Some(Version::V0(GetProtocolVersionUpgradeVoteStatusResponseV0 {
5206 result: Some(V0Result::Proof(Proof::default())),
5207 metadata: Some(ResponseMetadata::default()),
5208 })),
5209 };
5210 let request: GetProtocolVersionUpgradeVoteStatusRequest =
5212 GetProtocolVersionUpgradeVoteStatusRequestV0 {
5213 start_pro_tx_hash: vec![],
5214 count: 100_000,
5215 prove: true,
5216 }
5217 .into();
5218 let provider = unreachable_provider();
5219 let err = <MasternodeProtocolVotes as FromProof<
5220 GetProtocolVersionUpgradeVoteStatusRequest,
5221 >>::maybe_from_proof(
5222 request,
5223 response,
5224 Network::Testnet,
5225 default_platform_version(),
5226 &provider,
5227 )
5228 .unwrap_err();
5229 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5230 }
5231
5232 #[test]
5233 fn path_elements_empty_version_when_no_version() {
5234 use platform::get_path_elements_response::{
5236 get_path_elements_response_v0::Result as V0Result, GetPathElementsResponseV0, Version,
5237 };
5238 let response = GetPathElementsResponse {
5239 version: Some(Version::V0(GetPathElementsResponseV0 {
5240 result: Some(V0Result::Proof(Proof::default())),
5241 metadata: Some(ResponseMetadata::default()),
5242 })),
5243 };
5244 let request = GetPathElementsRequest { version: None };
5245 let provider = unreachable_provider();
5246 let err = <Elements as FromProof<GetPathElementsRequest>>::maybe_from_proof(
5247 request,
5248 response,
5249 Network::Testnet,
5250 default_platform_version(),
5251 &provider,
5252 )
5253 .unwrap_err();
5254 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5255 }
5256
5257 #[test]
5258 fn identities_contract_keys_rejects_bad_identity_id() {
5259 use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0;
5260 use platform::get_identities_contract_keys_response::{
5261 get_identities_contract_keys_response_v0::Result as V0Result,
5262 GetIdentitiesContractKeysResponseV0, Version,
5263 };
5264 let response = platform::GetIdentitiesContractKeysResponse {
5265 version: Some(Version::V0(GetIdentitiesContractKeysResponseV0 {
5266 result: Some(V0Result::Proof(Proof::default())),
5267 metadata: Some(ResponseMetadata::default()),
5268 })),
5269 };
5270 let request: platform::GetIdentitiesContractKeysRequest =
5271 GetIdentitiesContractKeysRequestV0 {
5272 identities_ids: vec![vec![0u8; 5]], contract_id: vec![0u8; 32],
5274 document_type_name: None,
5275 purposes: vec![0],
5276 prove: true,
5277 }
5278 .into();
5279 let provider = unreachable_provider();
5280 let err = <IdentitiesContractKeys as FromProof<
5281 platform::GetIdentitiesContractKeysRequest,
5282 >>::maybe_from_proof(
5283 request,
5284 response,
5285 Network::Testnet,
5286 default_platform_version(),
5287 &provider,
5288 )
5289 .unwrap_err();
5290 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5291 }
5292
5293 #[test]
5294 fn identities_contract_keys_rejects_bad_contract_id() {
5295 use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0;
5296 use platform::get_identities_contract_keys_response::{
5297 get_identities_contract_keys_response_v0::Result as V0Result,
5298 GetIdentitiesContractKeysResponseV0, Version,
5299 };
5300 let response = platform::GetIdentitiesContractKeysResponse {
5301 version: Some(Version::V0(GetIdentitiesContractKeysResponseV0 {
5302 result: Some(V0Result::Proof(Proof::default())),
5303 metadata: Some(ResponseMetadata::default()),
5304 })),
5305 };
5306 let request: platform::GetIdentitiesContractKeysRequest =
5307 GetIdentitiesContractKeysRequestV0 {
5308 identities_ids: vec![vec![0u8; 32]],
5309 contract_id: vec![0u8; 5], document_type_name: None,
5311 purposes: vec![0],
5312 prove: true,
5313 }
5314 .into();
5315 let provider = unreachable_provider();
5316 let err = <IdentitiesContractKeys as FromProof<
5317 platform::GetIdentitiesContractKeysRequest,
5318 >>::maybe_from_proof(
5319 request,
5320 response,
5321 Network::Testnet,
5322 default_platform_version(),
5323 &provider,
5324 )
5325 .unwrap_err();
5326 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5327 }
5328
5329 #[test]
5330 fn identities_contract_keys_rejects_bad_purpose() {
5331 use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0;
5332 use platform::get_identities_contract_keys_response::{
5333 get_identities_contract_keys_response_v0::Result as V0Result,
5334 GetIdentitiesContractKeysResponseV0, Version,
5335 };
5336 let response = platform::GetIdentitiesContractKeysResponse {
5337 version: Some(Version::V0(GetIdentitiesContractKeysResponseV0 {
5338 result: Some(V0Result::Proof(Proof::default())),
5339 metadata: Some(ResponseMetadata::default()),
5340 })),
5341 };
5342 let request: platform::GetIdentitiesContractKeysRequest =
5344 GetIdentitiesContractKeysRequestV0 {
5345 identities_ids: vec![vec![0u8; 32]],
5346 contract_id: vec![0u8; 32],
5347 document_type_name: None,
5348 purposes: vec![250],
5349 prove: true,
5350 }
5351 .into();
5352 let provider = unreachable_provider();
5353 let err = <IdentitiesContractKeys as FromProof<
5354 platform::GetIdentitiesContractKeysRequest,
5355 >>::maybe_from_proof(
5356 request,
5357 response,
5358 Network::Testnet,
5359 default_platform_version(),
5360 &provider,
5361 )
5362 .unwrap_err();
5363 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5364 }
5365
5366 #[test]
5367 fn prefunded_balance_empty_version_on_request_version_none() {
5368 use platform::get_prefunded_specialized_balance_response::{
5370 get_prefunded_specialized_balance_response_v0::Result as V0Result,
5371 GetPrefundedSpecializedBalanceResponseV0, Version,
5372 };
5373 let response = platform::GetPrefundedSpecializedBalanceResponse {
5374 version: Some(Version::V0(GetPrefundedSpecializedBalanceResponseV0 {
5375 result: Some(V0Result::Proof(Proof::default())),
5376 metadata: Some(ResponseMetadata::default()),
5377 })),
5378 };
5379 let request = platform::GetPrefundedSpecializedBalanceRequest { version: None };
5380 let provider = unreachable_provider();
5381 let err = <PrefundedSpecializedBalance as FromProof<
5382 platform::GetPrefundedSpecializedBalanceRequest,
5383 >>::maybe_from_proof(
5384 request,
5385 response,
5386 Network::Testnet,
5387 default_platform_version(),
5388 &provider,
5389 )
5390 .unwrap_err();
5391 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5392 }
5393
5394 #[test]
5395 fn evonodes_proposed_epoch_blocks_by_ids_empty_version() {
5396 use platform::get_evonodes_proposed_epoch_blocks_response::{
5397 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
5398 GetEvonodesProposedEpochBlocksResponseV0, Version,
5399 };
5400 let response = platform::GetEvonodesProposedEpochBlocksResponse {
5401 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
5402 result: Some(V0Result::Proof(Proof::default())),
5403 metadata: Some(ResponseMetadata::default()),
5404 })),
5405 };
5406 let request = platform::GetEvonodesProposedEpochBlocksByIdsRequest { version: None };
5407 let provider = unreachable_provider();
5408 let err = <ProposerBlockCounts as FromProof<
5409 platform::GetEvonodesProposedEpochBlocksByIdsRequest,
5410 >>::maybe_from_proof(
5411 request,
5412 response,
5413 Network::Testnet,
5414 default_platform_version(),
5415 &provider,
5416 )
5417 .unwrap_err();
5418 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5419 }
5420
5421 #[test]
5422 fn evonodes_proposed_epoch_blocks_by_ids_rejects_overflowing_epoch() {
5423 use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_ids_request::GetEvonodesProposedEpochBlocksByIdsRequestV0;
5425 use platform::get_evonodes_proposed_epoch_blocks_response::{
5426 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
5427 GetEvonodesProposedEpochBlocksResponseV0, Version,
5428 };
5429 let response = platform::GetEvonodesProposedEpochBlocksResponse {
5430 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
5431 result: Some(V0Result::Proof(Proof::default())),
5432 metadata: Some(default_metadata_with_epoch(1)),
5433 })),
5434 };
5435 let request: platform::GetEvonodesProposedEpochBlocksByIdsRequest =
5436 GetEvonodesProposedEpochBlocksByIdsRequestV0 {
5437 epoch: Some(100_000),
5438 ids: vec![],
5439 prove: true,
5440 }
5441 .into();
5442 let provider = unreachable_provider();
5443 let err = <ProposerBlockCounts as FromProof<
5444 platform::GetEvonodesProposedEpochBlocksByIdsRequest,
5445 >>::maybe_from_proof(
5446 request,
5447 response,
5448 Network::Testnet,
5449 default_platform_version(),
5450 &provider,
5451 )
5452 .unwrap_err();
5453 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5454 }
5455
5456 #[test]
5457 fn evonodes_proposed_epoch_blocks_by_ids_falls_back_to_metadata_epoch_overflow() {
5458 use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_ids_request::GetEvonodesProposedEpochBlocksByIdsRequestV0;
5460 use platform::get_evonodes_proposed_epoch_blocks_response::{
5461 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
5462 GetEvonodesProposedEpochBlocksResponseV0, Version,
5463 };
5464 let response = platform::GetEvonodesProposedEpochBlocksResponse {
5465 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
5466 result: Some(V0Result::Proof(Proof::default())),
5467 metadata: Some(default_metadata_with_epoch(99_999)),
5468 })),
5469 };
5470 let request: platform::GetEvonodesProposedEpochBlocksByIdsRequest =
5471 GetEvonodesProposedEpochBlocksByIdsRequestV0 {
5472 epoch: None,
5473 ids: vec![],
5474 prove: true,
5475 }
5476 .into();
5477 let provider = unreachable_provider();
5478 let err = <ProposerBlockCounts as FromProof<
5479 platform::GetEvonodesProposedEpochBlocksByIdsRequest,
5480 >>::maybe_from_proof(
5481 request,
5482 response,
5483 Network::Testnet,
5484 default_platform_version(),
5485 &provider,
5486 )
5487 .unwrap_err();
5488 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5489 }
5490
5491 #[test]
5492 fn evonodes_proposed_epoch_blocks_by_range_empty_version() {
5493 use platform::get_evonodes_proposed_epoch_blocks_response::{
5494 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
5495 GetEvonodesProposedEpochBlocksResponseV0, Version,
5496 };
5497 let response = platform::GetEvonodesProposedEpochBlocksResponse {
5498 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
5499 result: Some(V0Result::Proof(Proof::default())),
5500 metadata: Some(ResponseMetadata::default()),
5501 })),
5502 };
5503 let request = platform::GetEvonodesProposedEpochBlocksByRangeRequest { version: None };
5504 let provider = unreachable_provider();
5505 let err = <ProposerBlockCounts as FromProof<
5506 platform::GetEvonodesProposedEpochBlocksByRangeRequest,
5507 >>::maybe_from_proof(
5508 request,
5509 response,
5510 Network::Testnet,
5511 default_platform_version(),
5512 &provider,
5513 )
5514 .unwrap_err();
5515 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5516 }
5517
5518 #[test]
5519 fn evonodes_proposed_epoch_blocks_by_range_rejects_bad_start_after() {
5520 use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::{
5522 get_evonodes_proposed_epoch_blocks_by_range_request_v0::Start,
5523 GetEvonodesProposedEpochBlocksByRangeRequestV0,
5524 };
5525 use platform::get_evonodes_proposed_epoch_blocks_response::{
5526 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
5527 GetEvonodesProposedEpochBlocksResponseV0, Version,
5528 };
5529 let response = platform::GetEvonodesProposedEpochBlocksResponse {
5530 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
5531 result: Some(V0Result::Proof(Proof::default())),
5532 metadata: Some(default_metadata_with_epoch(1)),
5533 })),
5534 };
5535 let request: platform::GetEvonodesProposedEpochBlocksByRangeRequest =
5536 GetEvonodesProposedEpochBlocksByRangeRequestV0 {
5537 epoch: Some(1),
5538 limit: None,
5539 start: Some(Start::StartAfter(vec![0u8; 5])),
5540 prove: true,
5541 }
5542 .into();
5543 let provider = unreachable_provider();
5544 let err = <ProposerBlockCounts as FromProof<
5545 platform::GetEvonodesProposedEpochBlocksByRangeRequest,
5546 >>::maybe_from_proof(
5547 request,
5548 response,
5549 Network::Testnet,
5550 default_platform_version(),
5551 &provider,
5552 )
5553 .unwrap_err();
5554 assert!(matches!(err, Error::DriveError { .. }), "got: {err:?}");
5555 }
5556
5557 #[test]
5558 fn evonodes_proposed_epoch_blocks_by_range_rejects_bad_start_at() {
5559 use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::{
5561 get_evonodes_proposed_epoch_blocks_by_range_request_v0::Start,
5562 GetEvonodesProposedEpochBlocksByRangeRequestV0,
5563 };
5564 use platform::get_evonodes_proposed_epoch_blocks_response::{
5565 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
5566 GetEvonodesProposedEpochBlocksResponseV0, Version,
5567 };
5568 let response = platform::GetEvonodesProposedEpochBlocksResponse {
5569 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
5570 result: Some(V0Result::Proof(Proof::default())),
5571 metadata: Some(default_metadata_with_epoch(1)),
5572 })),
5573 };
5574 let request: platform::GetEvonodesProposedEpochBlocksByRangeRequest =
5575 GetEvonodesProposedEpochBlocksByRangeRequestV0 {
5576 epoch: Some(1),
5577 limit: None,
5578 start: Some(Start::StartAt(vec![0u8; 4])),
5579 prove: true,
5580 }
5581 .into();
5582 let provider = unreachable_provider();
5583 let err = <ProposerBlockCounts as FromProof<
5584 platform::GetEvonodesProposedEpochBlocksByRangeRequest,
5585 >>::maybe_from_proof(
5586 request,
5587 response,
5588 Network::Testnet,
5589 default_platform_version(),
5590 &provider,
5591 )
5592 .unwrap_err();
5593 assert!(matches!(err, Error::DriveError { .. }), "got: {err:?}");
5594 }
5595
5596 #[test]
5597 fn evonodes_proposed_epoch_blocks_by_range_rejects_overflow_limit() {
5598 use dapi_grpc::platform::v0::get_evonodes_proposed_epoch_blocks_by_range_request::GetEvonodesProposedEpochBlocksByRangeRequestV0;
5599 use platform::get_evonodes_proposed_epoch_blocks_response::{
5600 get_evonodes_proposed_epoch_blocks_response_v0::Result as V0Result,
5601 GetEvonodesProposedEpochBlocksResponseV0, Version,
5602 };
5603 let response = platform::GetEvonodesProposedEpochBlocksResponse {
5604 version: Some(Version::V0(GetEvonodesProposedEpochBlocksResponseV0 {
5605 result: Some(V0Result::Proof(Proof::default())),
5606 metadata: Some(default_metadata_with_epoch(1)),
5607 })),
5608 };
5609 let request: platform::GetEvonodesProposedEpochBlocksByRangeRequest =
5610 GetEvonodesProposedEpochBlocksByRangeRequestV0 {
5611 epoch: Some(1),
5612 limit: Some(100_000),
5613 start: None,
5614 prove: true,
5615 }
5616 .into();
5617 let provider = unreachable_provider();
5618 let err = <ProposerBlockCounts as FromProof<
5619 platform::GetEvonodesProposedEpochBlocksByRangeRequest,
5620 >>::maybe_from_proof(
5621 request,
5622 response,
5623 Network::Testnet,
5624 default_platform_version(),
5625 &provider,
5626 )
5627 .unwrap_err();
5628 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5629 }
5630
5631 #[test]
5632 fn shielded_pool_state_no_proof_when_response_empty() {
5633 let response = platform::GetShieldedPoolStateResponse::default();
5634 let request = platform::GetShieldedPoolStateRequest::default();
5635 let provider = unreachable_provider();
5636 let err = <ShieldedPoolState as FromProof<
5637 platform::GetShieldedPoolStateRequest,
5638 >>::maybe_from_proof(
5639 request,
5640 response,
5641 Network::Testnet,
5642 default_platform_version(),
5643 &provider,
5644 )
5645 .unwrap_err();
5646 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5647 }
5648
5649 #[test]
5650 fn shielded_notes_count_no_proof_when_response_empty() {
5651 let response = platform::GetShieldedNotesCountResponse::default();
5652 let request = platform::GetShieldedNotesCountRequest::default();
5653 let provider = unreachable_provider();
5654 let err = <ShieldedNotesCount as FromProof<
5655 platform::GetShieldedNotesCountRequest,
5656 >>::maybe_from_proof(
5657 request,
5658 response,
5659 Network::Testnet,
5660 default_platform_version(),
5661 &provider,
5662 )
5663 .unwrap_err();
5664 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5665 }
5666
5667 #[test]
5668 fn shielded_anchors_no_proof_when_response_empty() {
5669 let response = platform::GetShieldedAnchorsResponse::default();
5670 let request = platform::GetShieldedAnchorsRequest::default();
5671 let provider = unreachable_provider();
5672 let err =
5673 <ShieldedAnchors as FromProof<platform::GetShieldedAnchorsRequest>>::maybe_from_proof(
5674 request,
5675 response,
5676 Network::Testnet,
5677 default_platform_version(),
5678 &provider,
5679 )
5680 .unwrap_err();
5681 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5682 }
5683
5684 #[test]
5685 fn most_recent_shielded_anchor_no_proof_when_response_empty() {
5686 let response = platform::GetMostRecentShieldedAnchorResponse::default();
5687 let request = platform::GetMostRecentShieldedAnchorRequest::default();
5688 let provider = unreachable_provider();
5689 let err = <MostRecentShieldedAnchor as FromProof<
5690 platform::GetMostRecentShieldedAnchorRequest,
5691 >>::maybe_from_proof(
5692 request,
5693 response,
5694 Network::Testnet,
5695 default_platform_version(),
5696 &provider,
5697 )
5698 .unwrap_err();
5699 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5700 }
5701
5702 #[test]
5703 fn shielded_encrypted_notes_empty_version_on_request_version_none() {
5704 use platform::get_shielded_encrypted_notes_response::{
5705 get_shielded_encrypted_notes_response_v0::Result as V0Result,
5706 GetShieldedEncryptedNotesResponseV0, Version,
5707 };
5708 let response = platform::GetShieldedEncryptedNotesResponse {
5709 version: Some(Version::V0(GetShieldedEncryptedNotesResponseV0 {
5710 result: Some(V0Result::Proof(Proof::default())),
5711 metadata: Some(ResponseMetadata::default()),
5712 })),
5713 };
5714 let request = platform::GetShieldedEncryptedNotesRequest { version: None };
5715 let provider = unreachable_provider();
5716 let err = <ShieldedEncryptedNotes as FromProof<
5717 platform::GetShieldedEncryptedNotesRequest,
5718 >>::maybe_from_proof(
5719 request,
5720 response,
5721 Network::Testnet,
5722 default_platform_version(),
5723 &provider,
5724 )
5725 .unwrap_err();
5726 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5727 }
5728
5729 #[test]
5730 fn shielded_encrypted_notes_no_proof_when_response_empty() {
5731 let response = platform::GetShieldedEncryptedNotesResponse::default();
5732 let request = platform::GetShieldedEncryptedNotesRequest::default();
5733 let provider = unreachable_provider();
5734 let err = <ShieldedEncryptedNotes as FromProof<
5735 platform::GetShieldedEncryptedNotesRequest,
5736 >>::maybe_from_proof(
5737 request,
5738 response,
5739 Network::Testnet,
5740 default_platform_version(),
5741 &provider,
5742 )
5743 .unwrap_err();
5744 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5745 }
5746
5747 #[test]
5748 fn shielded_nullifiers_empty_version_on_request_version_none() {
5749 use platform::get_shielded_nullifiers_response::{
5750 get_shielded_nullifiers_response_v0::Result as V0Result,
5751 GetShieldedNullifiersResponseV0, Version,
5752 };
5753 let response = platform::GetShieldedNullifiersResponse {
5754 version: Some(Version::V0(GetShieldedNullifiersResponseV0 {
5755 result: Some(V0Result::Proof(Proof::default())),
5756 metadata: Some(ResponseMetadata::default()),
5757 })),
5758 };
5759 let request = platform::GetShieldedNullifiersRequest { version: None };
5760 let provider = unreachable_provider();
5761 let err = <ShieldedNullifierStatuses as FromProof<
5762 platform::GetShieldedNullifiersRequest,
5763 >>::maybe_from_proof(
5764 request,
5765 response,
5766 Network::Testnet,
5767 default_platform_version(),
5768 &provider,
5769 )
5770 .unwrap_err();
5771 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5772 }
5773
5774 #[test]
5775 fn recent_address_balance_changes_empty_version() {
5776 use platform::get_recent_address_balance_changes_response::{
5777 get_recent_address_balance_changes_response_v0::Result as V0Result,
5778 GetRecentAddressBalanceChangesResponseV0, Version,
5779 };
5780 let response = platform::GetRecentAddressBalanceChangesResponse {
5781 version: Some(Version::V0(GetRecentAddressBalanceChangesResponseV0 {
5782 result: Some(V0Result::Proof(Proof::default())),
5783 metadata: Some(ResponseMetadata::default()),
5784 })),
5785 };
5786 let request = platform::GetRecentAddressBalanceChangesRequest { version: None };
5787 let provider = unreachable_provider();
5788 let err = <RecentAddressBalanceChanges as FromProof<
5789 platform::GetRecentAddressBalanceChangesRequest,
5790 >>::maybe_from_proof(
5791 request,
5792 response,
5793 Network::Testnet,
5794 default_platform_version(),
5795 &provider,
5796 )
5797 .unwrap_err();
5798 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5799 }
5800
5801 #[test]
5802 fn recent_compacted_address_balance_changes_empty_version() {
5803 use platform::get_recent_compacted_address_balance_changes_response::{
5804 get_recent_compacted_address_balance_changes_response_v0::Result as V0Result,
5805 GetRecentCompactedAddressBalanceChangesResponseV0, Version,
5806 };
5807 let response = platform::GetRecentCompactedAddressBalanceChangesResponse {
5808 version: Some(Version::V0(
5809 GetRecentCompactedAddressBalanceChangesResponseV0 {
5810 result: Some(V0Result::Proof(Proof::default())),
5811 metadata: Some(ResponseMetadata::default()),
5812 },
5813 )),
5814 };
5815 let request = platform::GetRecentCompactedAddressBalanceChangesRequest { version: None };
5816 let provider = unreachable_provider();
5817 let err = <RecentCompactedAddressBalanceChanges as FromProof<
5818 platform::GetRecentCompactedAddressBalanceChangesRequest,
5819 >>::maybe_from_proof(
5820 request,
5821 response,
5822 Network::Testnet,
5823 default_platform_version(),
5824 &provider,
5825 )
5826 .unwrap_err();
5827 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5828 }
5829
5830 #[test]
5831 fn vote_identity_vote_rejects_bad_identity_id_length() {
5832 use dapi_grpc::platform::v0::get_contested_resource_identity_votes_request::GetContestedResourceIdentityVotesRequestV0;
5834 let request: platform::GetContestedResourceIdentityVotesRequest =
5835 GetContestedResourceIdentityVotesRequestV0 {
5836 identity_id: vec![0u8; 5], limit: None,
5838 offset: None,
5839 order_ascending: true,
5840 start_at_vote_poll_id_info: None,
5841 prove: true,
5842 }
5843 .into();
5844 let response = platform::GetContestedResourceIdentityVotesResponse::default();
5845 let provider = unreachable_provider();
5846 let err = <Vote as FromProof<
5847 platform::GetContestedResourceIdentityVotesRequest,
5848 >>::maybe_from_proof(
5849 request,
5850 response,
5851 Network::Testnet,
5852 default_platform_version(),
5853 &provider,
5854 )
5855 .unwrap_err();
5856 assert!(matches!(err, Error::RequestError { .. }), "got: {err:?}");
5857 }
5858
5859 #[test]
5860 fn vote_identity_vote_empty_version_on_request_none() {
5861 let request = platform::GetContestedResourceIdentityVotesRequest { version: None };
5862 let response = platform::GetContestedResourceIdentityVotesResponse::default();
5863 let provider = unreachable_provider();
5864 let err = <Vote as FromProof<
5865 platform::GetContestedResourceIdentityVotesRequest,
5866 >>::maybe_from_proof(
5867 request,
5868 response,
5869 Network::Testnet,
5870 default_platform_version(),
5871 &provider,
5872 )
5873 .unwrap_err();
5874 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5875 }
5876
5877 #[test]
5878 fn resource_votes_by_identity_empty_version_via_try_from_request() {
5879 let request = platform::GetContestedResourceIdentityVotesRequest { version: None };
5882 let response = platform::GetContestedResourceIdentityVotesResponse::default();
5883 let provider = unreachable_provider();
5884 let err = <ResourceVotesByIdentity as FromProof<
5885 platform::GetContestedResourceIdentityVotesRequest,
5886 >>::maybe_from_proof(
5887 request,
5888 response,
5889 Network::Testnet,
5890 default_platform_version(),
5891 &provider,
5892 )
5893 .unwrap_err();
5894 assert!(matches!(err, Error::EmptyVersion), "got: {err:?}");
5895 }
5896
5897 #[test]
5902 fn into_option_indexmap_empty_vs_with_entry_only_none() {
5903 use dpp::prelude::Identifier;
5904 let empty: RetrievedObjects<Identifier, u32> = RetrievedObjects::new();
5905 assert!(empty.into_option().is_none());
5906
5907 let mut map: RetrievedObjects<Identifier, u32> = RetrievedObjects::new();
5908 map.insert(Identifier::new([7u8; 32]), None);
5909 let mapped = map.into_option();
5910 assert!(
5911 mapped.is_some(),
5912 "absence markers must be preserved in into_option"
5913 );
5914 assert_eq!(mapped.unwrap().len(), 1);
5915 }
5916
5917 #[test]
5922 fn broadcast_state_transition_no_proof_when_response_empty() {
5923 let request = platform::BroadcastStateTransitionRequest {
5924 state_transition: vec![],
5925 };
5926 let response = platform::WaitForStateTransitionResultResponse::default();
5927 let provider = unreachable_provider();
5928 let err = <StateTransitionProofResult as FromProof<
5929 platform::BroadcastStateTransitionRequest,
5930 >>::maybe_from_proof(
5931 request,
5932 response,
5933 Network::Testnet,
5934 default_platform_version(),
5935 &provider,
5936 )
5937 .unwrap_err();
5938 assert!(matches!(err, Error::NoProofInResult), "got: {err:?}");
5939 }
5940
5941 #[test]
5942 fn broadcast_state_transition_protocol_error_fires_before_metadata_check() {
5943 use platform::wait_for_state_transition_result_response::{
5956 wait_for_state_transition_result_response_v0::Result as V0Result, Version,
5957 WaitForStateTransitionResultResponseV0,
5958 };
5959 let request = platform::BroadcastStateTransitionRequest {
5960 state_transition: vec![0xFFu8; 4],
5961 };
5962 let response = platform::WaitForStateTransitionResultResponse {
5963 version: Some(Version::V0(WaitForStateTransitionResultResponseV0 {
5964 result: Some(V0Result::Proof(Proof::default())),
5965 metadata: None, })),
5967 };
5968 let provider = unreachable_provider();
5969 let err = <StateTransitionProofResult as FromProof<
5970 platform::BroadcastStateTransitionRequest,
5971 >>::maybe_from_proof(
5972 request,
5973 response,
5974 Network::Testnet,
5975 default_platform_version(),
5976 &provider,
5977 )
5978 .unwrap_err();
5979 assert!(matches!(err, Error::ProtocolError { .. }), "got: {err:?}");
5980 }
5981}