diff --git a/packages/rs-drive-proof-verifier/src/lib.rs b/packages/rs-drive-proof-verifier/src/lib.rs index bf38d555ef7..7e28b6691fe 100644 --- a/packages/rs-drive-proof-verifier/src/lib.rs +++ b/packages/rs-drive-proof-verifier/src/lib.rs @@ -10,9 +10,9 @@ pub mod types; mod verify; pub use error::Error; pub use proof::{FromProof, Length}; -pub use provider::ContextProvider; #[cfg(feature = "mocks")] pub use provider::MockContextProvider; +pub use provider::{ContextProvider, DataContractProvider}; pub mod from_request; // Needed for #[derive(PlatformSerialize, PlatformDeserialize)] diff --git a/packages/rs-drive-proof-verifier/src/proof.rs b/packages/rs-drive-proof-verifier/src/proof.rs index bdd0a506149..fb4bfedfcad 100644 --- a/packages/rs-drive-proof-verifier/src/proof.rs +++ b/packages/rs-drive-proof-verifier/src/proof.rs @@ -1,4 +1,5 @@ use crate::from_request::TryFromRequest; +use crate::provider::DataContractProvider; use crate::{types, types::*, ContextProvider, Error}; use dapi_grpc::platform::v0::get_identities_contract_keys_request::GetIdentitiesContractKeysRequestV0; use dapi_grpc::platform::v0::get_path_elements_request::GetPathElementsRequestV0; @@ -46,11 +47,10 @@ use drive::query::contested_resource_votes_given_by_identity_query::ContestedRes use drive::query::vote_poll_contestant_votes_query::ContestedDocumentVotePollVotesDriveQuery; use drive::query::vote_poll_vote_state_query::ContestedDocumentVotePollDriveQuery; use drive::query::vote_polls_by_document_type_query::VotePollsByDocumentTypeQuery; -use drive::query::{ContractLookupFn, DriveQuery, VotePollsByEndDateDriveQuery}; +use drive::query::{DriveQuery, VotePollsByEndDateDriveQuery}; use std::array::TryFromSliceError; use std::collections::BTreeMap; use std::num::TryFromIntError; -use std::sync::Arc; use crate::verify::verify_tenderdash_proof; @@ -861,7 +861,7 @@ impl FromProof for StateTransitionPro epoch: (metadata.epoch as u16).try_into()?, }; - let contracts_provider_fn = known_contracts_provider_fn(provider); + let contracts_provider_fn = provider.as_contract_lookup_fn(); let (root_hash, result) = Drive::verify_state_transition_was_executed_with_proof( &state_transition, @@ -1271,8 +1271,8 @@ impl FromProof for ContestedResources { // Decode request to get drive query let drive_query = VotePollsByDocumentTypeQuery::try_from_request(request)?; - let resolved_request = drive_query - .resolve_with_known_contracts_provider(&known_contracts_provider_fn(provider))?; + let resolved_request = + drive_query.resolve_with_known_contracts_provider(&provider.as_contract_lookup_fn())?; // Parse response to read proof and metadata let proof = response.proof().or(Err(Error::NoProofInResult))?; @@ -1314,7 +1314,7 @@ impl FromProof for Contenders { let drive_query = ContestedDocumentVotePollDriveQuery::try_from_request(request)?; // Resolve request to get verify_*_proof - let contracts_provider = known_contracts_provider_fn(provider); + let contracts_provider = provider.as_contract_lookup_fn(); let resolved_request = drive_query.resolve_with_known_contracts_provider(&contracts_provider)?; @@ -1365,7 +1365,7 @@ impl FromProof for Voters { let drive_query = ContestedDocumentVotePollVotesDriveQuery::try_from_request(request)?; // Parse request to get resolved contract that implements verify_*_proof - let contracts_provider = known_contracts_provider_fn(provider); + let contracts_provider = provider.as_contract_lookup_fn(); let resolved_request = drive_query.resolve_with_known_contracts_provider(&contracts_provider)?; @@ -1414,7 +1414,7 @@ impl FromProof for ResourceV let proof = response.proof().or(Err(Error::NoProofInResult))?; let mtd = response.metadata().or(Err(Error::EmptyResponseMetadata))?; - let contract_provider_fn = known_contracts_provider_fn(provider); + let contract_provider_fn = provider.as_contract_lookup_fn(); let (root_hash, voters) = drive_query .verify_identity_votes_given_proof( &proof.grovedb_proof, @@ -1584,19 +1584,6 @@ fn u32_to_u16_opt(i: u32) -> Result, Error> { Ok(i) } -/// Returns function that uses [ContextProvider] to provide a [DataContract] to Drive proof verification functions -fn known_contracts_provider_fn<'a, P: ContextProvider + ?Sized + 'a>( - provider: &'a P, -) -> Box { - let f = |id: &Identifier| -> Result>, drive::error::Error> { - provider.get_data_contract(id).map_err(|e| { - drive::error::Error::Proof(ProofError::ErrorRetrievingContract(e.to_string())) - }) - }; - - Box::new(f) -} - /// Determine number of non-None elements pub trait Length { /// Return number of non-None elements in the data structure diff --git a/packages/rs-drive-proof-verifier/src/provider.rs b/packages/rs-drive-proof-verifier/src/provider.rs index 305154207e7..bc60cfed2b1 100644 --- a/packages/rs-drive-proof-verifier/src/provider.rs +++ b/packages/rs-drive-proof-verifier/src/provider.rs @@ -1,5 +1,6 @@ use crate::error::ContextProviderError; use dpp::prelude::{DataContract, Identifier}; +use drive::{error::proof::ProofError, query::ContractLookupFn}; #[cfg(feature = "mocks")] use hex::ToHex; use std::{io::ErrorKind, ops::Deref, sync::Arc}; @@ -95,6 +96,27 @@ where } } +/// A trait that provides a function that can be used to look up a [DataContract] by its [Identifier]. +/// +/// This trait is automatically implemented for any type that implements [ContextProvider]. +/// It is used internally by the Drive proof verification functions to look up data contracts. +pub trait DataContractProvider: Send + Sync { + /// Returns [ContractLookupFn] function that can be used to look up a [DataContract] by its [Identifier]. + fn as_contract_lookup_fn(&self) -> Box; +} +impl DataContractProvider for C { + /// Returns function that uses [ContextProvider] to provide a [DataContract] to Drive proof verification functions + fn as_contract_lookup_fn(&self) -> Box { + let f = |id: &Identifier| -> Result>, drive::error::Error> { + self.get_data_contract(id).map_err(|e| { + drive::error::Error::Proof(ProofError::ErrorRetrievingContract(e.to_string())) + }) + }; + + Box::new(f) + } +} + /// Mock ContextProvider that can read quorum keys from files. /// /// Use [dash_sdk::SdkBuilder::with_dump_dir()] to generate quorum keys files. diff --git a/packages/rs-drive/src/drive/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs b/packages/rs-drive/src/drive/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs index f9e9d18ded4..7e904267e64 100644 --- a/packages/rs-drive/src/drive/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs +++ b/packages/rs-drive/src/drive/verify/state_transition/verify_state_transition_was_executed_with_proof/v0/mod.rs @@ -114,11 +114,12 @@ impl Drive { let document_type = contract .document_type_for_name(transition.document_type_name()) - .map_err(|_| { + .map_err(|e| { Error::Proof(ProofError::UnknownContract(format!( - "unknown contract document {} with id {}", + "cannot fetch contract for document {} with id {}: {}", transition.document_type_name(), - transition.data_contract_id() + transition.data_contract_id(), + e ))) })?; diff --git a/packages/rs-sdk/src/platform/transition/broadcast.rs b/packages/rs-sdk/src/platform/transition/broadcast.rs index b8c0089d3f9..5c050ce8cff 100644 --- a/packages/rs-sdk/src/platform/transition/broadcast.rs +++ b/packages/rs-sdk/src/platform/transition/broadcast.rs @@ -5,6 +5,8 @@ use dapi_grpc::platform::VersionedGrpcResponse; use dpp::state_transition::proof_result::StateTransitionProofResult; use dpp::state_transition::StateTransition; use drive::drive::Drive; +use drive_proof_verifier::error::ContextProviderError; +use drive_proof_verifier::DataContractProvider; use rs_dapi_client::{DapiRequest, RequestSettings}; #[async_trait::async_trait] @@ -47,12 +49,17 @@ impl BroadcastStateTransition for StateTransition { let block_info = block_info_from_metadata(response.metadata()?)?; let proof = response.proof_owned()?; + let context_provider = + sdk.context_provider() + .ok_or(Error::from(ContextProviderError::Config( + "Context provider not initialized".to_string(), + )))?; let (_, result) = Drive::verify_state_transition_was_executed_with_proof( self, &block_info, proof.grovedb_proof.as_slice(), - &|_| Ok(None), + &context_provider.as_contract_lookup_fn(), sdk.version(), )?; diff --git a/packages/rs-sdk/src/platform/transition/put_contract.rs b/packages/rs-sdk/src/platform/transition/put_contract.rs index 79d8e87d5ac..fb7e55b5bc0 100644 --- a/packages/rs-sdk/src/platform/transition/put_contract.rs +++ b/packages/rs-sdk/src/platform/transition/put_contract.rs @@ -16,6 +16,8 @@ use dpp::state_transition::data_contract_create_transition::DataContractCreateTr use dpp::state_transition::proof_result::StateTransitionProofResult; use dpp::state_transition::StateTransition; use drive::drive::Drive; +use drive_proof_verifier::error::ContextProviderError; +use drive_proof_verifier::DataContractProvider; use rs_dapi_client::{DapiRequest, RequestSettings}; #[async_trait::async_trait] @@ -103,12 +105,17 @@ impl PutContract for DataContract { let block_info = block_info_from_metadata(response.metadata()?)?; let proof = response.proof_owned()?; + let context_provider = + sdk.context_provider() + .ok_or(Error::from(ContextProviderError::Config( + "Context provider not initialized".to_string(), + )))?; let (_, result) = Drive::verify_state_transition_was_executed_with_proof( &state_transition, &block_info, proof.grovedb_proof.as_slice(), - &|_| Ok(None), + &context_provider.as_contract_lookup_fn(), sdk.version(), )?; diff --git a/packages/rs-sdk/src/platform/transition/put_identity.rs b/packages/rs-sdk/src/platform/transition/put_identity.rs index 6e4283c26a4..59422aa6b2b 100644 --- a/packages/rs-sdk/src/platform/transition/put_identity.rs +++ b/packages/rs-sdk/src/platform/transition/put_identity.rs @@ -8,6 +8,8 @@ use dapi_grpc::tonic::Code; use dpp::dashcore::PrivateKey; use dpp::identity::signer::Signer; use dpp::prelude::{AssetLockProof, Identity}; +use drive_proof_verifier::error::ContextProviderError; +use drive_proof_verifier::DataContractProvider; use crate::platform::block_info_from_metadata::block_info_from_metadata; use dpp::state_transition::proof_result::StateTransitionProofResult; @@ -103,12 +105,17 @@ impl PutIdentity for Identity { let block_info = block_info_from_metadata(response.metadata()?)?; let proof = response.proof_owned()?; + let context_provider = + sdk.context_provider() + .ok_or(Error::from(ContextProviderError::Config( + "Context provider not initialized".to_string(), + )))?; let (_, result) = Drive::verify_state_transition_was_executed_with_proof( &state_transition, &block_info, proof.grovedb_proof.as_slice(), - &|_| Ok(None), + &context_provider.as_contract_lookup_fn(), sdk.version(), )?; diff --git a/packages/rs-sdk/src/platform/transition/top_up_identity.rs b/packages/rs-sdk/src/platform/transition/top_up_identity.rs index 59b776df4a0..48145234f49 100644 --- a/packages/rs-sdk/src/platform/transition/top_up_identity.rs +++ b/packages/rs-sdk/src/platform/transition/top_up_identity.rs @@ -9,6 +9,8 @@ use dpp::state_transition::identity_topup_transition::methods::IdentityTopUpTran use dpp::state_transition::identity_topup_transition::IdentityTopUpTransition; use dpp::state_transition::proof_result::StateTransitionProofResult; use drive::drive::Drive; +use drive_proof_verifier::error::ContextProviderError; +use drive_proof_verifier::DataContractProvider; use rs_dapi_client::{DapiRequest, RequestSettings}; #[async_trait::async_trait] @@ -54,12 +56,17 @@ impl TopUpIdentity for Identity { let block_info = block_info_from_metadata(response.metadata()?)?; let proof = response.proof_owned()?; + let context_provider = + sdk.context_provider() + .ok_or(Error::from(ContextProviderError::Config( + "Context provider not initialized".to_string(), + )))?; let (_, result) = Drive::verify_state_transition_was_executed_with_proof( &state_transition, &block_info, proof.grovedb_proof.as_slice(), - &|_| Ok(None), + &context_provider.as_contract_lookup_fn(), sdk.version(), )?; diff --git a/packages/rs-sdk/src/platform/transition/vote.rs b/packages/rs-sdk/src/platform/transition/vote.rs index 505109f4fc4..f03e0a1f692 100644 --- a/packages/rs-sdk/src/platform/transition/vote.rs +++ b/packages/rs-sdk/src/platform/transition/vote.rs @@ -14,6 +14,7 @@ use dpp::state_transition::proof_result::StateTransitionProofResult; use dpp::voting::votes::resource_vote::accessors::v0::ResourceVoteGettersV0; use dpp::voting::votes::Vote; use drive::drive::Drive; +use drive_proof_verifier::{error::ContextProviderError, DataContractProvider}; use rs_dapi_client::DapiRequest; #[async_trait::async_trait] @@ -122,12 +123,17 @@ impl PutVote for Vote { let block_info = block_info_from_metadata(response.metadata()?)?; let proof = response.proof_owned()?; + let context_provider = + sdk.context_provider() + .ok_or(Error::from(ContextProviderError::Config( + "Context provider not initialized".to_string(), + )))?; let (_, result) = Drive::verify_state_transition_was_executed_with_proof( &masternode_vote_transition, &block_info, proof.grovedb_proof.as_slice(), - &|_| Ok(None), + &context_provider.as_contract_lookup_fn(), sdk.version(), )?; diff --git a/packages/rs-sdk/src/platform/transition/withdraw_from_identity.rs b/packages/rs-sdk/src/platform/transition/withdraw_from_identity.rs index 5e64ed1afb9..8e9020a5f3d 100644 --- a/packages/rs-sdk/src/platform/transition/withdraw_from_identity.rs +++ b/packages/rs-sdk/src/platform/transition/withdraw_from_identity.rs @@ -8,6 +8,8 @@ use dpp::identity::Identity; use dpp::prelude::UserFeeIncrease; use dpp::state_transition::identity_credit_withdrawal_transition::IdentityCreditWithdrawalTransition; +use drive_proof_verifier::error::ContextProviderError; +use drive_proof_verifier::DataContractProvider; use crate::platform::block_info_from_metadata::block_info_from_metadata; use crate::platform::transition::broadcast_request::BroadcastRequestForStateTransition; @@ -74,12 +76,17 @@ impl WithdrawFromIdentity for Identity { let block_info = block_info_from_metadata(response.metadata()?)?; let proof = response.proof_owned()?; + let context_provider = + sdk.context_provider() + .ok_or(Error::from(ContextProviderError::Config( + "Context provider not initialized".to_string(), + )))?; let (_, result) = Drive::verify_state_transition_was_executed_with_proof( &state_transition, &block_info, proof.grovedb_proof.as_slice(), - &|_| Ok(None), + &context_provider.as_contract_lookup_fn(), sdk.version(), )?; diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 3976ee7c544..50558b2c151 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -212,6 +212,9 @@ impl Sdk { } } } + pub fn context_provider(&self) -> Option { + self.context_provider.as_ref().map(Arc::clone) + } /// Returns a mutable reference to the `MockDashPlatformSdk` instance. ///