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