From b3f5f17d7c7a85ecf075b13a220ad084dda3648e Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 25 Jul 2024 13:13:11 +0200 Subject: [PATCH 01/14] feat(sdk): asset lock quorum verify against platform --- packages/rs-sdk/src/error.rs | 8 ++ .../src/platform/transition/put_identity.rs | 78 +++++++++++++++++-- 2 files changed, 80 insertions(+), 6 deletions(-) diff --git a/packages/rs-sdk/src/error.rs b/packages/rs-sdk/src/error.rs index 0a5024f541..892824e533 100644 --- a/packages/rs-sdk/src/error.rs +++ b/packages/rs-sdk/src/error.rs @@ -49,6 +49,14 @@ pub enum Error { /// Epoch not found; we must have at least one epoch #[error("No epoch found on the Platform; it should never happen")] EpochNotFound, + /// Quorum not found; try again later + #[error("Quorum {quorum_hash_hex} of type {quorum_type} not yet available on the platform at height {core_chain_locked_height}: {e}; try again later")] + QuorumNotFound { + quorum_hash_hex: String, + quorum_type: u32, + core_chain_locked_height: u32, + e: ContextProviderError, + }, /// SDK operation timeout reached error #[error("SDK operation timeout {} secs reached: {1}", .0.as_secs())] TimeoutReached(Duration, String), diff --git a/packages/rs-sdk/src/platform/transition/put_identity.rs b/packages/rs-sdk/src/platform/transition/put_identity.rs index 59422aa6b2..d4bb8b946c 100644 --- a/packages/rs-sdk/src/platform/transition/put_identity.rs +++ b/packages/rs-sdk/src/platform/transition/put_identity.rs @@ -1,20 +1,21 @@ +use crate::platform::block_info_from_metadata::block_info_from_metadata; use crate::platform::transition::broadcast_identity::BroadcastRequestForNewIdentity; use crate::platform::transition::broadcast_request::BroadcastRequestForStateTransition; use crate::platform::Fetch; use crate::{Error, Sdk}; - +use dapi_grpc::platform::v0::get_epochs_info_request::{self, GetEpochsInfoRequestV0}; +use dapi_grpc::platform::v0::GetEpochsInfoRequest; use dapi_grpc::platform::VersionedGrpcResponse; use dapi_grpc::tonic::Code; +use dpp::dashcore::hashes::Hash; 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; use drive::drive::Drive; -use rs_dapi_client::{DapiClientError, DapiRequest, RequestSettings}; +use drive_proof_verifier::error::ContextProviderError; +use drive_proof_verifier::{ContextProvider, DataContractProvider}; +use rs_dapi_client::{DapiClientError, DapiRequest, DapiRequestExecutor, RequestSettings}; #[async_trait::async_trait] /// A trait for putting an identity to platform @@ -37,6 +38,71 @@ pub trait PutIdentity { ) -> Result; } +#[async_trait::async_trait] +pub trait AssetLockProofVerifier { + /// Verifies the asset lock proof against the platform + async fn verify(&self, sdk: &Sdk) -> Result<(), Error>; +} + +#[async_trait::async_trait] +impl AssetLockProofVerifier for AssetLockProof { + async fn verify(&self, sdk: &Sdk) -> Result<(), Error> { + let context_provider = sdk + .context_provider() + .ok_or(Error::Config("Context Provider not configured".to_string()))?; + + // Check status of Platform first + // TODO: implement some caching mechanism to avoid fetching the same data multiple times + let request = GetEpochsInfoRequest { + version: Some(get_epochs_info_request::Version::V0( + GetEpochsInfoRequestV0 { + ascending: false, + count: 1, + prove: true, + start_epoch: None, + }, + )), + }; + let response = sdk.execute(request, RequestSettings::default()).await?; + + let platform_core_chain_locked_height = response.metadata()?.core_chain_locked_height; + let proof = response.proof_owned()?; + let platform_quorum_hash = proof.quorum_hash.try_into().map_err(|e: Vec| { + Error::Protocol(dpp::ProtocolError::DecodingError(format!( + "Invalid quorum hash size {}, expected 32 bytes", + e.len() + ))) + })?; + + let platform_quorum_type = proof.quorum_type; + + let (quorum_hash, core_chain_locked_height) = match self { + AssetLockProof::Chain(v) => (platform_quorum_hash, v.core_chain_locked_height), + AssetLockProof::Instant(v) => ( + v.instant_lock().cyclehash.to_raw_hash().to_byte_array(), + platform_core_chain_locked_height, + ), + }; + + // Try to fetch the quorum public key; if it fails, the + let result = context_provider.get_quorum_public_key( + platform_quorum_type, + quorum_hash, + core_chain_locked_height, + ); + + match result { + Err(ContextProviderError::InvalidQuorum(s)) => Err(Error::QuorumNotFound { + e: ContextProviderError::InvalidQuorum(s), + quorum_hash_hex: hex::encode(quorum_hash), + quorum_type: platform_quorum_type, + core_chain_locked_height, + }), + Err(e) => Err(e.into()), + Ok(_) => Ok(()), + } + } +} #[async_trait::async_trait] impl PutIdentity for Identity { async fn put_to_platform( From 9de013ff1cad59424c6fba628f6611a01abf855c Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 15 Aug 2024 08:40:49 +0200 Subject: [PATCH 02/14] feat(sdk)!: params of dash networks - testnet, mainnet, etc --- packages/rs-sdk/src/lib.rs | 1 + packages/rs-sdk/src/networks.rs | 80 +++++++++++++++++++++++++++++++++ packages/rs-sdk/src/sdk.rs | 18 ++++++++ 3 files changed, 99 insertions(+) create mode 100644 packages/rs-sdk/src/networks.rs diff --git a/packages/rs-sdk/src/lib.rs b/packages/rs-sdk/src/lib.rs index 14b65a58c2..49648e453e 100644 --- a/packages/rs-sdk/src/lib.rs +++ b/packages/rs-sdk/src/lib.rs @@ -67,6 +67,7 @@ mod core_client; pub mod error; mod internal_cache; pub mod mock; +pub mod networks; pub mod platform; pub mod sdk; diff --git a/packages/rs-sdk/src/networks.rs b/packages/rs-sdk/src/networks.rs new file mode 100644 index 0000000000..8920b0ead1 --- /dev/null +++ b/packages/rs-sdk/src/networks.rs @@ -0,0 +1,80 @@ +//! Configuration of dash networks (devnet, testnet, mainnet, etc.). + +/* +Mainnet: + consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_400_60; + consensus.llmqTypeDIP0024InstantSend = Consensus::LLMQType::LLMQ_60_75; + consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_100_67; + consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_400_85; + +Testnet: + consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_50_60; + consensus.llmqTypeDIP0024InstantSend = Consensus::LLMQType::LLMQ_60_75; + consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_25_67; + consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_50_60; + +Devnet: + consensus.llmqTypeChainLocks = Consensus::LLMQType::LLMQ_DEVNET; + consensus.llmqTypeDIP0024InstantSend = Consensus::LLMQType::LLMQ_DEVNET_DIP0024; + consensus.llmqTypePlatform = Consensus::LLMQType::LLMQ_DEVNET_PLATFORM; + consensus.llmqTypeMnhf = Consensus::LLMQType::LLMQ_DEVNET; + +*/ + +use dashcore_rpc::json::QuorumType; + +pub enum NetworkType { + Mainnet, + Testnet, + Devnet, + Mock, + Custom(NetworkConfig), +} + +impl NetworkType { + pub fn instant_lock_quorum_type(&self) -> QuorumType { + self.to_network_config().instant_lock + } + + fn to_network_config(&self) -> NetworkConfig { + match self { + NetworkType::Mainnet => NetworkConfig::new_mainnet(), + NetworkType::Testnet => NetworkConfig::new_testnet(), + NetworkType::Devnet => NetworkConfig::new_devnet(), + NetworkType::Mock => NetworkConfig::new_mock(), + NetworkType::Custom(config) => config.clone(), + } + } +} + +/// Configuration of Dash Core Quorums. +/// +/// In most cases, you should use the [`new_mainnet`] or [`new_testnet`] functions to create a new instance. +#[derive(Clone, Debug)] +pub struct NetworkConfig { + pub instant_lock: QuorumType, +} + +impl NetworkConfig { + pub fn new_mainnet() -> Self { + NetworkConfig { + instant_lock: QuorumType::Llmq400_60, + } + } + + pub fn new_testnet() -> Self { + NetworkConfig { + instant_lock: QuorumType::Llmq50_60, + } + } + + pub fn new_devnet() -> Self { + NetworkConfig { + instant_lock: QuorumType::LlmqDevnet, + } + } + + pub fn new_mock() -> Self { + Self::new_devnet() + } +} diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 96b0e23729..67ab4070c7 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -5,6 +5,7 @@ use crate::internal_cache::InternalSdkCache; use crate::mock::MockResponse; #[cfg(feature = "mocks")] use crate::mock::{provider::GrpcContextProvider, MockDashPlatformSdk}; +use crate::networks::NetworkType; use crate::platform::transition::put_settings::PutSettings; use crate::platform::{Fetch, Identifier}; use dapi_grpc::mock::Mockable; @@ -512,6 +513,8 @@ pub struct SdkBuilder { core_user: String, core_password: String, + network_type: NetworkType, + /// If true, request and verify proofs of the responses. proofs: bool, @@ -547,6 +550,7 @@ impl Default for SdkBuilder { core_port: 0, core_password: "".to_string(), core_user: "".to_string(), + network_type: NetworkType::Mock, proofs: true, @@ -571,11 +575,16 @@ impl Default for SdkBuilder { impl SdkBuilder { /// Create a new SdkBuilder with provided address list. + /// + /// It creates new SdkBuilder, preconfigured to connect to provided addresses on the [NetworkType::Testnet]. + /// + /// You can change this using [`SdkBuilder::with_network_type()`]. pub fn new(addresses: AddressList) -> Self { Self { addresses: Some(addresses), ..Default::default() } + .with_network_type(NetworkType::Testnet) } /// Create a new SdkBuilder that will generate mock client. @@ -649,6 +658,15 @@ impl SdkBuilder { self } + /// Define network to which you want to connect. + /// + /// For development, you can use [NetworkType::Testnet] or [NetworkType::Devnet]. + /// For production, use [NetworkType::Mainnet]. + pub fn with_network_type(mut self, network_type: NetworkType) -> Self { + self.network_type = network_type; + self + } + /// Use Dash Core as a wallet and context provider. /// /// This is a convenience method that configures the SDK to use Dash Core as a wallet and context provider. From 6362883a6b7233b7db3488ff7f1ab42e51ef9c42 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:00:43 +0200 Subject: [PATCH 03/14] feat(sdk): network type, continued --- packages/rs-sdk/src/networks.rs | 46 ++++++++++++++++++++------------- packages/rs-sdk/src/sdk.rs | 30 ++++++++++++++++----- 2 files changed, 51 insertions(+), 25 deletions(-) diff --git a/packages/rs-sdk/src/networks.rs b/packages/rs-sdk/src/networks.rs index 8920b0ead1..a2841df6da 100644 --- a/packages/rs-sdk/src/networks.rs +++ b/packages/rs-sdk/src/networks.rs @@ -1,4 +1,7 @@ //! Configuration of dash networks (devnet, testnet, mainnet, etc.). +//! +//! See also: +//! * https://github.com/dashpay/dash/blob/develop/src/chainparams.cpp /* Mainnet: @@ -23,26 +26,33 @@ Devnet: use dashcore_rpc::json::QuorumType; +/// Dash network types. +#[derive(Eq, PartialEq, Clone, Debug)] pub enum NetworkType { + /// Mock implementation; in practice, feaults to Devnet config for Mock mode. Errors when used in non-mock mode. + Mock, + /// Mainnet network, used for production. Mainnet, + /// Testnet network, used for testing and development. Testnet, + /// Devnet network, used local for development. Devnet, - Mock, - Custom(NetworkConfig), + /// Custom network configuration. + Custom(QuorumParams), } impl NetworkType { pub fn instant_lock_quorum_type(&self) -> QuorumType { - self.to_network_config().instant_lock + self.to_quorum_params().instant_lock_quorum_type } - fn to_network_config(&self) -> NetworkConfig { + pub(crate) fn to_quorum_params(&self) -> QuorumParams { match self { - NetworkType::Mainnet => NetworkConfig::new_mainnet(), - NetworkType::Testnet => NetworkConfig::new_testnet(), - NetworkType::Devnet => NetworkConfig::new_devnet(), - NetworkType::Mock => NetworkConfig::new_mock(), + NetworkType::Mainnet => QuorumParams::new_mainnet(), + NetworkType::Testnet => QuorumParams::new_testnet(), + NetworkType::Devnet => QuorumParams::new_devnet(), NetworkType::Custom(config) => config.clone(), + NetworkType::Mock => QuorumParams::new_mock(), } } } @@ -50,27 +60,27 @@ impl NetworkType { /// Configuration of Dash Core Quorums. /// /// In most cases, you should use the [`new_mainnet`] or [`new_testnet`] functions to create a new instance. -#[derive(Clone, Debug)] -pub struct NetworkConfig { - pub instant_lock: QuorumType, +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct QuorumParams { + pub instant_lock_quorum_type: QuorumType, } -impl NetworkConfig { +impl QuorumParams { pub fn new_mainnet() -> Self { - NetworkConfig { - instant_lock: QuorumType::Llmq400_60, + QuorumParams { + instant_lock_quorum_type: QuorumType::Llmq400_60, } } pub fn new_testnet() -> Self { - NetworkConfig { - instant_lock: QuorumType::Llmq50_60, + QuorumParams { + instant_lock_quorum_type: QuorumType::Llmq50_60, } } pub fn new_devnet() -> Self { - NetworkConfig { - instant_lock: QuorumType::LlmqDevnet, + QuorumParams { + instant_lock_quorum_type: QuorumType::LlmqDevnet, } } diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 67ab4070c7..be799b6547 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -5,7 +5,7 @@ use crate::internal_cache::InternalSdkCache; use crate::mock::MockResponse; #[cfg(feature = "mocks")] use crate::mock::{provider::GrpcContextProvider, MockDashPlatformSdk}; -use crate::networks::NetworkType; +use crate::networks::{NetworkType, QuorumParams}; use crate::platform::transition::put_settings::PutSettings; use crate::platform::{Fetch, Identifier}; use dapi_grpc::mock::Mockable; @@ -79,6 +79,8 @@ pub type LastQueryTimestamp = u64; #[derive(Clone)] pub struct Sdk { inner: SdkInstance, + /// Type of network we use. Determines some parameters, like quorum types. + network_type: NetworkType, /// Use proofs when retrieving data from the platform. /// /// This is set to `true` by default. `false` is not implemented yet. @@ -420,6 +422,12 @@ impl Sdk { } } + + /// Return configuration of quorum, like type of quorum used for instant lock. + pub(crate) fn quorum_params(&self) -> QuorumParams { + self.network_type.to_quorum_params() + } + /// Return [Dash Platform version](PlatformVersion) information used by this SDK. /// /// @@ -499,8 +507,9 @@ impl DapiRequestExecutor for &Sdk { /// Mandatory steps of initialization in normal mode are: /// /// 1. Create an instance of [SdkBuilder] with [`SdkBuilder::new()`] -/// 2. Configure the builder with [`SdkBuilder::with_core()`] -/// 3. Call [`SdkBuilder::build()`] to create the [Sdk] instance. +/// 2. Set up network type with [`SdkBuilder::with_network_type()`] (not needed for mock) +/// 3. Configure the builder with [`SdkBuilder::with_core()`] +/// 4. Call [`SdkBuilder::build()`] to create the [Sdk] instance. pub struct SdkBuilder { /// List of addressses to connect to. /// @@ -576,15 +585,14 @@ impl Default for SdkBuilder { impl SdkBuilder { /// Create a new SdkBuilder with provided address list. /// - /// It creates new SdkBuilder, preconfigured to connect to provided addresses on the [NetworkType::Testnet]. + /// It creates new SdkBuilder, preconfigured to connect to provided addresses. /// - /// You can change this using [`SdkBuilder::with_network_type()`]. + /// Once created, you need to set [NetworkType] with [`SdkBuilder::with_network_type()`]. pub fn new(addresses: AddressList) -> Self { Self { addresses: Some(addresses), ..Default::default() } - .with_network_type(NetworkType::Testnet) } /// Create a new SdkBuilder that will generate mock client. @@ -714,6 +722,12 @@ impl SdkBuilder { let sdk= match self.addresses { // non-mock mode Some(addresses) => { + if self.network_type == NetworkType::Mock { + return Err(Error::Config( + "Network type must be set, use SdkBuilder::with_network_type()".to_string(), + )); + } + let dapi = DapiClient::new(addresses, self.settings); #[cfg(feature = "mocks")] let dapi = dapi.dump_dir(self.dump_dir.clone()); @@ -721,6 +735,7 @@ impl SdkBuilder { #[allow(unused_mut)] // needs to be mutable for #[cfg(feature = "mocks")] let mut sdk= Sdk{ inner:SdkInstance::Dapi { dapi, version:self.version }, + network_type: self.network_type, proofs:self.proofs, context_provider: self.context_provider.map(Arc::new), cancel_token: self.cancel_token, @@ -770,7 +785,8 @@ impl SdkBuilder { mock:Arc::new(Mutex::new( MockDashPlatformSdk::new(self.version, Arc::clone(&dapi), self.proofs))), dapi, version:self.version, - }, + }, + network_type: self.network_type, dump_dir: self.dump_dir, proofs:self.proofs, internal_cache: Default::default(), From f984ced097f1f1479c2a277569a29f496a8bfa52 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:01:14 +0200 Subject: [PATCH 04/14] feat: asset lock verify --- packages/rs-sdk/src/error.rs | 14 +++- packages/rs-sdk/src/platform/transition.rs | 1 + .../src/platform/transition/asset_lock.rs | 82 +++++++++++++++++++ .../src/platform/transition/put_identity.rs | 72 +--------------- 4 files changed, 98 insertions(+), 71 deletions(-) create mode 100644 packages/rs-sdk/src/platform/transition/asset_lock.rs diff --git a/packages/rs-sdk/src/error.rs b/packages/rs-sdk/src/error.rs index 892824e533..0d87db421b 100644 --- a/packages/rs-sdk/src/error.rs +++ b/packages/rs-sdk/src/error.rs @@ -50,13 +50,25 @@ pub enum Error { #[error("No epoch found on the Platform; it should never happen")] EpochNotFound, /// Quorum not found; try again later - #[error("Quorum {quorum_hash_hex} of type {quorum_type} not yet available on the platform at height {core_chain_locked_height}: {e}; try again later")] + #[error( + "Quorum {quorum_hash_hex} of type {quorum_type} at height {core_chain_locked_height}: {e}" + )] QuorumNotFound { quorum_hash_hex: String, quorum_type: u32, core_chain_locked_height: u32, e: ContextProviderError, }, + + /// Asset lock not found; try again later. + /// + /// ## Parameters + /// + /// - 0 - core locked height in asset lock + /// - 1 - current core locked height on the platform + #[error("Asset lock for core locked height {0} not available yet, max avaiable locked core height is {1}; try again later")] + CoreLockedHeightNotYetAvailable(u32, u32), + /// SDK operation timeout reached error #[error("SDK operation timeout {} secs reached: {1}", .0.as_secs())] TimeoutReached(Duration, String), diff --git a/packages/rs-sdk/src/platform/transition.rs b/packages/rs-sdk/src/platform/transition.rs index 490bc40090..31dfe04858 100644 --- a/packages/rs-sdk/src/platform/transition.rs +++ b/packages/rs-sdk/src/platform/transition.rs @@ -1,4 +1,5 @@ //! State transitions used to put changed objects to the Dash Platform. +pub mod asset_lock; pub mod broadcast; pub(crate) mod broadcast_identity; pub mod broadcast_request; diff --git a/packages/rs-sdk/src/platform/transition/asset_lock.rs b/packages/rs-sdk/src/platform/transition/asset_lock.rs new file mode 100644 index 0000000000..c09b5d91c2 --- /dev/null +++ b/packages/rs-sdk/src/platform/transition/asset_lock.rs @@ -0,0 +1,82 @@ +//! [AssetLockProof] utilities + +use crate::{Error, Sdk}; +use dapi_grpc::platform::v0::get_epochs_info_request::{self, GetEpochsInfoRequestV0}; +use dapi_grpc::platform::v0::GetEpochsInfoRequest; +use dapi_grpc::platform::VersionedGrpcResponse; +use dpp::dashcore::hashes::Hash; +use dpp::prelude::AssetLockProof; +use drive_proof_verifier::error::ContextProviderError; +use drive_proof_verifier::ContextProvider; +use rs_dapi_client::{DapiRequestExecutor, RequestSettings}; +#[async_trait::async_trait] +pub trait AssetLockProofVerifier { + /// Verifies the asset lock proof against the platform. + /// + /// This function will return an error if the proof is not yet available on the platform. + /// + /// # Errors + /// + /// - [Error::CoreLockedHeightNotYetAvailable] if the core locked height in the proof is higher than the + /// current core locked height on the platform. Try again later. + /// - [Error::QuorumNotFound] if the quorum public key is not yet available on the platform, what implies that + /// the quorum is not (yet) available. Try again later. + /// - other errors when something goes wrong. + async fn verify(&self, sdk: &Sdk) -> Result<(), Error>; +} + +#[async_trait::async_trait] +impl AssetLockProofVerifier for AssetLockProof { + async fn verify(&self, sdk: &Sdk) -> Result<(), Error> { + let context_provider = sdk + .context_provider() + .ok_or(Error::Config("Context Provider not configured".to_string()))?; + + // Retrieve current core chain lock info from the platform + // TODO: implement some caching mechanism to avoid fetching the same data multiple times + let request = GetEpochsInfoRequest { + version: Some(get_epochs_info_request::Version::V0( + GetEpochsInfoRequestV0 { + ascending: false, + count: 1, + prove: true, + start_epoch: None, + }, + )), + }; + let response = sdk.execute(request, RequestSettings::default()).await?; + let platform_core_chain_locked_height = response.metadata()?.core_chain_locked_height; + + match self { + AssetLockProof::Chain(asset_lock) => { + if asset_lock.core_chain_locked_height > platform_core_chain_locked_height { + Err(Error::CoreLockedHeightNotYetAvailable( + asset_lock.core_chain_locked_height, + platform_core_chain_locked_height, + )) + } else { + Ok(()) + } + } + AssetLockProof::Instant(v) => { + let quorum_hash = v.instant_lock().cyclehash.to_raw_hash().to_byte_array(); + let quorum_type = sdk.quorum_params().instant_lock_quorum_type; + // Try to fetch the quorum public key; if it fails, we assume platform does not have this quorum yet + match context_provider.get_quorum_public_key( + quorum_type as u32, + quorum_hash, + platform_core_chain_locked_height, + ) { + Err(ContextProviderError::InvalidQuorum(s)) => Err(Error::QuorumNotFound { + e: ContextProviderError::InvalidQuorum(s), + quorum_hash_hex: hex::encode(quorum_hash), + quorum_type: quorum_type as u32, + core_chain_locked_height: platform_core_chain_locked_height, + }), + Err(e) => Err(e.into()), + Ok(_) => Ok(()), + } + } + } + } +} diff --git a/packages/rs-sdk/src/platform/transition/put_identity.rs b/packages/rs-sdk/src/platform/transition/put_identity.rs index d4bb8b946c..f062f4bc76 100644 --- a/packages/rs-sdk/src/platform/transition/put_identity.rs +++ b/packages/rs-sdk/src/platform/transition/put_identity.rs @@ -3,19 +3,16 @@ use crate::platform::transition::broadcast_identity::BroadcastRequestForNewIdent use crate::platform::transition::broadcast_request::BroadcastRequestForStateTransition; use crate::platform::Fetch; use crate::{Error, Sdk}; -use dapi_grpc::platform::v0::get_epochs_info_request::{self, GetEpochsInfoRequestV0}; -use dapi_grpc::platform::v0::GetEpochsInfoRequest; use dapi_grpc::platform::VersionedGrpcResponse; use dapi_grpc::tonic::Code; -use dpp::dashcore::hashes::Hash; use dpp::dashcore::PrivateKey; use dpp::identity::signer::Signer; use dpp::prelude::{AssetLockProof, Identity}; use dpp::state_transition::proof_result::StateTransitionProofResult; use drive::drive::Drive; use drive_proof_verifier::error::ContextProviderError; -use drive_proof_verifier::{ContextProvider, DataContractProvider}; -use rs_dapi_client::{DapiClientError, DapiRequest, DapiRequestExecutor, RequestSettings}; +use drive_proof_verifier::DataContractProvider; +use rs_dapi_client::{DapiClientError, DapiRequest, RequestSettings}; #[async_trait::async_trait] /// A trait for putting an identity to platform @@ -38,71 +35,6 @@ pub trait PutIdentity { ) -> Result; } -#[async_trait::async_trait] -pub trait AssetLockProofVerifier { - /// Verifies the asset lock proof against the platform - async fn verify(&self, sdk: &Sdk) -> Result<(), Error>; -} - -#[async_trait::async_trait] -impl AssetLockProofVerifier for AssetLockProof { - async fn verify(&self, sdk: &Sdk) -> Result<(), Error> { - let context_provider = sdk - .context_provider() - .ok_or(Error::Config("Context Provider not configured".to_string()))?; - - // Check status of Platform first - // TODO: implement some caching mechanism to avoid fetching the same data multiple times - let request = GetEpochsInfoRequest { - version: Some(get_epochs_info_request::Version::V0( - GetEpochsInfoRequestV0 { - ascending: false, - count: 1, - prove: true, - start_epoch: None, - }, - )), - }; - let response = sdk.execute(request, RequestSettings::default()).await?; - - let platform_core_chain_locked_height = response.metadata()?.core_chain_locked_height; - let proof = response.proof_owned()?; - let platform_quorum_hash = proof.quorum_hash.try_into().map_err(|e: Vec| { - Error::Protocol(dpp::ProtocolError::DecodingError(format!( - "Invalid quorum hash size {}, expected 32 bytes", - e.len() - ))) - })?; - - let platform_quorum_type = proof.quorum_type; - - let (quorum_hash, core_chain_locked_height) = match self { - AssetLockProof::Chain(v) => (platform_quorum_hash, v.core_chain_locked_height), - AssetLockProof::Instant(v) => ( - v.instant_lock().cyclehash.to_raw_hash().to_byte_array(), - platform_core_chain_locked_height, - ), - }; - - // Try to fetch the quorum public key; if it fails, the - let result = context_provider.get_quorum_public_key( - platform_quorum_type, - quorum_hash, - core_chain_locked_height, - ); - - match result { - Err(ContextProviderError::InvalidQuorum(s)) => Err(Error::QuorumNotFound { - e: ContextProviderError::InvalidQuorum(s), - quorum_hash_hex: hex::encode(quorum_hash), - quorum_type: platform_quorum_type, - core_chain_locked_height, - }), - Err(e) => Err(e.into()), - Ok(_) => Ok(()), - } - } -} #[async_trait::async_trait] impl PutIdentity for Identity { async fn put_to_platform( From bff31d5154d8cb4331854cdd5f9c97ac3f46c41f Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:17:02 +0200 Subject: [PATCH 05/14] refactor(dapi-client): replace CanRetry.is_node_failure with !CanRetry.can_retry() --- packages/rs-dapi-client/src/dapi_client.rs | 14 +++++++------- packages/rs-dapi-client/src/lib.rs | 10 +++++++++- packages/rs-dapi-client/src/transport/grpc.rs | 4 ++-- 3 files changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/rs-dapi-client/src/dapi_client.rs b/packages/rs-dapi-client/src/dapi_client.rs index 8e5a3d660b..166dd2c6d8 100644 --- a/packages/rs-dapi-client/src/dapi_client.rs +++ b/packages/rs-dapi-client/src/dapi_client.rs @@ -39,12 +39,12 @@ pub enum DapiClientError { } impl CanRetry for DapiClientError { - fn is_node_failure(&self) -> bool { + fn can_retry(&self) -> bool { use DapiClientError::*; match self { - NoAvailableAddresses => false, - Transport(transport_error, _) => transport_error.is_node_failure(), - AddressList(_) => false, + NoAvailableAddresses => true, + Transport(transport_error, _) => transport_error.can_retry(), + AddressList(_) => true, #[cfg(feature = "mocks")] Mock(_) => false, } @@ -222,7 +222,7 @@ impl DapiRequestExecutor for DapiClient { tracing::trace!(?response, "received {} response", response_name); } Err(error) => { - if error.is_node_failure() { + if !error.can_retry() { if applied_settings.ban_failed_address { let mut address_list = self .address_list @@ -253,12 +253,12 @@ impl DapiRequestExecutor for DapiClient { duration.as_secs_f32() ) }) - .when(|e| e.is_node_failure()) + .when(|e| !e.can_retry()) .instrument(tracing::info_span!("request routine")) .await; if let Err(error) = &result { - if error.is_node_failure() { + if !error.can_retry() { tracing::error!(?error, "request failed"); } } diff --git a/packages/rs-dapi-client/src/lib.rs b/packages/rs-dapi-client/src/lib.rs index e4f5836e29..950216f4f0 100644 --- a/packages/rs-dapi-client/src/lib.rs +++ b/packages/rs-dapi-client/src/lib.rs @@ -73,6 +73,14 @@ impl DapiRequest for T { /// Allows to flag the transport error variant how tolerant we are of it and whether we can /// try to do a request again. pub trait CanRetry { + /// Returns true if the operation can be retried safely, false means it's unspecified + fn can_retry(&self) -> bool; + /// Get boolean flag that indicates if the error is retryable. - fn is_node_failure(&self) -> bool; + /// + /// Depreacted in favor of [CanRetry::can_retry]. + #[deprecated = "Use !can_retry() instead"] + fn is_node_failure(&self) -> bool { + !self.can_retry() + } } diff --git a/packages/rs-dapi-client/src/transport/grpc.rs b/packages/rs-dapi-client/src/transport/grpc.rs index 316be9cc11..0c9c1baa00 100644 --- a/packages/rs-dapi-client/src/transport/grpc.rs +++ b/packages/rs-dapi-client/src/transport/grpc.rs @@ -75,11 +75,11 @@ impl TransportClient for CoreGrpcClient { } impl CanRetry for dapi_grpc::tonic::Status { - fn is_node_failure(&self) -> bool { + fn can_retry(&self) -> bool { let code = self.code(); use dapi_grpc::tonic::Code::*; - matches!( + !matches!( code, Ok | DataLoss | Cancelled From e3a553864d0549ce0f873209076e69d0a26e241c Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 15 Aug 2024 11:17:17 +0200 Subject: [PATCH 06/14] feat(sdk): Error implements CanRetry --- packages/rs-sdk/src/error.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/rs-sdk/src/error.rs b/packages/rs-sdk/src/error.rs index 0d87db421b..cb0f2b686a 100644 --- a/packages/rs-sdk/src/error.rs +++ b/packages/rs-sdk/src/error.rs @@ -5,7 +5,7 @@ use std::time::Duration; use dapi_grpc::mock::Mockable; use dpp::version::PlatformVersionError; use dpp::ProtocolError; -use rs_dapi_client::DapiClientError; +use rs_dapi_client::{CanRetry, DapiClientError}; pub use drive_proof_verifier::error::ContextProviderError; @@ -97,3 +97,13 @@ impl From for Error { Self::Protocol(value.into()) } } +impl CanRetry for Error { + /// Returns true if the operation can be retried, false means it's unspecified + /// False means + fn can_retry(&self) -> bool { + matches!( + self, + Error::CoreLockedHeightNotYetAvailable(_, _) | Error::QuorumNotFound { .. } + ) + } +} From 4df0c40b55b86b256a376952887ea7224874d99a Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:42:09 +0200 Subject: [PATCH 07/14] fix(dapi-grpc): GetEpochsInfoRequest not marked as versioned --- packages/dapi-grpc/build.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/dapi-grpc/build.rs b/packages/dapi-grpc/build.rs index 6392c84e38..1c80c3d86a 100644 --- a/packages/dapi-grpc/build.rs +++ b/packages/dapi-grpc/build.rs @@ -47,11 +47,12 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { // Derive features for versioned messages // // "GetConsensusParamsRequest" is excluded as this message does not support proofs - const VERSIONED_REQUESTS: [&str; 25] = [ + const VERSIONED_REQUESTS: [&str; 26] = [ "GetDataContractHistoryRequest", "GetDataContractRequest", "GetDataContractsRequest", "GetDocumentsRequest", + "GetEpochsInfoRequest", "GetIdentitiesByPublicKeyHashesRequest", "GetIdentitiesRequest", "GetIdentityNonceRequest", @@ -81,6 +82,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { "GetDataContractResponse", "GetDataContractsResponse", "GetDocumentsResponse", + "GetEpochsInfoResponse", "GetIdentitiesByPublicKeyHashesResponse", "GetIdentitiesResponse", "GetIdentityBalanceAndRevisionResponse", @@ -92,7 +94,6 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { "GetIdentityResponse", "GetProofsResponse", "WaitForStateTransitionResultResponse", - "GetEpochsInfoResponse", "GetProtocolVersionUpgradeStateResponse", "GetProtocolVersionUpgradeVoteStatusResponse", "GetPathElementsResponse", From f41f2bc793e1a51fc40e65a195c150c8bbb8d8c4 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 15 Aug 2024 12:42:56 +0200 Subject: [PATCH 08/14] test(sdk): asset locks verify tests, WIP --- .../src/platform/transition/asset_lock.rs | 2 +- packages/rs-sdk/src/platform/types/epoch.rs | 3 + packages/rs-sdk/tests/fetch/asset_lock.rs | 112 ++++++++++++++++++ packages/rs-sdk/tests/fetch/config.rs | 15 ++- packages/rs-sdk/tests/fetch/mod.rs | 1 + 5 files changed, 126 insertions(+), 7 deletions(-) create mode 100644 packages/rs-sdk/tests/fetch/asset_lock.rs diff --git a/packages/rs-sdk/src/platform/transition/asset_lock.rs b/packages/rs-sdk/src/platform/transition/asset_lock.rs index c09b5d91c2..47734c09df 100644 --- a/packages/rs-sdk/src/platform/transition/asset_lock.rs +++ b/packages/rs-sdk/src/platform/transition/asset_lock.rs @@ -13,7 +13,7 @@ use rs_dapi_client::{DapiRequestExecutor, RequestSettings}; pub trait AssetLockProofVerifier { /// Verifies the asset lock proof against the platform. /// - /// This function will return an error if the proof is not yet available on the platform. + /// This function will return an error if Dash Platform cannot use the provided asset lock proof. /// /// # Errors /// diff --git a/packages/rs-sdk/src/platform/types/epoch.rs b/packages/rs-sdk/src/platform/types/epoch.rs index 6db702cbfd..c7d348f009 100644 --- a/packages/rs-sdk/src/platform/types/epoch.rs +++ b/packages/rs-sdk/src/platform/types/epoch.rs @@ -8,6 +8,9 @@ use crate::{ Error, Sdk, }; +/// Epoch information +pub type Epoch = ExtendedEpochInfo; + #[async_trait] /// Helper trait for managing Epoch information diff --git a/packages/rs-sdk/tests/fetch/asset_lock.rs b/packages/rs-sdk/tests/fetch/asset_lock.rs new file mode 100644 index 0000000000..a54f995623 --- /dev/null +++ b/packages/rs-sdk/tests/fetch/asset_lock.rs @@ -0,0 +1,112 @@ +use dapi_grpc::platform::v0::get_epochs_info_request::GetEpochsInfoRequestV0; +use dapi_grpc::platform::v0::{GetEpochsInfoRequest, GetEpochsInfoResponse}; +use dapi_grpc::platform::VersionedGrpcResponse; +use dash_sdk::platform::transition::asset_lock::AssetLockProofVerifier; +use dash_sdk::platform::types::epoch::{Epoch, ExtendedEpochInfoEx}; +use dpp::dashcore::consensus::deserialize; +use dpp::dashcore::hash_types::CycleHash; +use dpp::dashcore::hashes::hex::FromHex; +use dpp::dashcore::hashes::Hash; +use dpp::dashcore::{InstantLock, Transaction}; +use dpp::identity::state_transition::asset_lock_proof::chain::ChainAssetLockProof; +use dpp::identity::state_transition::asset_lock_proof::InstantAssetLockProof; +use dpp::prelude::AssetLockProof; +use rs_dapi_client::DapiRequest; + +use super::{common::setup_logs, config::Config}; + +async fn current_platform_state(sdk: &dash_sdk::Sdk) -> (u32, Vec) { + let req: GetEpochsInfoRequest = GetEpochsInfoRequestV0 { + ascending: false, + count: 1, + prove: true, + start_epoch: None, + } + .into(); + + let resp: GetEpochsInfoResponse = req + .execute(sdk, Default::default()) + .await + .expect("get epoch info"); + let core_height = resp.metadata().expect("metadata").core_chain_locked_height; + let quorum_hash = resp.proof().expect("proof").quorum_hash.clone(); + (core_height, quorum_hash) +} + +/// Given some existing identity ID, when I fetch the identity, and I get it. +#[tokio::test(flavor = "multi_thread", worker_threads = 1)] +async fn test_asset_lock_proof() { + setup_logs(); + + let cfg = Config::new(); + + let sdk = cfg.setup_api("test_asset_lock_proof").await; + let (core_chain_locked_height, quorum_hash) = current_platform_state(&sdk).await; + + // some semi-correct instant lock + let cyclehash = CycleHash::from_slice(&quorum_hash).expect("cycle hash"); + let instant_lock = InstantLock { + cyclehash, + ..Default::default() + }; + + let out_point = [0u8; 36]; + + // some hardcoded tx, just for tests + let tx_bytes = Vec::from_hex( + "010000000001000100e1f505000000001976a9140389035a9225b3839e2bbf32d826a1e222031fd888ac00000000" + ).unwrap(); + let tx: Transaction = deserialize(&tx_bytes).expect("deserialize tx"); + + struct TestCase { + asset_lock_proof: AssetLockProof, + // expect err that can be retried + expect_err: bool, + } + // instant_lock: InstantLock, transaction: Transaction, output_index: u32 + let test_cases = vec![ + TestCase { + asset_lock_proof: AssetLockProof::Chain(ChainAssetLockProof::new( + core_chain_locked_height, + out_point, + )), + expect_err: false, + }, + TestCase { + asset_lock_proof: AssetLockProof::Instant(InstantAssetLockProof::new( + instant_lock, + tx.clone(), + 0, + )), + expect_err: false, + }, + TestCase { + asset_lock_proof: AssetLockProof::Instant(InstantAssetLockProof::new( + InstantLock::default(), + tx, + 0, + )), + expect_err: true, + }, + TestCase { + asset_lock_proof: AssetLockProof::Chain(ChainAssetLockProof::new( + core_chain_locked_height + 100, + out_point, + )), + expect_err: true, + }, + ]; + + for (i, tc) in test_cases.into_iter().enumerate() { + let result = tc.asset_lock_proof.verify(&sdk).await; + assert_eq!( + result.is_err(), + tc.expect_err, + "tc {} expeced err = {}, got err = {}: {:?}", + i, + tc.expect_err, + result.is_err(), + result + ); + } +} diff --git a/packages/rs-sdk/tests/fetch/config.rs b/packages/rs-sdk/tests/fetch/config.rs index fabf64cb40..94c49df478 100644 --- a/packages/rs-sdk/tests/fetch/config.rs +++ b/packages/rs-sdk/tests/fetch/config.rs @@ -3,6 +3,7 @@ //! This module contains [Config] struct that can be used to configure dash-platform-sdk. //! It's mainly used for testing. +use dash_sdk::networks::NetworkType; use dpp::platform_value::string_encoding::Encoding; use dpp::{ dashcore::{hashes::Hash, ProTxHash}, @@ -176,12 +177,14 @@ impl Config { #[cfg(all(feature = "network-testing", not(feature = "offline-testing")))] let sdk = { // Dump all traffic to disk - let builder = dash_sdk::SdkBuilder::new(self.address_list()).with_core( - &self.platform_host, - self.core_port, - &self.core_user, - &self.core_password, - ); + let builder = dash_sdk::SdkBuilder::new(self.address_list()) + .with_core( + &self.platform_host, + self.core_port, + &self.core_user, + &self.core_password, + ) + .with_network_type(NetworkType::Devnet); #[cfg(feature = "generate-test-vectors")] let builder = { diff --git a/packages/rs-sdk/tests/fetch/mod.rs b/packages/rs-sdk/tests/fetch/mod.rs index 76e6c84c69..9a3b005d96 100644 --- a/packages/rs-sdk/tests/fetch/mod.rs +++ b/packages/rs-sdk/tests/fetch/mod.rs @@ -5,6 +5,7 @@ compile_error!("tests require `mocks` feature to be enabled"); #[cfg(not(any(feature = "network-testing", feature = "offline-testing")))] compile_error!("network-testing or offline-testing must be enabled for tests"); +mod asset_lock; #[cfg(feature = "mocks")] mod broadcast; mod common; From 35177796c47ca52ad13970964bcd74b1718b969b Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:14:27 +0200 Subject: [PATCH 09/14] fix(sdk): local devnet uses LlmqTest --- packages/rs-sdk/src/networks.rs | 3 ++- packages/rs-sdk/tests/fetch/asset_lock.rs | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rs-sdk/src/networks.rs b/packages/rs-sdk/src/networks.rs index a2841df6da..b1d815b7aa 100644 --- a/packages/rs-sdk/src/networks.rs +++ b/packages/rs-sdk/src/networks.rs @@ -80,7 +80,8 @@ impl QuorumParams { pub fn new_devnet() -> Self { QuorumParams { - instant_lock_quorum_type: QuorumType::LlmqDevnet, + // FIXME: local devnet uses regtest + instant_lock_quorum_type: QuorumType::LlmqTest, } } diff --git a/packages/rs-sdk/tests/fetch/asset_lock.rs b/packages/rs-sdk/tests/fetch/asset_lock.rs index a54f995623..84768bcf45 100644 --- a/packages/rs-sdk/tests/fetch/asset_lock.rs +++ b/packages/rs-sdk/tests/fetch/asset_lock.rs @@ -2,7 +2,6 @@ use dapi_grpc::platform::v0::get_epochs_info_request::GetEpochsInfoRequestV0; use dapi_grpc::platform::v0::{GetEpochsInfoRequest, GetEpochsInfoResponse}; use dapi_grpc::platform::VersionedGrpcResponse; use dash_sdk::platform::transition::asset_lock::AssetLockProofVerifier; -use dash_sdk::platform::types::epoch::{Epoch, ExtendedEpochInfoEx}; use dpp::dashcore::consensus::deserialize; use dpp::dashcore::hash_types::CycleHash; use dpp::dashcore::hashes::hex::FromHex; From d9cada9de082a447026976598d60c1916f6f5ad8 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 15 Aug 2024 13:14:48 +0200 Subject: [PATCH 10/14] test(sdk): asset_lock test vectors --- .../vectors/test_asset_lock_proof/.gitkeep | 0 ...4c67089535588985622579e77969e0ffd68afc7.json | Bin 0 -> 70814 bytes ...374fc5b09ba912e017aacb366d2171e9ca6f9d5.json | 1 + 3 files changed, 1 insertion(+) create mode 100644 packages/rs-sdk/tests/vectors/test_asset_lock_proof/.gitkeep create mode 100644 packages/rs-sdk/tests/vectors/test_asset_lock_proof/msg_GetEpochsInfoRequest_1b87e649557ccb609adb9e2904c67089535588985622579e77969e0ffd68afc7.json create mode 100644 packages/rs-sdk/tests/vectors/test_asset_lock_proof/quorum_pubkey-100-4ce7fd81273c2b394c0f32367374fc5b09ba912e017aacb366d2171e9ca6f9d5.json diff --git a/packages/rs-sdk/tests/vectors/test_asset_lock_proof/.gitkeep b/packages/rs-sdk/tests/vectors/test_asset_lock_proof/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/packages/rs-sdk/tests/vectors/test_asset_lock_proof/msg_GetEpochsInfoRequest_1b87e649557ccb609adb9e2904c67089535588985622579e77969e0ffd68afc7.json b/packages/rs-sdk/tests/vectors/test_asset_lock_proof/msg_GetEpochsInfoRequest_1b87e649557ccb609adb9e2904c67089535588985622579e77969e0ffd68afc7.json new file mode 100644 index 0000000000000000000000000000000000000000..5d6f3e563073956050efdbd6416910127a3c2680 GIT binary patch literal 70814 zcmeI(-)@!H6$J2J^Ar)+zVI#u&wkNw5<$M5sgyZ7I`egCId|9JE5 z-}39%KYaiF)mWCl`u5EauixjFr;oq+=H0iiUjO;K*MH4#|MJcE?_PcUn}580^W&@h z_Wj!*UXA@9^1mORe0cJ^CqF&?{okK{{fE=dv#Znf)w7%Nb$fL>z0A+2{I}oV<@@|O z_2(?Qy}EnZb)Rp#+#(*GPAsd%hdL$*CjCVv$IDS76GzF28R44PpJw z0}(ZryG9hO9t>wv5yXGK>-JM>&Fi6bip9ic;yprdig%yRDJ&zVyX&jFQ-jMl32uG= zV*Dn*KL+6G)MyjeKry$k$opeJYXCQ=l=YK%$HGI-1e}HFBVr>qZaQ)?_%-1>tQ8aY^j8w4gKE7&c))* z^K-?E``Q21`K_nlP|L5^$FYLa;rOS$!TL$TGr1xuQwq~U4yRB_Bx^$T#!#B7qb#~b z6OUOw=*kz2&vF3n!rFtzcya#9`oX^Ui!CwxlgJ}Z=tNmsC!&d%WcG#8G$uvI@CkG7zw*=~?Q zX8f?itH5OKL=aGQDu1MEHPH+?6@t304zU+h>e!vTML=H8;I|x?Vz0oOsx1t`9KS_t zYD%RS9oBH4$YlLYfuG}W%!opE7+3#Eji`FVAnK~5NMK!`veI_ou1F+qM77i|>SEHd z2CFM)oC>7ek?{)A9EoVvh8B7s^>{fFn-WF^pXM%95`eV0qQU}i(!x1bRLmt;%IS=D%B(cX1d9aM%OSd z@PTNhydhetruMR6i@B>av|ve5kq6mwP@*9rbwuY+l%({EYO)q!7vo~NEsA`}mfnJ& zadeB6Ue`Pt5$P5Yd7|nSN}QU1u*Er{BeW!5Eopy= z!lfu$s%V?G-lwk?sd5)o1*nRaPzrH`l6pQJ9?HnWMRKcl#KdX>_-r`095H_vrco(EZof_Bk;m!Q4wnDY zA@W`lDHmjE4m^gkt>oii`GR*&Rk%_g_ct2MrZ4K?J|K&bk$s3 zz1^jLrB4kcs^}I;*HS7GL|>j~F$Hr%!Jo<6D7qM$c;=K41=jIHuZXs#PHW40MGR1` zsER~L1xkd}^->Ehe~G`=C-KZqM?|lb#rlY~3Q0R@%2|C?fx_lnV8fltRkTqe(ys-p zYKe$T79$aJza&lun32PqX}4&pA|tChr~uKUas^;Z+)3EgQoxZSG9QZ%OQuC0h1XgW ze428u5TSNUny+k$8yl+FMvH1bv?6R1lK4_l!l(+=hK;Ll=oB{-A;Zj;bP9zlTg1sL z5?Y_A9=Xd;U4b=)aixRmXzHA@PIFY^a*OtqjoD+PG}J$nyI|FVjRMs_i9uQ1c(PvO zNomWLmbSRThOHG5*SNYMBBqR=*|`eDk+Qk6ezFRS}wWnOn-wx z*}^)EjmY^+RMI}`Y(hu5$d}kct4Va;c;?sPe;ZkpVheH$rBGluW~u-s)sgtgq8n8T z5X-!~B&x}UVH+Z(`WljoYBDZ~Ea_sqDOOY65^zyrfDN!bh&tGf`TM~EkPi_2-J0A=_uuu|a70&Q(!C5p|K zCa!Z)7$FfRB=={IDh~qEI9BdNVjdg>tLhM?Se-}~tq##u7Yi2)CA`8K(}vD*%x-A} zSQ4$fw4yVNj&6u zu`g6bQzi#fNU@O1Lbix+cT2hn24<|`Ak;#`&K{yEg|;e}>khEOMbFQOLcSNQuqf&V zhkbh!C>dgVMb?vhN3l}c6}c#i7WeR!52D(9CFPj{2ZsNIpbAv1!~ly@&X+Bfw*r-U zM(A!xQIyu5T(Rniu1HtW0-ZlSQ~TGf*~2zig`}|}<5O2) zwn?091WRL9_wjfdf9OM}O|{m~4`ZvnyHQ1iB&rZcz^3%_MLJAr(-mk1MO8#z;w1i} zIt&Mh%X)Q#goI{313Mm7*Ka($=;W{Og=S+V(FR_fiw1+FlMUXL!8)g?y&Jde)#5WXzmTrk}*wlv3 zX=r)0#T8QUCp@E7d`Q=>S8JlKI&A!Sg*Iz%d7O1nl8S3o(H?OF$st&o50x zA7Qc{ujnlTZ_k$@r|WYCVH+P1`g%S(f7d%!-KBw{Ei{*0flg9JXv;=T4aCeGg0OU@ zN(J8#HfvO4d8ep^angCY&iEk~y|z%nYQD2HSsOTJnf@@Am;#B;RQ#0-Un zmAIOrzU2-bl1N3KFEYc8Y7M-~NGx4EVI@NE7!wsG9-xrEDXrt4Q@4p4F{$^p&Z!tpZ#l|$@B@da2u(>5La;h*QST&Ip zlwehOrOa({@|9q6IIVB+qVTQ{L;~r=hoef?+W6vZn2Q#8bBR2N?!Yy^jt|edMFVS8 zLQ2;oR-Im?!!F(ht8PhDGUiRJXiMnmMd-S%tc@*Hydj0U|Ask`c_w(|qEZ)Kv2N4% zMdu|tsETf@b77%Z$oi@XpI#@bBtJ!ICyOL5Tm&T}Vmc>PP~<`K%N3!UvY1f`tr;R- zxmD^?fK35k<#mf*5d})`W5ufcvR=AaQx33NN2yks5PAz6z+>Jk zU{iRsB`J_R79Fan3>A_{=_Um#5gU_gxDba4P^Ck9rOl97N5ykAG81{WP}WLZ@R3qo zDWEn;dy_RPif)NKM1(tuWK<*POpz+KBG;tQufzY>3<};(mhM295T{frlprsTAW4m+ z6Ira7R3vhKkfBn|`8rPYigZaSjdhE3$+kR6yg(t#zjzcgBOQHkzHl@KJOXl<;2lX1XBtX1xq}O+38Q6&vj=S5U{C=0H&;ap^v*Y~_k# zm4eb%8#T%;JLZ5=Y$C(8j?WBJC$ye{5*s-l2?>vEnL4}r-thzp=Pn+m3g?Su5rB5?XHirVI>|z8%IXaePah6sQC4H3G^ySLm!; zIT3wn0Ww)NB%DGgP{)0vSL922-;N>VVVn{VP#bfCly110hZIqZL{aeg}b5D-ONRxsITW-{-?JVl0-jpk_4689}ed<#gdmeLru}!O$>RzPFmfnJsOt*wY zbgH&Oc~3H>LQWg3jFAm93AUOz`CC#Dl*&bPD2%sYeE{fGDT(ihN(#2YP&{H&bTV~G zT5Pn+Ol}DZ&XX64oG`J)LnP)2saBbhHd;S{(-t5G68z(tbVawM^d#$UaiHov#~&hm zMk-e5A?->6@9MCWNZKp;GYu8#7ZgnLmGet<`U_6=-KDogwCG?VPU()wIk3Ph2DmdC zMe1@z7vq~l#cJtXN~5HQ5t&|EeWc#;_`nRRC!pH3I{v@@+0E5`Uscf~;}1PZ#7QOm z*j}eK0+?t!khy|-F-$RyBO!2WK*V2?g7lGZ{x6g70hJm*u#l*4VPkduj> z|H;Kdiq75!$f%v;ilsTEg_%)AMxDwPTU%>iTVX0%D3~ExoqFyQD{4t?1X5YOLajAV z9Kv7~GDtiws;<{T-Jb=TIFep$1>Tv6ZmE&VEl~)0Z*?n)S0q>TfY!xh*9rNE}Heams{AgxZK z4N{!OdxctAnvo3rlLhKutvKy>x_+bRaOj=%nPKKxm5Ks^s{F{1(@cfyHeYEFg=phr z*36a?Ra4d>JaQ7Cnn>zMJh@xcYO-FU>iP5lHQIzJP!+3hVh2hTQh|-AHgqV1M2U!~ zM2EFCS|3HpprVS>!;iPQf}`>lq0aLm9y#2^CMQ!dHb;84!q%TONsT2mg4Fh;n%DOR zg8!onUcezSn41wMG&sr0l%Or9(x8~pwH{Sboz^ILT0ATo97YZ&mw3b+CFcKGXEva`QUt&#(H{|KQHp!z8Jt9Xx`Ohm@*|*6R~Th87udGqF%BR3Zw| zK?#k2eAUIG;l@u5cMj4LQdN{JRDL*jRTa{ONkxr6)2XD;Ejj>aJzil>m|DXp%F1

N+MMbyT{eSfnrOX-l(+NCe)ARdRo@Q%I|7BkG^Ftn1mE zp3jce&UJmd+UQY*FnEZyRG#u$rTFEGo{FY>iAT;`s?fua%hissy0DU{x`jGhxRCRE zxK>QAkdS5yL|?hc$Uvf+Ta=CsDI#LcLJ&^wbygyAG_RN!ry(|Z5N zy#+`uC^oFX;+6uHM5I6ptVFf0Q2N5S+)`k@T~D1Hmtu9eK_ceff|B;psDhQ0Z4=*U z2ic;5#TaGFR7`_!hGDx*`sDvjWW%!XbMM}g#v!>R3&N^b=+ru0lr&5!3}88H ztlVZTHC2VA3=^A_VO<(?Z&ZS97Y`DT2iDxF2JwNe@dzDtX+kNB)u}=sa#!0Cg_MZU zEw|`%Q-K|m>c90RSp+>k%jqXK*Lf?Jk80vNEVOJloFQAJK Date: Fri, 16 Aug 2024 05:54:21 +0200 Subject: [PATCH 11/14] fix(dapi-grpc): fix const --- packages/dapi-grpc/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/dapi-grpc/build.rs b/packages/dapi-grpc/build.rs index 398826cac4..f0244e7c39 100644 --- a/packages/dapi-grpc/build.rs +++ b/packages/dapi-grpc/build.rs @@ -47,7 +47,7 @@ fn configure_platform(mut platform: MappingConfig) -> MappingConfig { // Derive features for versioned messages // // "GetConsensusParamsRequest" is excluded as this message does not support proofs - const VERSIONED_REQUESTS: [&str; 26] = [ + const VERSIONED_REQUESTS: [&str; 27] = [ "GetDataContractHistoryRequest", "GetDataContractRequest", "GetDataContractsRequest", From f57e455fd7762a873424806cada583ae2a093f64 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Fri, 16 Aug 2024 12:58:09 +0200 Subject: [PATCH 12/14] fix(sdk): build error due to imports --- packages/rs-sdk/tests/fetch/config.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rs-sdk/tests/fetch/config.rs b/packages/rs-sdk/tests/fetch/config.rs index fd79ca1f5a..417ea086b3 100644 --- a/packages/rs-sdk/tests/fetch/config.rs +++ b/packages/rs-sdk/tests/fetch/config.rs @@ -184,7 +184,7 @@ impl Config { &self.core_user, &self.core_password, ) - .with_network_type(NetworkType::Devnet); + .with_network_type(dash_sdk::networks::NetworkType::Devnet); #[cfg(feature = "generate-test-vectors")] let builder = { From b5dfc6a8bfd7432e8b068dcb070d5e9542fe4ddc Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 19 Aug 2024 17:24:38 +0200 Subject: [PATCH 13/14] chore(sdk): cargo fmt --- packages/rs-sdk/src/sdk.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index f0844816d4..f37e6aa5b7 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -472,7 +472,6 @@ impl Sdk { } } - /// Return configuration of quorum, like type of quorum used for instant lock. pub(crate) fn quorum_params(&self) -> QuorumParams { self.network_type.to_quorum_params() @@ -848,7 +847,7 @@ impl SdkBuilder { mock:Arc::new(Mutex::new( MockDashPlatformSdk::new(self.version, Arc::clone(&dapi), self.proofs))), dapi, version:self.version, - }, + }, network_type: self.network_type, dump_dir: self.dump_dir, proofs:self.proofs, From 727cc208c1366cefb0d5c65ac619c5a0b5ea4487 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 10 Dec 2024 10:25:16 +0100 Subject: [PATCH 14/14] chore: fix build --- packages/rs-dapi-client/src/executor.rs | 17 +++++++++++++++++ .../src/core_types/validator_set/v0/mod.rs | 2 +- packages/rs-sdk/tests/fetch/asset_lock.rs | 5 +++-- 3 files changed, 21 insertions(+), 3 deletions(-) diff --git a/packages/rs-dapi-client/src/executor.rs b/packages/rs-dapi-client/src/executor.rs index 0afb8f5705..def87ab2e9 100644 --- a/packages/rs-dapi-client/src/executor.rs +++ b/packages/rs-dapi-client/src/executor.rs @@ -1,6 +1,7 @@ use crate::transport::TransportRequest; use crate::{Address, CanRetry, DapiClientError, RequestSettings}; use dapi_grpc::mock::Mockable; +use dapi_grpc::platform::VersionedGrpcResponse; use dapi_grpc::tonic::async_trait; use std::fmt::Debug; @@ -121,6 +122,22 @@ where } } +impl VersionedGrpcResponse for ExecutionResponse { + type Error = T::Error; + + fn metadata(&self) -> Result<&dapi_grpc::platform::v0::ResponseMetadata, Self::Error> { + self.inner.metadata() + } + + fn proof(&self) -> Result<&dapi_grpc::platform::v0::Proof, Self::Error> { + self.inner.proof() + } + + fn proof_owned(self) -> Result { + self.inner.proof_owned() + } +} + /// Result of request execution pub type ExecutionResult = Result, ExecutionError>; diff --git a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs index dba9180e24..54b529f3f9 100644 --- a/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs +++ b/packages/rs-dpp/src/core_types/validator_set/v0/mod.rs @@ -300,7 +300,7 @@ mod tests { let node_ip = "192.168.1.1".to_string(); let node_id = PubkeyHash::from_slice(&[4; 20]).unwrap(); let validator = ValidatorV0 { - pro_tx_hash: pro_tx_hash.clone(), + pro_tx_hash, public_key, node_ip, node_id, diff --git a/packages/rs-sdk/tests/fetch/asset_lock.rs b/packages/rs-sdk/tests/fetch/asset_lock.rs index 84768bcf45..84186c1fc9 100644 --- a/packages/rs-sdk/tests/fetch/asset_lock.rs +++ b/packages/rs-sdk/tests/fetch/asset_lock.rs @@ -10,7 +10,7 @@ use dpp::dashcore::{InstantLock, Transaction}; use dpp::identity::state_transition::asset_lock_proof::chain::ChainAssetLockProof; use dpp::identity::state_transition::asset_lock_proof::InstantAssetLockProof; use dpp::prelude::AssetLockProof; -use rs_dapi_client::DapiRequest; +use rs_dapi_client::{DapiRequest, IntoInner}; use super::{common::setup_logs, config::Config}; @@ -26,7 +26,8 @@ async fn current_platform_state(sdk: &dash_sdk::Sdk) -> (u32, Vec) { let resp: GetEpochsInfoResponse = req .execute(sdk, Default::default()) .await - .expect("get epoch info"); + .expect("get epoch info") + .into_inner(); let core_height = resp.metadata().expect("metadata").core_chain_locked_height; let quorum_hash = resp.proof().expect("proof").quorum_hash.clone(); (core_height, quorum_hash)