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