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/27] 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 0a5024f541d..892824e533c 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 59422aa6b2b..d4bb8b946cd 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/27] 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 14b65a58c2c..49648e453e6 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 00000000000..8920b0ead17 --- /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 96b0e23729e..67ab4070c71 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/27] 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 8920b0ead17..a2841df6dac 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 67ab4070c71..be799b6547d 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/27] 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 892824e533c..0d87db421bd 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 490bc40090d..31dfe048580 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 00000000000..c09b5d91c2d --- /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 d4bb8b946cd..f062f4bc763 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/27] 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 8e5a3d660b2..166dd2c6d88 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 e4f5836e29e..950216f4f08 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 316be9cc111..0c9c1baa00b 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/27] 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 0d87db421bd..cb0f2b686af 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/27] 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 6392c84e38a..1c80c3d86aa 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/27] 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 c09b5d91c2d..47734c09dff 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 6db702cbfdb..c7d348f009e 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 00000000000..a54f9956236 --- /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 fabf64cb405..94c49df4781 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 76e6c84c69c..9a3b005d960 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/27] 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 a2841df6dac..b1d815b7aa6 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 a54f9956236..84768bcf45c 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/27] 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 00000000000..e69de29bb2d 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/27] 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 398826cac4f..f0244e7c39d 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/27] 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 fd79ca1f5af..417ea086b35 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/27] 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 f0844816d44..f37e6aa5b75 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/27] 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 0afb8f57054..def87ab2e94 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 dba9180e24b..54b529f3f9c 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 84768bcf45c..84186c1fc95 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) From bd6a4ffbc37e04a5e19e8c2160e9f558a84fc0c3 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Mon, 3 Mar 2025 15:04:17 +0100 Subject: [PATCH 15/27] feat: verify instant asset lock signature --- packages/rs-sdk/src/error.rs | 10 +- .../src/platform/transition/asset_lock.rs | 175 +++++++++++++++++- packages/rs-sdk/src/sdk.rs | 2 +- 3 files changed, 179 insertions(+), 8 deletions(-) diff --git a/packages/rs-sdk/src/error.rs b/packages/rs-sdk/src/error.rs index f12d0055009..4a59122bdc9 100644 --- a/packages/rs-sdk/src/error.rs +++ b/packages/rs-sdk/src/error.rs @@ -75,6 +75,14 @@ pub enum Error { #[error("Asset lock for core locked height {0} not available yet, max avaiable locked core height is {1}; try again later")] CoreLockedHeightNotYetAvailable(u32, u32), + /// Provided asset lock is invalid + /// + /// ## Parameters + /// + /// - 0 - detailed error message + #[error("Invalid asset lock: {0}")] + InvalidAssetLock(String), + /// SDK operation timeout reached error #[error("SDK operation timeout {} secs reached: {1}", .0.as_secs())] TimeoutReached(Duration, String), @@ -120,7 +128,7 @@ impl TryFrom for StateTransitionBroadcastErr type Error = Error; fn try_from(value: StateTransitionBroadcastErrorProto) -> Result { - let cause = if value.data.len() > 0 { + let cause = if !value.data.is_empty() { let consensus_error = ConsensusError::deserialize_from_bytes(&value.data).map_err(|e| { tracing::debug!("Failed to deserialize consensus error: {}", e); diff --git a/packages/rs-sdk/src/platform/transition/asset_lock.rs b/packages/rs-sdk/src/platform/transition/asset_lock.rs index 47734c09dff..06ce7fa2dd7 100644 --- a/packages/rs-sdk/src/platform/transition/asset_lock.rs +++ b/packages/rs-sdk/src/platform/transition/asset_lock.rs @@ -4,11 +4,15 @@ 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 dashcore_rpc::json::QuorumType; +use dpp::bls_signatures::{Bls12381G2Impl, BlsError, Pairing, PublicKey, Signature}; +use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; +use dpp::dashcore::InstantLock; 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. @@ -21,6 +25,7 @@ pub trait AssetLockProofVerifier { /// 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. + /// - [Error::InvalidSignature] if the signature in the proof is invalid. /// - other errors when something goes wrong. async fn verify(&self, sdk: &Sdk) -> Result<(), Error>; } @@ -58,11 +63,17 @@ impl AssetLockProofVerifier for AssetLockProof { Ok(()) } } - AssetLockProof::Instant(v) => { - let quorum_hash = v.instant_lock().cyclehash.to_raw_hash().to_byte_array(); + AssetLockProof::Instant(instant_asset_lock_proof) => { + instant_asset_lock_proof.validate_structure(sdk.version())?; + + let quorum_hash = instant_asset_lock_proof + .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( + let quorum_pubkey = match context_provider.get_quorum_public_key( quorum_type as u32, quorum_hash, platform_core_chain_locked_height, @@ -74,9 +85,161 @@ impl AssetLockProofVerifier for AssetLockProof { core_chain_locked_height: platform_core_chain_locked_height, }), Err(e) => Err(e.into()), - Ok(_) => Ok(()), - } + Ok(key) => Ok(key), + }?; + + verify_instant_lock_signature( + instant_asset_lock_proof.instant_lock(), + &quorum_type, + &quorum_hash, + &quorum_pubkey, + ) + .map_err(|e| { + Error::InvalidAssetLock(format!( + "error during instant asset lock verification: {}", + e + )) + }) + .and_then(|correct| { + if correct { + Ok(()) + } else { + Err(Error::InvalidAssetLock( + "invalid asset lock signature".to_string(), + )) + } + }) } } } } +/// Verify instant lock signature. +/// +/// Retrurns Ok(true) when signature is valid, Ok(false) when signature is invalid, or an error when something goes wrong. +/// +/// Note: This is a generalisation [verify_recent_instant_lock_signature_locally_v0] from drive-abci. +/// +/// TODO: Discuss moving to some other place to reuse in drive-abci and here +fn verify_instant_lock_signature( + instant_lock: &InstantLock, + quorum_type: &QuorumType, + quorum_hash: &[u8], + quorum_public_key: &[u8; 48], +) -> Result { + // First verify signature format + let signature: Signature = + match ::Signature::from_compressed( + instant_lock.signature.as_bytes(), + ) + .into_option() + { + Some(signature) => Signature::Basic(signature), + None => { + tracing::warn!( + instant_lock = ?instant_lock, + "Invalid instant lock {} signature format", + instant_lock.txid, + ); + + return Ok(false); + } + }; + + let threshold_public_key = + PublicKey::try_from(quorum_public_key.as_slice()).map_err(|e| Error::Protocol(e.into()))?; + + let request_id = instant_lock.request_id().map_err(|e| { + Error::Protocol(dpp::ProtocolError::EncodingError(format!( + "cannot create instant asset lock request id: {}", + e + ))) + })?; + + // The signature must verify against the quorum public key and SHA256(llmqType, quorumHash, SHA256(height), txId). + // llmqType and quorumHash must be taken from the quorum selected in 1. + let mut engine = sha256d::Hash::engine(); + + let mut reversed_quorum_hash = quorum_hash.to_vec(); + reversed_quorum_hash.reverse(); + + engine.input(&[*quorum_type as u8]); + engine.input(reversed_quorum_hash.as_slice()); + engine.input(request_id.as_byte_array()); + engine.input(instant_lock.txid.as_byte_array()); + + let message_digest = sha256d::Hash::from_engine(engine); + + match signature.verify( + &threshold_public_key, + message_digest.as_byte_array().as_slice(), + ) { + Ok(()) => Ok(true), + Err(BlsError::InvalidSignature) => Ok(false), + Err(e) => Err(Error::Protocol(e.into())), + } +} + +#[cfg(test)] +mod tests { + + use dashcore_rpc::json::QuorumType; + use dpp::dashcore::{consensus::deserialize, InstantLock}; + + use crate::platform::transition::asset_lock::verify_instant_lock_signature; + + /// Test signature verification on an instant asset lock. + #[test] + fn test_verify_instant_lock_signature() { + const INSTANT_SEND_LOCK_QUORUM_TYPE: QuorumType = QuorumType::Llmq60_75; + + struct TestCase { + instant_lock_hex: &'static str, + quorum_hash: &'static str, + quorum_public_key: &'static str, + correct_signature: bool, + } + + // test vector generated with: + // dash-cli getislocks '["e7ca636c01d65d4e445a802cf69e261676ba5e2a7e0ae57949e2ce5e40bf99ce"]' + let test_cases = vec![ + TestCase{ + instant_lock_hex: "010c828b35aa1ba4ec8ff7b34335f8d4179080f2ed3a0d63f349b8adc868c73ff201010000007a46cb5ef53943cec615f9054acc460418129e4f13ee33cc1f5c39707c11401b020000005d63eaab8d9d29e48e041b9f5b43e3e41b5dac21cd998e703b631198b77b731c0c0000002f7f367e3e9461b8c6c2d919f276a0e344e673dfc84da21b8ff9606fa64f4429050000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639000000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639010000002e35829452aae4996c47ead73b20183bad78e83cb29185f4be9ca60b80e8c06208000000e9ec07776bc2337daa6ee7549b9ba38d8782f0581a21555bc9dde8156c713d6c080000009ba8c0f9ddc2531b576244930e75e66752e8a3dd70d3262ee1b379f58d19ba7d06000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d002000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d00300000042f2373701b15830d8fba26001b4480963db6cf238936eb8d6705ec3fe4cc9f801000000ce99bf405ecee24979e50a7e2a5eba7616269ef62c805a444e5dd6016c63cae72ed3582b963bbda2fdec219ff84299c525dfadcf4b69218a1400000000000000b0f624683b04c01ad58bcf6233f6e492faf0e7f9adf0609dab04a97796aabf13175262c74056690610c075d8cce2cc9f12549b8d5ab3484be19b9c3ebcc9c29dd8d8762bb6e940cc79acfc2940f709a3fa5ff0be11c1304c219931ce58dbac95", + quorum_hash: "000000000000000e1fd2afb1f179b1f5c2f50a3614da93c0e40c4a1ddd921200", + quorum_public_key: "a1ce5102d30de044adccb2a64d1120db355d222a1478b5e2a3f4bf7f90895ac01eccde2ff8cec27c9a886bdfa0b83b1a", + correct_signature: true, + }, + TestCase{ + instant_lock_hex: "010c828b35aa1ba4ec8ff7b34335f8d4179080f2ed3a0d63f349b8adc868c73ff201010000007a46cb5ef53943cec615f9054acc460418129e4f13ee33cc1f5c39707c11401b020000005d63eaab8d9d29e48e041b9f5b43e3e41b5dac21cd998e703b631198b77b731c0c0000002f7f367e3e9461b8c6c2d919f276a0e344e673dfc84da21b8ff9606fa64f4429050000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639000000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639010000002e35829452aae4996c47ead73b20183bad78e83cb29185f4be9ca60b80e8c06208000000e9ec07776bc2337daa6ee7549b9ba38d8782f0581a21555bc9dde8156c713d6c080000009ba8c0f9ddc2531b576244930e75e66752e8a3dd70d3262ee1b379f58d19ba7d06000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d002000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d00300000042f2373701b15830d8fba26001b4480963db6cf238936eb8d6705ec3fe4cc9f801000000ce99bf405ecee24979e50a7e2a5eba7616269ef62c805a444e5dd6016c63cae72ed3582b963bbda2fdec219ff84299c525dfadcf4b69218a1400000000000000b0f624683b04c01ad58bcf6233f6e492faf0e7f9adf0609dab04a97796aabf13175262c74056690610c075d8cce2cc9f12549b8d5ab3484be19b9c3ebcc9c29dd8d8762bb6e940cc79acfc2940f709a3fa5ff0be11c1304c219931ce58dbac95", + quorum_hash: "000000000000000dce79f58fadb53bb32ada6c6f817b1e96e0b95a276248fa7a", + quorum_public_key: "a1ce5102d30de044adccb2a64d1120db355d222a1478b5e2a3f4bf7f90895ac01eccde2ff8cec27c9a886bdfa0b83b1a", + correct_signature: false, + },TestCase{ + instant_lock_hex: "010c828b35aa1ba4ec8ff7b34335f8d4179080f2ed3a0d63f349b8adc868c73ff201010000007a46cb5ef53943cec615f9054acc460418129e4f13ee33cc1f5c39707c11401b020000005d63eaab8d9d29e48e041b9f5b43e3e41b5dac21cd998e703b631198b77b731c0c0000002f7f367e3e9461b8c6c2d919f276a0e344e673dfc84da21b8ff9606fa64f4429050000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639000000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639010000002e35829452aae4996c47ead73b20183bad78e83cb29185f4be9ca60b80e8c06208000000e9ec07776bc2337daa6ee7549b9ba38d8782f0581a21555bc9dde8156c713d6c080000009ba8c0f9ddc2531b576244930e75e66752e8a3dd70d3262ee1b379f58d19ba7d06000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d002000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d00300000042f2373701b15830d8fba26001b4480963db6cf238936eb8d6705ec3fe4cc9f801000000ce99bf405ecee24979e50a7e2a5eba7616269ef62c805a444e5dd6016c63cae72ed3582b963bbda2fdec219ff84299c525dfadcf4b69218a1400000000000000b0f624683b04c01ad58bcf6233f6e492faf0e7f9adf0609dab04a97796aabf13175262c74056690610c075d8cce2cc9f12549b8d5ab3484be19b9c3ebcc9c29dd8d8762bb6e940cc79acfc2940f709a3fa5ff0be11c1304c219931ce58dbac95", + quorum_hash: "000000000000000e1fd2afb1f179b1f5c2f50a3614da93c0e40c4a1ddd921200", + quorum_public_key: "aa3d8543ec8e228b548ddcdee60de91b3bfdb1639b5d4ce295c9e8397985e14ebf2a0c371fb9b4d92354589af5ea2683", + correct_signature: false, + }, + ]; + + for tc in test_cases { + let hex_decoded = hex::decode(tc.instant_lock_hex).unwrap(); + let instant_lock: InstantLock = deserialize(&hex_decoded).unwrap(); + let quorum_hash = hex::decode(tc.quorum_hash).expect("correct hash"); + let quorum_public_key: [u8; 48] = hex::decode(tc.quorum_public_key) + .expect("correct public key") + .try_into() + .expect("correct public key len"); + + assert_eq!( + verify_instant_lock_signature( + &instant_lock, + &INSTANT_SEND_LOCK_QUORUM_TYPE, + &quorum_hash, + &quorum_public_key, + ) + .expect("signature verification failed"), + tc.correct_signature + ); + } + } +} diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 16b1d693ea0..886ccd5cd7c 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -1050,7 +1050,7 @@ impl SdkBuilder { "Network type must be set, use SdkBuilder::with_network_type()".to_string(), )); } - + #[allow(unused_mut)] // needs to be mutable for features other than wasm let mut dapi = DapiClient::new(addresses, dapi_client_settings); #[cfg(not(target_arch = "wasm32"))] From b2c6b13dbf228a9f7b67b95e6e979e1d26d36f4f Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 4 Mar 2025 12:44:28 +0100 Subject: [PATCH 16/27] refactor: use Network from dashcore --- packages/rs-dpp/Cargo.toml | 2 +- packages/rs-sdk/src/networks.rs | 91 +++++++++---------- .../rs-sdk/src/platform/fetch_unproved.rs | 2 +- packages/rs-sdk/src/sdk.rs | 74 +++++++-------- packages/rs-sdk/tests/fetch/config.rs | 1 - 5 files changed, 78 insertions(+), 92 deletions(-) diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 09a509111da..8c3eb7e6c53 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -14,7 +14,7 @@ authors = [ [dependencies] anyhow = { version = "1.0.81" } async-trait = { version = "0.1.79" } -ordered-float = { version = "4.6.0", features = ["serde"]} +ordered-float = { version = "4.6.0", features = ["serde"] } base64 = "0.22.1" bs58 = "0.5" byteorder = { version = "1.4" } diff --git a/packages/rs-sdk/src/networks.rs b/packages/rs-sdk/src/networks.rs index b1d815b7aa6..2faea06865e 100644 --- a/packages/rs-sdk/src/networks.rs +++ b/packages/rs-sdk/src/networks.rs @@ -25,67 +25,58 @@ Devnet: */ use dashcore_rpc::json::QuorumType; +use dpp::dashcore::Network; -/// 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, - /// Custom network configuration. - Custom(QuorumParams), -} +/// Official production network (mainnet) +pub const NETWORK_MAINNET: Network = Network::Dash; -impl NetworkType { - pub fn instant_lock_quorum_type(&self) -> QuorumType { - self.to_quorum_params().instant_lock_quorum_type - } +/// Official testnet network +pub const NETWORK_TESTNET: Network = Network::Testnet; - pub(crate) fn to_quorum_params(&self) -> QuorumParams { - match self { - 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(), - } - } -} +/// Local development network, run in containers on a local machine for development purposess +pub const NETWORK_LOCAL: Network = Network::Regtest; -/// Configuration of Dash Core Quorums. +/// Configuration of the Dash Platform network. /// -/// In most cases, you should use the [`new_mainnet`] or [`new_testnet`] functions to create a new instance. -#[derive(Clone, Debug, PartialEq, Eq)] -pub struct QuorumParams { - pub instant_lock_quorum_type: QuorumType, +/// In most cases, you should use [NETWORK_MAINNET], [NETWORK_TESTNET], or [NETWORK_LOCAL] constants. +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum NetworkSettings { + Default(Network), + Custom { + core_network: Network, + instant_lock_quorum_type: QuorumType, + }, + /// Mock network for testing purposes + #[cfg(feature = "mocks")] + Mock, } -impl QuorumParams { - pub fn new_mainnet() -> Self { - QuorumParams { - instant_lock_quorum_type: QuorumType::Llmq400_60, - } - } - - pub fn new_testnet() -> Self { - QuorumParams { - instant_lock_quorum_type: QuorumType::Llmq50_60, +impl NetworkSettings { + pub fn core_network(&self) -> Network { + match self { + Self::Default(network) => *network, + Self::Custom { core_network, .. } => *core_network, + #[cfg(feature = "mocks")] + Self::Mock => NETWORK_LOCAL, } } - pub fn new_devnet() -> Self { - QuorumParams { - // FIXME: local devnet uses regtest - instant_lock_quorum_type: QuorumType::LlmqTest, - } + pub fn chain_locks_type(&self) -> QuorumType { + let llmq_type = match self { + Self::Default(network) => network.chain_locks_type() as u32, + Self::Custom { + instant_lock_quorum_type, + .. + } => *instant_lock_quorum_type as u32, + #[cfg(feature = "mocks")] + Self::Mock => self.core_network().chain_locks_type() as u32, + }; + QuorumType::from(llmq_type) } +} - pub fn new_mock() -> Self { - Self::new_devnet() +impl From for NetworkSettings { + fn from(network: Network) -> Self { + NetworkSettings::Default(network) } } diff --git a/packages/rs-sdk/src/platform/fetch_unproved.rs b/packages/rs-sdk/src/platform/fetch_unproved.rs index d98d5988447..2393503effa 100644 --- a/packages/rs-sdk/src/platform/fetch_unproved.rs +++ b/packages/rs-sdk/src/platform/fetch_unproved.rs @@ -89,7 +89,7 @@ where Self::maybe_from_unproved_with_metadata( request.clone(), response, - sdk.network, + sdk.core_network(), sdk.version(), ) .map_err(|e| ExecutionError { diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 886ccd5cd7c..5c38e9b11ae 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, QuorumParams}; +use crate::networks::{NetworkSettings, NETWORK_MAINNET}; use crate::platform::transition::put_settings::PutSettings; use crate::platform::{Fetch, Identifier}; use arc_swap::{ArcSwapAny, ArcSwapOption}; @@ -95,11 +95,9 @@ pub type LastQueryTimestamp = u64; /// /// See tests/ for examples of using the SDK. pub struct Sdk { - /// The network that the sdk is configured for (Dash (mainnet), Testnet, Devnet, Regtest) - pub network: Network, inner: SdkInstance, /// Type of network we use. Determines some parameters, like quorum types. - network_type: NetworkType, + network_settings: NetworkSettings, /// Use proofs when retrieving data from the platform. /// /// This is set to `true` by default. `false` is not implemented yet. @@ -142,7 +140,6 @@ pub struct Sdk { impl Clone for Sdk { fn clone(&self) -> Self { Self { - network: self.network, inner: self.inner.clone(), proofs: self.proofs, internal_cache: Arc::clone(&self.internal_cache), @@ -152,7 +149,7 @@ impl Clone for Sdk { metadata_height_tolerance: self.metadata_height_tolerance, metadata_time_tolerance_ms: self.metadata_time_tolerance_ms, dapi_client_settings: self.dapi_client_settings, - network_type: self.network_type.clone(), + network_settings: self.network_settings, #[cfg(feature = "mocks")] dump_dir: self.dump_dir.clone(), } @@ -279,7 +276,11 @@ impl Sdk { Ok(()) } - // TODO: Changed to public for tests + /// Get configured Dash Core network type. + pub fn core_network(&self) -> Network { + self.network_settings.core_network() + } + /// Retrieve object `O` from proof contained in `request` (of type `R`) and `response`. /// /// This method is used to retrieve objects from proofs returned by Dash Platform. @@ -304,7 +305,7 @@ impl Sdk { SdkInstance::Dapi { .. } => O::maybe_from_proof_with_metadata( request, response, - self.network, + self.network_settings.core_network(), self.version(), &provider, ), @@ -532,8 +533,8 @@ 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() + pub(crate) fn network_settings(&self) -> NetworkSettings { + self.network_settings } /// Return [Dash Platform version](PlatformVersion) information used by this SDK. @@ -715,7 +716,7 @@ impl DapiRequestExecutor for Sdk { /// Mandatory steps of initialization in normal mode are: /// /// 1. Create an instance of [SdkBuilder] with [`SdkBuilder::new()`] -/// 2. Set up network type with [`SdkBuilder::with_network_type()`] (not needed for mock) +/// 2. Set up network type with [`SdkBuilder::with_network_settings()`] (not needed for mock) /// 3. Configure the builder with [`SdkBuilder::with_core()`] /// 4. Call [`SdkBuilder::build()`] to create the [Sdk] instance. pub struct SdkBuilder { @@ -725,14 +726,13 @@ pub struct SdkBuilder { addresses: Option, settings: Option, - network: Network, - core_ip: String, core_port: u16, core_user: String, core_password: Zeroizing, - network_type: NetworkType, + /// Customized network settings of a Dash network used by the SDK. + network_settings: NetworkSettings, /// If true, request and verify proofs of the responses. proofs: bool, @@ -780,13 +780,11 @@ impl Default for SdkBuilder { Self { addresses: None, settings: None, - network: Network::Dash, core_ip: "".to_string(), core_port: 0, core_password: "".to_string().into(), core_user: "".to_string(), - network_type: NetworkType::Mock, - + network_settings: NETWORK_MAINNET.into(), proofs: true, metadata_height_tolerance: Some(1), metadata_time_tolerance_ms: None, @@ -817,7 +815,7 @@ impl SdkBuilder { /// /// It creates new SdkBuilder, preconfigured to connect to provided addresses. /// - /// Once created, you need to set [NetworkType] with [`SdkBuilder::with_network_type()`]. + /// Once created, you need to set [NetworkType] with [`SdkBuilder::with_network_settings()`]. pub fn new(addresses: AddressList) -> Self { Self { addresses: Some(addresses), @@ -827,7 +825,7 @@ impl SdkBuilder { /// Create a new SdkBuilder that will generate mock client. pub fn new_mock() -> Self { - Self::default() + Self::default().with_network_settings(NetworkSettings::Mock) } /// Create a new SdkBuilder instance preconfigured for testnet. NOT IMPLEMENTED YET. @@ -859,12 +857,18 @@ impl SdkBuilder { ) } - /// Configure network type. + /// Configure network type to connect to. /// - /// Defaults to Network::Dash which is mainnet. - pub fn with_network(mut self, network: Network) -> Self { - self.network = network; - self + /// Consider using one of these: + /// * [NETWORK_MAINNET](crate::networks::NETWORK_MAINNET). + /// * [NETWORK_TESTNET](crate::networks::NETWORK_TESTNET), + /// * [NETWORK_LOCAL](crate::networks::NETWORK_LOCAL), + /// + /// Defaults to [NETWORK_MAINNET](crate::networks::NETWORK_MAINNET). + /// + /// For more control over the configuration, use [SdkBuilder::with_network_settings()]. + pub fn with_network(self, network: Network) -> Self { + self.with_network_settings(network) } /// Configure CA certificate to use when verifying TLS connections. @@ -949,12 +953,12 @@ impl SdkBuilder { self } - /// Define network to which you want to connect. + /// Customize custom Dash Platform network settings. /// - /// 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; + /// This method is aimed for advanced use cases, where [SdkBuilder::with_network()] is not good enough. + /// It allows to configure network settings like quorum type, network type, etc. by creating [NetworkSettings] directly. + pub fn with_network_settings>(mut self, network_type: T) -> Self { + self.network_settings = network_type.into(); self } @@ -1045,12 +1049,6 @@ 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(), - )); - } - #[allow(unused_mut)] // needs to be mutable for features other than wasm let mut dapi = DapiClient::new(addresses, dapi_client_settings); #[cfg(not(target_arch = "wasm32"))] @@ -1063,10 +1061,9 @@ impl SdkBuilder { #[allow(unused_mut)] // needs to be mutable for #[cfg(feature = "mocks")] let mut sdk= Sdk{ - network: self.network, dapi_client_settings, inner:SdkInstance::Dapi { dapi, version:self.version }, - network_type: self.network_type, + network_settings: self.network_settings, proofs:self.proofs, context_provider: ArcSwapOption::new( self.context_provider.map(Arc::new)), cancel_token: self.cancel_token, @@ -1127,7 +1124,6 @@ impl SdkBuilder { let mock_sdk = MockDashPlatformSdk::new(self.version, Arc::clone(&dapi)); let mock_sdk = Arc::new(Mutex::new(mock_sdk)); let sdk= Sdk { - network: self.network, dapi_client_settings, inner:SdkInstance::Mock { mock:mock_sdk.clone(), @@ -1135,7 +1131,7 @@ impl SdkBuilder { address_list: AddressList::new(), version: self.version, }, - network_type: self.network_type, + network_settings: self.network_settings, dump_dir: self.dump_dir.clone(), proofs:self.proofs, internal_cache: Default::default(), diff --git a/packages/rs-sdk/tests/fetch/config.rs b/packages/rs-sdk/tests/fetch/config.rs index b8031f87510..a93eb2402c5 100644 --- a/packages/rs-sdk/tests/fetch/config.rs +++ b/packages/rs-sdk/tests/fetch/config.rs @@ -3,7 +3,6 @@ //! 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}, From 1264c18d4cc4124cb83d12b0d39a6ce606754ea3 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 4 Mar 2025 12:57:55 +0100 Subject: [PATCH 17/27] refactor: further simplify Network type processing --- packages/rs-sdk/src/networks.rs | 47 ++++--------------- .../src/platform/transition/asset_lock.rs | 5 +- packages/rs-sdk/src/sdk.rs | 40 +++++++--------- 3 files changed, 29 insertions(+), 63 deletions(-) diff --git a/packages/rs-sdk/src/networks.rs b/packages/rs-sdk/src/networks.rs index 2faea06865e..586f01ce13f 100644 --- a/packages/rs-sdk/src/networks.rs +++ b/packages/rs-sdk/src/networks.rs @@ -35,48 +35,19 @@ pub const NETWORK_TESTNET: Network = Network::Testnet; /// Local development network, run in containers on a local machine for development purposess pub const NETWORK_LOCAL: Network = Network::Regtest; +pub trait NetworkSettings { + fn core_network(&self) -> Network; -/// Configuration of the Dash Platform network. -/// -/// In most cases, you should use [NETWORK_MAINNET], [NETWORK_TESTNET], or [NETWORK_LOCAL] constants. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum NetworkSettings { - Default(Network), - Custom { - core_network: Network, - instant_lock_quorum_type: QuorumType, - }, - /// Mock network for testing purposes - #[cfg(feature = "mocks")] - Mock, + fn chain_locks_quorum_type(&self) -> QuorumType; } -impl NetworkSettings { - pub fn core_network(&self) -> Network { - match self { - Self::Default(network) => *network, - Self::Custom { core_network, .. } => *core_network, - #[cfg(feature = "mocks")] - Self::Mock => NETWORK_LOCAL, - } +impl NetworkSettings for Network { + fn core_network(&self) -> Network { + *self } - pub fn chain_locks_type(&self) -> QuorumType { - let llmq_type = match self { - Self::Default(network) => network.chain_locks_type() as u32, - Self::Custom { - instant_lock_quorum_type, - .. - } => *instant_lock_quorum_type as u32, - #[cfg(feature = "mocks")] - Self::Mock => self.core_network().chain_locks_type() as u32, - }; - QuorumType::from(llmq_type) - } -} - -impl From for NetworkSettings { - fn from(network: Network) -> Self { - NetworkSettings::Default(network) + fn chain_locks_quorum_type(&self) -> QuorumType { + let llmq_type: u8 = self.chain_locks_type().into(); + QuorumType::from(llmq_type as u32) } } diff --git a/packages/rs-sdk/src/platform/transition/asset_lock.rs b/packages/rs-sdk/src/platform/transition/asset_lock.rs index 06ce7fa2dd7..684db7b4b4e 100644 --- a/packages/rs-sdk/src/platform/transition/asset_lock.rs +++ b/packages/rs-sdk/src/platform/transition/asset_lock.rs @@ -1,5 +1,6 @@ //! [AssetLockProof] utilities +use crate::networks::NetworkSettings; use crate::{Error, Sdk}; use dapi_grpc::platform::v0::get_epochs_info_request::{self, GetEpochsInfoRequestV0}; use dapi_grpc::platform::v0::GetEpochsInfoRequest; @@ -71,7 +72,7 @@ impl AssetLockProofVerifier for AssetLockProof { .cyclehash .to_raw_hash() .to_byte_array(); - let quorum_type = sdk.quorum_params().instant_lock_quorum_type; + let quorum_type: QuorumType = sdk.network_settings().chain_locks_quorum_type(); // Try to fetch the quorum public key; if it fails, we assume platform does not have this quorum yet let quorum_pubkey = match context_provider.get_quorum_public_key( quorum_type as u32, @@ -183,7 +184,7 @@ fn verify_instant_lock_signature( mod tests { use dashcore_rpc::json::QuorumType; - use dpp::dashcore::{consensus::deserialize, InstantLock}; + use dpp::dashcore::{consensus::deserialize, hashes::Hash, InstantLock}; use crate::platform::transition::asset_lock::verify_instant_lock_signature; diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 5c38e9b11ae..e9c9a9ab69b 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -97,7 +97,7 @@ pub type LastQueryTimestamp = u64; pub struct Sdk { inner: SdkInstance, /// Type of network we use. Determines some parameters, like quorum types. - network_settings: NetworkSettings, + network: Network, /// Use proofs when retrieving data from the platform. /// /// This is set to `true` by default. `false` is not implemented yet. @@ -149,7 +149,7 @@ impl Clone for Sdk { metadata_height_tolerance: self.metadata_height_tolerance, metadata_time_tolerance_ms: self.metadata_time_tolerance_ms, dapi_client_settings: self.dapi_client_settings, - network_settings: self.network_settings, + network: self.network, #[cfg(feature = "mocks")] dump_dir: self.dump_dir.clone(), } @@ -278,7 +278,7 @@ impl Sdk { /// Get configured Dash Core network type. pub fn core_network(&self) -> Network { - self.network_settings.core_network() + self.network.core_network() } /// Retrieve object `O` from proof contained in `request` (of type `R`) and `response`. @@ -305,7 +305,7 @@ impl Sdk { SdkInstance::Dapi { .. } => O::maybe_from_proof_with_metadata( request, response, - self.network_settings.core_network(), + self.network.core_network(), self.version(), &provider, ), @@ -533,8 +533,8 @@ impl Sdk { } /// Return configuration of quorum, like type of quorum used for instant lock. - pub(crate) fn network_settings(&self) -> NetworkSettings { - self.network_settings + pub(crate) fn network_settings(&self) -> Network { + self.network } /// Return [Dash Platform version](PlatformVersion) information used by this SDK. @@ -731,8 +731,10 @@ pub struct SdkBuilder { core_user: String, core_password: Zeroizing, - /// Customized network settings of a Dash network used by the SDK. - network_settings: NetworkSettings, + /// Dash Core network type used by the SDK. + /// + /// Defaults to [NETWORK_MAINNET](crate::networks::NETWORK_MAINNET). + network: Network, /// If true, request and verify proofs of the responses. proofs: bool, @@ -784,7 +786,7 @@ impl Default for SdkBuilder { core_port: 0, core_password: "".to_string().into(), core_user: "".to_string(), - network_settings: NETWORK_MAINNET.into(), + network: NETWORK_MAINNET, proofs: true, metadata_height_tolerance: Some(1), metadata_time_tolerance_ms: None, @@ -825,7 +827,7 @@ impl SdkBuilder { /// Create a new SdkBuilder that will generate mock client. pub fn new_mock() -> Self { - Self::default().with_network_settings(NetworkSettings::Mock) + Self::default() } /// Create a new SdkBuilder instance preconfigured for testnet. NOT IMPLEMENTED YET. @@ -867,8 +869,9 @@ impl SdkBuilder { /// Defaults to [NETWORK_MAINNET](crate::networks::NETWORK_MAINNET). /// /// For more control over the configuration, use [SdkBuilder::with_network_settings()]. - pub fn with_network(self, network: Network) -> Self { - self.with_network_settings(network) + pub fn with_network(mut self, network: Network) -> Self { + self.network = network; + self } /// Configure CA certificate to use when verifying TLS connections. @@ -953,15 +956,6 @@ impl SdkBuilder { self } - /// Customize custom Dash Platform network settings. - /// - /// This method is aimed for advanced use cases, where [SdkBuilder::with_network()] is not good enough. - /// It allows to configure network settings like quorum type, network type, etc. by creating [NetworkSettings] directly. - pub fn with_network_settings>(mut self, network_type: T) -> Self { - self.network_settings = network_type.into(); - 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. @@ -1063,7 +1057,7 @@ impl SdkBuilder { let mut sdk= Sdk{ dapi_client_settings, inner:SdkInstance::Dapi { dapi, version:self.version }, - network_settings: self.network_settings, + network: self.network, proofs:self.proofs, context_provider: ArcSwapOption::new( self.context_provider.map(Arc::new)), cancel_token: self.cancel_token, @@ -1131,7 +1125,7 @@ impl SdkBuilder { address_list: AddressList::new(), version: self.version, }, - network_settings: self.network_settings, + network: self.network, dump_dir: self.dump_dir.clone(), proofs:self.proofs, internal_cache: Default::default(), From 521fdacf08faac4d737af5237221f91e2656d191 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 5 Mar 2025 13:31:55 +0100 Subject: [PATCH 18/27] chore: remove verification of AssetLockProof::Instant --- .../src/platform/transition/asset_lock.rs | 240 ++++-------------- 1 file changed, 43 insertions(+), 197 deletions(-) diff --git a/packages/rs-sdk/src/platform/transition/asset_lock.rs b/packages/rs-sdk/src/platform/transition/asset_lock.rs index 684db7b4b4e..126c89f3780 100644 --- a/packages/rs-sdk/src/platform/transition/asset_lock.rs +++ b/packages/rs-sdk/src/platform/transition/asset_lock.rs @@ -1,24 +1,27 @@ //! [AssetLockProof] utilities -use crate::networks::NetworkSettings; 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 dashcore_rpc::json::QuorumType; -use dpp::bls_signatures::{Bls12381G2Impl, BlsError, Pairing, PublicKey, Signature}; -use dpp::dashcore::hashes::{sha256d, Hash, HashEngine}; -use dpp::dashcore::InstantLock; 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 Dash Platform cannot use the provided asset lock proof. + /// This function verifies some assertions that are necessary for the asset lock proof to be used by Dash Platform, + /// and errors if any of them are not met. + /// + /// Verification involves fetching some information from DAPI and comparing it with the provided asset lock proof. + /// + /// Note that positive verification result does not imply that the asset lock proof is valid. Dash Platform can + /// still reject the asset lock. + /// + /// # Limitations + /// + /// Only [AssetLockProof::Chain] is supported. /// /// # Errors /// @@ -28,33 +31,19 @@ pub trait AssetLockProofVerifier { /// the quorum is not (yet) available. Try again later. /// - [Error::InvalidSignature] if the signature in the proof is invalid. /// - other errors when something goes wrong. + /// + /// # Unstable + /// + /// This function is unstable and may change in the future. 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) => { + let platform_core_chain_locked_height = fetch_platform_locked_height(sdk).await?; if asset_lock.core_chain_locked_height > platform_core_chain_locked_height { Err(Error::CoreLockedHeightNotYetAvailable( asset_lock.core_chain_locked_height, @@ -66,181 +55,38 @@ impl AssetLockProofVerifier for AssetLockProof { } AssetLockProof::Instant(instant_asset_lock_proof) => { instant_asset_lock_proof.validate_structure(sdk.version())?; - - let quorum_hash = instant_asset_lock_proof - .instant_lock() - .cyclehash - .to_raw_hash() - .to_byte_array(); - let quorum_type: QuorumType = sdk.network_settings().chain_locks_quorum_type(); - // Try to fetch the quorum public key; if it fails, we assume platform does not have this quorum yet - let quorum_pubkey = 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(key) => Ok(key), - }?; - - verify_instant_lock_signature( - instant_asset_lock_proof.instant_lock(), - &quorum_type, - &quorum_hash, - &quorum_pubkey, - ) - .map_err(|e| { - Error::InvalidAssetLock(format!( - "error during instant asset lock verification: {}", - e - )) - }) - .and_then(|correct| { - if correct { - Ok(()) - } else { - Err(Error::InvalidAssetLock( - "invalid asset lock signature".to_string(), - )) - } - }) + // To verify instant asset lock, we need to: + // + // 1. Determine quorum hash used to sign it. + // 2. Detch quorum public key for this hash. + // 3. Verify instant asset lock signature. + // + // Unfortunately, determining quorum used to sign the instant asset lock is not straightforward, + // as it requires processing of SML which is not implemented in the SDK yet. + // + // So we just accept the instant asset lock as valid for now. + + Ok(()) } } } } -/// Verify instant lock signature. -/// -/// Retrurns Ok(true) when signature is valid, Ok(false) when signature is invalid, or an error when something goes wrong. -/// -/// Note: This is a generalisation [verify_recent_instant_lock_signature_locally_v0] from drive-abci. -/// -/// TODO: Discuss moving to some other place to reuse in drive-abci and here -fn verify_instant_lock_signature( - instant_lock: &InstantLock, - quorum_type: &QuorumType, - quorum_hash: &[u8], - quorum_public_key: &[u8; 48], -) -> Result { - // First verify signature format - let signature: Signature = - match ::Signature::from_compressed( - instant_lock.signature.as_bytes(), - ) - .into_option() - { - Some(signature) => Signature::Basic(signature), - None => { - tracing::warn!( - instant_lock = ?instant_lock, - "Invalid instant lock {} signature format", - instant_lock.txid, - ); - - return Ok(false); - } - }; - - let threshold_public_key = - PublicKey::try_from(quorum_public_key.as_slice()).map_err(|e| Error::Protocol(e.into()))?; - - let request_id = instant_lock.request_id().map_err(|e| { - Error::Protocol(dpp::ProtocolError::EncodingError(format!( - "cannot create instant asset lock request id: {}", - e - ))) - })?; - - // The signature must verify against the quorum public key and SHA256(llmqType, quorumHash, SHA256(height), txId). - // llmqType and quorumHash must be taken from the quorum selected in 1. - let mut engine = sha256d::Hash::engine(); - - let mut reversed_quorum_hash = quorum_hash.to_vec(); - reversed_quorum_hash.reverse(); - - engine.input(&[*quorum_type as u8]); - engine.input(reversed_quorum_hash.as_slice()); - engine.input(request_id.as_byte_array()); - engine.input(instant_lock.txid.as_byte_array()); - - let message_digest = sha256d::Hash::from_engine(engine); - - match signature.verify( - &threshold_public_key, - message_digest.as_byte_array().as_slice(), - ) { - Ok(()) => Ok(true), - Err(BlsError::InvalidSignature) => Ok(false), - Err(e) => Err(Error::Protocol(e.into())), - } -} - -#[cfg(test)] -mod tests { - - use dashcore_rpc::json::QuorumType; - use dpp::dashcore::{consensus::deserialize, hashes::Hash, InstantLock}; - use crate::platform::transition::asset_lock::verify_instant_lock_signature; - - /// Test signature verification on an instant asset lock. - #[test] - fn test_verify_instant_lock_signature() { - const INSTANT_SEND_LOCK_QUORUM_TYPE: QuorumType = QuorumType::Llmq60_75; - - struct TestCase { - instant_lock_hex: &'static str, - quorum_hash: &'static str, - quorum_public_key: &'static str, - correct_signature: bool, - } - - // test vector generated with: - // dash-cli getislocks '["e7ca636c01d65d4e445a802cf69e261676ba5e2a7e0ae57949e2ce5e40bf99ce"]' - let test_cases = vec![ - TestCase{ - instant_lock_hex: "010c828b35aa1ba4ec8ff7b34335f8d4179080f2ed3a0d63f349b8adc868c73ff201010000007a46cb5ef53943cec615f9054acc460418129e4f13ee33cc1f5c39707c11401b020000005d63eaab8d9d29e48e041b9f5b43e3e41b5dac21cd998e703b631198b77b731c0c0000002f7f367e3e9461b8c6c2d919f276a0e344e673dfc84da21b8ff9606fa64f4429050000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639000000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639010000002e35829452aae4996c47ead73b20183bad78e83cb29185f4be9ca60b80e8c06208000000e9ec07776bc2337daa6ee7549b9ba38d8782f0581a21555bc9dde8156c713d6c080000009ba8c0f9ddc2531b576244930e75e66752e8a3dd70d3262ee1b379f58d19ba7d06000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d002000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d00300000042f2373701b15830d8fba26001b4480963db6cf238936eb8d6705ec3fe4cc9f801000000ce99bf405ecee24979e50a7e2a5eba7616269ef62c805a444e5dd6016c63cae72ed3582b963bbda2fdec219ff84299c525dfadcf4b69218a1400000000000000b0f624683b04c01ad58bcf6233f6e492faf0e7f9adf0609dab04a97796aabf13175262c74056690610c075d8cce2cc9f12549b8d5ab3484be19b9c3ebcc9c29dd8d8762bb6e940cc79acfc2940f709a3fa5ff0be11c1304c219931ce58dbac95", - quorum_hash: "000000000000000e1fd2afb1f179b1f5c2f50a3614da93c0e40c4a1ddd921200", - quorum_public_key: "a1ce5102d30de044adccb2a64d1120db355d222a1478b5e2a3f4bf7f90895ac01eccde2ff8cec27c9a886bdfa0b83b1a", - correct_signature: true, +/// Fetches the current core chain locked height from the platform. +async fn fetch_platform_locked_height(sdk: &Sdk) -> Result { + // 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, }, - TestCase{ - instant_lock_hex: "010c828b35aa1ba4ec8ff7b34335f8d4179080f2ed3a0d63f349b8adc868c73ff201010000007a46cb5ef53943cec615f9054acc460418129e4f13ee33cc1f5c39707c11401b020000005d63eaab8d9d29e48e041b9f5b43e3e41b5dac21cd998e703b631198b77b731c0c0000002f7f367e3e9461b8c6c2d919f276a0e344e673dfc84da21b8ff9606fa64f4429050000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639000000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639010000002e35829452aae4996c47ead73b20183bad78e83cb29185f4be9ca60b80e8c06208000000e9ec07776bc2337daa6ee7549b9ba38d8782f0581a21555bc9dde8156c713d6c080000009ba8c0f9ddc2531b576244930e75e66752e8a3dd70d3262ee1b379f58d19ba7d06000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d002000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d00300000042f2373701b15830d8fba26001b4480963db6cf238936eb8d6705ec3fe4cc9f801000000ce99bf405ecee24979e50a7e2a5eba7616269ef62c805a444e5dd6016c63cae72ed3582b963bbda2fdec219ff84299c525dfadcf4b69218a1400000000000000b0f624683b04c01ad58bcf6233f6e492faf0e7f9adf0609dab04a97796aabf13175262c74056690610c075d8cce2cc9f12549b8d5ab3484be19b9c3ebcc9c29dd8d8762bb6e940cc79acfc2940f709a3fa5ff0be11c1304c219931ce58dbac95", - quorum_hash: "000000000000000dce79f58fadb53bb32ada6c6f817b1e96e0b95a276248fa7a", - quorum_public_key: "a1ce5102d30de044adccb2a64d1120db355d222a1478b5e2a3f4bf7f90895ac01eccde2ff8cec27c9a886bdfa0b83b1a", - correct_signature: false, - },TestCase{ - instant_lock_hex: "010c828b35aa1ba4ec8ff7b34335f8d4179080f2ed3a0d63f349b8adc868c73ff201010000007a46cb5ef53943cec615f9054acc460418129e4f13ee33cc1f5c39707c11401b020000005d63eaab8d9d29e48e041b9f5b43e3e41b5dac21cd998e703b631198b77b731c0c0000002f7f367e3e9461b8c6c2d919f276a0e344e673dfc84da21b8ff9606fa64f4429050000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639000000009ca17ff3474487cfc718e871696bd1d4d7669efced04aa5cdb4cc69f906da639010000002e35829452aae4996c47ead73b20183bad78e83cb29185f4be9ca60b80e8c06208000000e9ec07776bc2337daa6ee7549b9ba38d8782f0581a21555bc9dde8156c713d6c080000009ba8c0f9ddc2531b576244930e75e66752e8a3dd70d3262ee1b379f58d19ba7d06000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d002000000efb7d48484544cfa06585494b427862f098708707ffa1610b4ed33a724bfe4d00300000042f2373701b15830d8fba26001b4480963db6cf238936eb8d6705ec3fe4cc9f801000000ce99bf405ecee24979e50a7e2a5eba7616269ef62c805a444e5dd6016c63cae72ed3582b963bbda2fdec219ff84299c525dfadcf4b69218a1400000000000000b0f624683b04c01ad58bcf6233f6e492faf0e7f9adf0609dab04a97796aabf13175262c74056690610c075d8cce2cc9f12549b8d5ab3484be19b9c3ebcc9c29dd8d8762bb6e940cc79acfc2940f709a3fa5ff0be11c1304c219931ce58dbac95", - quorum_hash: "000000000000000e1fd2afb1f179b1f5c2f50a3614da93c0e40c4a1ddd921200", - quorum_public_key: "aa3d8543ec8e228b548ddcdee60de91b3bfdb1639b5d4ce295c9e8397985e14ebf2a0c371fb9b4d92354589af5ea2683", - correct_signature: false, - }, - ]; - - for tc in test_cases { - let hex_decoded = hex::decode(tc.instant_lock_hex).unwrap(); - let instant_lock: InstantLock = deserialize(&hex_decoded).unwrap(); - let quorum_hash = hex::decode(tc.quorum_hash).expect("correct hash"); - let quorum_public_key: [u8; 48] = hex::decode(tc.quorum_public_key) - .expect("correct public key") - .try_into() - .expect("correct public key len"); + )), + }; + let response = sdk.execute(request, RequestSettings::default()).await?; - assert_eq!( - verify_instant_lock_signature( - &instant_lock, - &INSTANT_SEND_LOCK_QUORUM_TYPE, - &quorum_hash, - &quorum_public_key, - ) - .expect("signature verification failed"), - tc.correct_signature - ); - } - } + Ok(response.metadata()?.core_chain_locked_height) } From 969fb0ec9eb7dbc127c9beecbcdb6f6db9c6e4b8 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 5 Mar 2025 13:46:27 +0100 Subject: [PATCH 19/27] chore: minor cleanup --- packages/rs-sdk/src/networks.rs | 16 ++++++++++++---- packages/rs-sdk/src/sdk.rs | 10 +++++----- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/packages/rs-sdk/src/networks.rs b/packages/rs-sdk/src/networks.rs index 586f01ce13f..1a38aa2c051 100644 --- a/packages/rs-sdk/src/networks.rs +++ b/packages/rs-sdk/src/networks.rs @@ -33,16 +33,24 @@ pub const NETWORK_MAINNET: Network = Network::Dash; /// Official testnet network pub const NETWORK_TESTNET: Network = Network::Testnet; +/// Devnets are small networks started for the needs of development, QA, staging, etc. +pub const NETWORK_DEVNET: Network = Network::Devnet; + /// Local development network, run in containers on a local machine for development purposess pub const NETWORK_LOCAL: Network = Network::Regtest; -pub trait NetworkSettings { - fn core_network(&self) -> Network; +pub trait NetworkConfiguration { + /// Returns the core network type of the current network. + fn to_network(&self) -> Network; + /// Type of quorum used by chain locks on this network. fn chain_locks_quorum_type(&self) -> QuorumType; } -impl NetworkSettings for Network { - fn core_network(&self) -> Network { +/// Configuration of the blockchain network. +pub type NetworkSettings = Network; + +impl NetworkConfiguration for Network { + fn to_network(&self) -> Network { *self } diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index e9c9a9ab69b..77a14dca9fe 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::{NetworkSettings, NETWORK_MAINNET}; +use crate::networks::{NetworkConfiguration, NetworkSettings, NETWORK_MAINNET}; use crate::platform::transition::put_settings::PutSettings; use crate::platform::{Fetch, Identifier}; use arc_swap::{ArcSwapAny, ArcSwapOption}; @@ -97,7 +97,7 @@ pub type LastQueryTimestamp = u64; pub struct Sdk { inner: SdkInstance, /// Type of network we use. Determines some parameters, like quorum types. - network: Network, + network: NetworkSettings, /// Use proofs when retrieving data from the platform. /// /// This is set to `true` by default. `false` is not implemented yet. @@ -278,7 +278,7 @@ impl Sdk { /// Get configured Dash Core network type. pub fn core_network(&self) -> Network { - self.network.core_network() + self.network_settings().to_network() } /// Retrieve object `O` from proof contained in `request` (of type `R`) and `response`. @@ -305,7 +305,7 @@ impl Sdk { SdkInstance::Dapi { .. } => O::maybe_from_proof_with_metadata( request, response, - self.network.core_network(), + self.core_network(), self.version(), &provider, ), @@ -533,7 +533,7 @@ impl Sdk { } /// Return configuration of quorum, like type of quorum used for instant lock. - pub(crate) fn network_settings(&self) -> Network { + pub(crate) fn network_settings(&self) -> impl NetworkConfiguration { self.network } From dd5079723fb5a11279b851f9e5ba382db58108c8 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 5 Mar 2025 14:02:30 +0100 Subject: [PATCH 20/27] chore: self-review --- packages/rs-sdk/src/error.rs | 13 ++-- packages/rs-sdk/src/lib.rs | 1 - packages/rs-sdk/src/networks.rs | 61 ------------------- .../src/platform/transition/asset_lock.rs | 8 +-- packages/rs-sdk/src/sdk.rs | 12 +--- 5 files changed, 15 insertions(+), 80 deletions(-) delete mode 100644 packages/rs-sdk/src/networks.rs diff --git a/packages/rs-sdk/src/error.rs b/packages/rs-sdk/src/error.rs index 4a59122bdc9..f54c0d75ab8 100644 --- a/packages/rs-sdk/src/error.rs +++ b/packages/rs-sdk/src/error.rs @@ -70,10 +70,13 @@ pub enum Error { /// /// ## 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), + /// - core locked height in asset lock + /// - current core locked height on the platform + #[error("Asset lock for core locked height {core_locked_height_in_asset_lock} not available yet, max avaiable locked core height is {core_locked_height_on_platform}; try again later")] + CoreLockedHeightNotYetAvailable { + core_locked_height_in_asset_lock: u32, + core_locked_height_on_platform: u32, + }, /// Provided asset lock is invalid /// @@ -210,7 +213,7 @@ impl CanRetry for Error { self, Error::StaleNode(..) | Error::TimeoutReached(_, _) - | Error::CoreLockedHeightNotYetAvailable(_, _) + | Error::CoreLockedHeightNotYetAvailable { .. } | Error::QuorumNotFound { .. } ) } diff --git a/packages/rs-sdk/src/lib.rs b/packages/rs-sdk/src/lib.rs index 1bb884c9764..fe2c51ab065 100644 --- a/packages/rs-sdk/src/lib.rs +++ b/packages/rs-sdk/src/lib.rs @@ -65,7 +65,6 @@ pub mod core; 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 deleted file mode 100644 index 1a38aa2c051..00000000000 --- a/packages/rs-sdk/src/networks.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! Configuration of dash networks (devnet, testnet, mainnet, etc.). -//! -//! See also: -//! * https://github.com/dashpay/dash/blob/develop/src/chainparams.cpp - -/* -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; -use dpp::dashcore::Network; - -/// Official production network (mainnet) -pub const NETWORK_MAINNET: Network = Network::Dash; - -/// Official testnet network -pub const NETWORK_TESTNET: Network = Network::Testnet; - -/// Devnets are small networks started for the needs of development, QA, staging, etc. -pub const NETWORK_DEVNET: Network = Network::Devnet; - -/// Local development network, run in containers on a local machine for development purposess -pub const NETWORK_LOCAL: Network = Network::Regtest; - -pub trait NetworkConfiguration { - /// Returns the core network type of the current network. - fn to_network(&self) -> Network; - /// Type of quorum used by chain locks on this network. - fn chain_locks_quorum_type(&self) -> QuorumType; -} - -/// Configuration of the blockchain network. -pub type NetworkSettings = Network; - -impl NetworkConfiguration for Network { - fn to_network(&self) -> Network { - *self - } - - fn chain_locks_quorum_type(&self) -> QuorumType { - let llmq_type: u8 = self.chain_locks_type().into(); - QuorumType::from(llmq_type as u32) - } -} diff --git a/packages/rs-sdk/src/platform/transition/asset_lock.rs b/packages/rs-sdk/src/platform/transition/asset_lock.rs index 126c89f3780..9299897218a 100644 --- a/packages/rs-sdk/src/platform/transition/asset_lock.rs +++ b/packages/rs-sdk/src/platform/transition/asset_lock.rs @@ -45,10 +45,10 @@ impl AssetLockProofVerifier for AssetLockProof { AssetLockProof::Chain(asset_lock) => { let platform_core_chain_locked_height = fetch_platform_locked_height(sdk).await?; 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, - )) + Err(Error::CoreLockedHeightNotYetAvailable { + core_locked_height_in_asset_lock: asset_lock.core_chain_locked_height, + core_locked_height_on_platform: platform_core_chain_locked_height, + }) } else { Ok(()) } diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 77a14dca9fe..b88471daf73 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -5,7 +5,6 @@ use crate::internal_cache::InternalSdkCache; use crate::mock::MockResponse; #[cfg(feature = "mocks")] use crate::mock::{provider::GrpcContextProvider, MockDashPlatformSdk}; -use crate::networks::{NetworkConfiguration, NetworkSettings, NETWORK_MAINNET}; use crate::platform::transition::put_settings::PutSettings; use crate::platform::{Fetch, Identifier}; use arc_swap::{ArcSwapAny, ArcSwapOption}; @@ -97,7 +96,7 @@ pub type LastQueryTimestamp = u64; pub struct Sdk { inner: SdkInstance, /// Type of network we use. Determines some parameters, like quorum types. - network: NetworkSettings, + network: Network, /// Use proofs when retrieving data from the platform. /// /// This is set to `true` by default. `false` is not implemented yet. @@ -278,7 +277,7 @@ impl Sdk { /// Get configured Dash Core network type. pub fn core_network(&self) -> Network { - self.network_settings().to_network() + self.network } /// Retrieve object `O` from proof contained in `request` (of type `R`) and `response`. @@ -532,11 +531,6 @@ impl Sdk { } } - /// Return configuration of quorum, like type of quorum used for instant lock. - pub(crate) fn network_settings(&self) -> impl NetworkConfiguration { - self.network - } - /// Return [Dash Platform version](PlatformVersion) information used by this SDK. /// /// @@ -786,7 +780,7 @@ impl Default for SdkBuilder { core_port: 0, core_password: "".to_string().into(), core_user: "".to_string(), - network: NETWORK_MAINNET, + network: Network::Dash, proofs: true, metadata_height_tolerance: Some(1), metadata_time_tolerance_ms: None, From 821bfd7f64570497fd275d45d22f7a3d469a2de8 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:09:56 +0100 Subject: [PATCH 21/27] chore: fix warnings and failing build --- packages/rs-dpp/Cargo.toml | 2 +- packages/rs-drive-proof-verifier/src/provider.rs | 2 +- .../src/types/evonode_status.rs | 2 +- packages/rs-drive-proof-verifier/src/verify.rs | 2 +- packages/rs-sdk/src/error.rs | 2 +- packages/rs-sdk/src/platform/query.rs | 2 +- packages/rs-sdk/src/platform/transition.rs | 5 ++--- packages/rs-sdk/src/platform/transition/asset_lock.rs | 2 +- packages/rs-sdk/src/platform/transition/builder.rs | 1 + .../rs-sdk/src/platform/transition/put_identity.rs | 6 ++---- .../platform/transition/update_price_of_document.rs | 1 - packages/rs-sdk/src/platform/types/proposed_blocks.rs | 1 - packages/rs-sdk/src/sdk.rs | 11 ++++++----- packages/rs-sdk/tests/fetch/config.rs | 1 + 14 files changed, 19 insertions(+), 21 deletions(-) diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index 8c3eb7e6c53..1a4cc395e82 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -127,7 +127,7 @@ dash-sdk-features = [ # "json-object", # "platform-value", # "system_contracts", - # "validation", # TODO: This one is big + "validation", # TODO: This one is big "identity-hashing", "data-contract-json-conversion", # "identity-serialization", diff --git a/packages/rs-drive-proof-verifier/src/provider.rs b/packages/rs-drive-proof-verifier/src/provider.rs index e7eafd2e45f..cb4d72db801 100644 --- a/packages/rs-drive-proof-verifier/src/provider.rs +++ b/packages/rs-drive-proof-verifier/src/provider.rs @@ -86,7 +86,7 @@ impl + Send + Sync> ContextProvider for C { } } -impl<'a, T: ContextProvider + 'a> ContextProvider for std::sync::Mutex +impl ContextProvider for std::sync::Mutex where Self: Sync + Send, { diff --git a/packages/rs-drive-proof-verifier/src/types/evonode_status.rs b/packages/rs-drive-proof-verifier/src/types/evonode_status.rs index 87831de0f6f..589b692f485 100644 --- a/packages/rs-drive-proof-verifier/src/types/evonode_status.rs +++ b/packages/rs-drive-proof-verifier/src/types/evonode_status.rs @@ -241,7 +241,7 @@ impl TryFrom<&GetStatusResponse> for Version { let protocol = v0 .version .as_ref() - .and_then(|v| v.protocol.clone()) + .and_then(|v| v.protocol) .map(|p| Protocol { tenderdash: p.tenderdash.map(|t| TenderdashProtocol { p2p: t.p2p, diff --git a/packages/rs-drive-proof-verifier/src/verify.rs b/packages/rs-drive-proof-verifier/src/verify.rs index 6015999df2e..7a9eb9d0c7e 100644 --- a/packages/rs-drive-proof-verifier/src/verify.rs +++ b/packages/rs-drive-proof-verifier/src/verify.rs @@ -130,7 +130,7 @@ pub fn verify_signature_digest( }); } let signature = Signature::Basic( - ::Signature::from_compressed(&signature) + ::Signature::from_compressed(signature) .into_option() .ok_or(Error::SignatureVerificationError { error: "Could not verify signature digest".to_string(), diff --git a/packages/rs-sdk/src/error.rs b/packages/rs-sdk/src/error.rs index f54c0d75ab8..1749c655536 100644 --- a/packages/rs-sdk/src/error.rs +++ b/packages/rs-sdk/src/error.rs @@ -72,7 +72,7 @@ pub enum Error { /// /// - core locked height in asset lock /// - current core locked height on the platform - #[error("Asset lock for core locked height {core_locked_height_in_asset_lock} not available yet, max avaiable locked core height is {core_locked_height_on_platform}; try again later")] + #[error("Asset lock for core locked height {core_locked_height_in_asset_lock} not available yet, max available locked core height is {core_locked_height_on_platform}; try again later")] CoreLockedHeightNotYetAvailable { core_locked_height_in_asset_lock: u32, core_locked_height_on_platform: u32, diff --git a/packages/rs-sdk/src/platform/query.rs b/packages/rs-sdk/src/platform/query.rs index a145d89058b..ed8b1797675 100644 --- a/packages/rs-sdk/src/platform/query.rs +++ b/packages/rs-sdk/src/platform/query.rs @@ -180,7 +180,7 @@ impl Query for Identifier { } } -impl<'a> Query for DriveDocumentQuery<'a> { +impl Query for DriveDocumentQuery<'_> { fn query(self, prove: bool) -> Result { if !prove { unimplemented!("queries without proofs are not supported yet"); diff --git a/packages/rs-sdk/src/platform/transition.rs b/packages/rs-sdk/src/platform/transition.rs index 854043f0eaf..e8c64d90f6f 100644 --- a/packages/rs-sdk/src/platform/transition.rs +++ b/packages/rs-sdk/src/platform/transition.rs @@ -3,6 +3,8 @@ pub mod asset_lock; pub mod broadcast; pub(crate) mod broadcast_identity; pub mod broadcast_request; +pub mod builder; +pub mod fungible_tokens; pub mod purchase_document; pub mod put_contract; pub mod put_document; @@ -18,6 +20,3 @@ pub mod waitable; pub mod withdraw_from_identity; pub use txid::TxId; - -mod builder; -pub mod fungible_tokens; diff --git a/packages/rs-sdk/src/platform/transition/asset_lock.rs b/packages/rs-sdk/src/platform/transition/asset_lock.rs index 9299897218a..d620b0f8c08 100644 --- a/packages/rs-sdk/src/platform/transition/asset_lock.rs +++ b/packages/rs-sdk/src/platform/transition/asset_lock.rs @@ -58,7 +58,7 @@ impl AssetLockProofVerifier for AssetLockProof { // To verify instant asset lock, we need to: // // 1. Determine quorum hash used to sign it. - // 2. Detch quorum public key for this hash. + // 2. Fetch quorum public key for this hash. // 3. Verify instant asset lock signature. // // Unfortunately, determining quorum used to sign the instant asset lock is not straightforward, diff --git a/packages/rs-sdk/src/platform/transition/builder.rs b/packages/rs-sdk/src/platform/transition/builder.rs index 6c4549561d4..15649e382aa 100644 --- a/packages/rs-sdk/src/platform/transition/builder.rs +++ b/packages/rs-sdk/src/platform/transition/builder.rs @@ -9,6 +9,7 @@ use dpp::state_transition::StateTransition; use dpp::version::PlatformVersion; /// Trait for building state transitions +#[allow(async_fn_in_trait)] pub trait StateTransitionBuilder { /// Returns the settings for the state transition /// diff --git a/packages/rs-sdk/src/platform/transition/put_identity.rs b/packages/rs-sdk/src/platform/transition/put_identity.rs index d2a4475a19f..2a08fbce33e 100644 --- a/packages/rs-sdk/src/platform/transition/put_identity.rs +++ b/packages/rs-sdk/src/platform/transition/put_identity.rs @@ -1,10 +1,8 @@ -use crate::platform::block_info_from_metadata::block_info_from_metadata; -use crate::platform::transition::broadcast_identity::BroadcastRequestForNewIdentity; -use crate::{Error, Sdk}; - use super::broadcast::BroadcastStateTransition; +use super::broadcast_identity::BroadcastRequestForNewIdentity; use super::put_settings::PutSettings; use super::waitable::Waitable; +use crate::{Error, Sdk}; use dpp::dashcore::PrivateKey; use dpp::identity::signer::Signer; use dpp::prelude::{AssetLockProof, Identity}; diff --git a/packages/rs-sdk/src/platform/transition/update_price_of_document.rs b/packages/rs-sdk/src/platform/transition/update_price_of_document.rs index e0bb06e0eff..b6e651d5eec 100644 --- a/packages/rs-sdk/src/platform/transition/update_price_of_document.rs +++ b/packages/rs-sdk/src/platform/transition/update_price_of_document.rs @@ -11,7 +11,6 @@ use dpp::identity::signer::Signer; use dpp::identity::IdentityPublicKey; use dpp::state_transition::batch_transition::methods::v0::DocumentsBatchTransitionMethodsV0; use dpp::state_transition::batch_transition::BatchTransition; -use dpp::state_transition::proof_result::StateTransitionProofResult; use dpp::state_transition::StateTransition; #[async_trait::async_trait] diff --git a/packages/rs-sdk/src/platform/types/proposed_blocks.rs b/packages/rs-sdk/src/platform/types/proposed_blocks.rs index 16afa42101e..e0ca6512ff5 100644 --- a/packages/rs-sdk/src/platform/types/proposed_blocks.rs +++ b/packages/rs-sdk/src/platform/types/proposed_blocks.rs @@ -43,7 +43,6 @@ pub trait ProposedBlockCountEx { /// ## See also /// /// - [`ProposerBlockCounts`](crate::ProposerBlockCounts): The data structure holding the result of this operation. - async fn fetch_proposed_blocks_by_range( sdk: &Sdk, epoch: Option, diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index b88471daf73..12e779cb5a4 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -727,7 +727,7 @@ pub struct SdkBuilder { /// Dash Core network type used by the SDK. /// - /// Defaults to [NETWORK_MAINNET](crate::networks::NETWORK_MAINNET). + /// Defaults to [Network::Dash]. network: Network, /// If true, request and verify proofs of the responses. @@ -856,11 +856,12 @@ impl SdkBuilder { /// Configure network type to connect to. /// /// Consider using one of these: - /// * [NETWORK_MAINNET](crate::networks::NETWORK_MAINNET). - /// * [NETWORK_TESTNET](crate::networks::NETWORK_TESTNET), - /// * [NETWORK_LOCAL](crate::networks::NETWORK_LOCAL), + /// * [Network::Dash] for mainnet, + /// * [Network::Testnet] for testnet, + /// * [Network::Devnet] for testing, QA, staging and similar environments, + /// * [Network::Regtest] for local development environments (eg. whole network started with dashmate on one host). /// - /// Defaults to [NETWORK_MAINNET](crate::networks::NETWORK_MAINNET). + /// Defaults to [Network::Dash]. /// /// For more control over the configuration, use [SdkBuilder::with_network_settings()]. pub fn with_network(mut self, network: Network) -> Self { diff --git a/packages/rs-sdk/tests/fetch/config.rs b/packages/rs-sdk/tests/fetch/config.rs index a93eb2402c5..2be76fe5a7e 100644 --- a/packages/rs-sdk/tests/fetch/config.rs +++ b/packages/rs-sdk/tests/fetch/config.rs @@ -55,6 +55,7 @@ pub struct Config { pub platform_ssl: bool, /// When platform_ssl is true, use the PEM-encoded CA certificate from provided absolute path to verify the server certificate. + #[cfg(all(feature = "network-testing", not(feature = "offline-testing")))] #[serde(default)] pub platform_ca_cert_path: Option, From a6910f2fc3ce5c7577eb8cbcf3827e081ac72530 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:11:59 +0100 Subject: [PATCH 22/27] test: remove unsupported test case --- packages/rs-sdk/tests/fetch/asset_lock.rs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/packages/rs-sdk/tests/fetch/asset_lock.rs b/packages/rs-sdk/tests/fetch/asset_lock.rs index 84186c1fc95..487a74e9e33 100644 --- a/packages/rs-sdk/tests/fetch/asset_lock.rs +++ b/packages/rs-sdk/tests/fetch/asset_lock.rs @@ -63,7 +63,7 @@ async fn test_asset_lock_proof() { // 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( @@ -80,14 +80,6 @@ async fn test_asset_lock_proof() { )), 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, From 9ca5a7b30e813814935a0c0329af744447b3a9d1 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Wed, 5 Mar 2025 15:19:03 +0100 Subject: [PATCH 23/27] doc: fix some docs --- packages/rs-sdk/src/sdk.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 12e779cb5a4..9fb885bd75a 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -710,7 +710,7 @@ impl DapiRequestExecutor for Sdk { /// Mandatory steps of initialization in normal mode are: /// /// 1. Create an instance of [SdkBuilder] with [`SdkBuilder::new()`] -/// 2. Set up network type with [`SdkBuilder::with_network_settings()`] (not needed for mock) +/// 2. Set up network type with [`SdkBuilder::with_network()`] /// 3. Configure the builder with [`SdkBuilder::with_core()`] /// 4. Call [`SdkBuilder::build()`] to create the [Sdk] instance. pub struct SdkBuilder { @@ -811,7 +811,7 @@ impl SdkBuilder { /// /// It creates new SdkBuilder, preconfigured to connect to provided addresses. /// - /// Once created, you need to set [NetworkType] with [`SdkBuilder::with_network_settings()`]. + /// Once created, consider setting the [Network] with [`SdkBuilder::with_network()`]. pub fn new(addresses: AddressList) -> Self { Self { addresses: Some(addresses), @@ -862,8 +862,6 @@ impl SdkBuilder { /// * [Network::Regtest] for local development environments (eg. whole network started with dashmate on one host). /// /// Defaults to [Network::Dash]. - /// - /// For more control over the configuration, use [SdkBuilder::with_network_settings()]. pub fn with_network(mut self, network: Network) -> Self { self.network = network; self From de4de6754c1855ccdab424382abc793fa3a8ce62 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 6 Mar 2025 11:54:42 +0100 Subject: [PATCH 24/27] chore: use async_trait for StateTransitionBuilder --- packages/rs-sdk/src/platform/transition/builder.rs | 3 ++- .../rs-sdk/src/platform/transition/fungible_tokens/burn.rs | 1 + .../rs-sdk/src/platform/transition/fungible_tokens/destroy.rs | 1 + .../platform/transition/fungible_tokens/emergency_action.rs | 1 + .../rs-sdk/src/platform/transition/fungible_tokens/freeze.rs | 1 + .../rs-sdk/src/platform/transition/fungible_tokens/mint.rs | 1 + .../rs-sdk/src/platform/transition/fungible_tokens/transfer.rs | 1 + .../rs-sdk/src/platform/transition/fungible_tokens/unfreeze.rs | 1 + 8 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/rs-sdk/src/platform/transition/builder.rs b/packages/rs-sdk/src/platform/transition/builder.rs index 15649e382aa..091af08cbf5 100644 --- a/packages/rs-sdk/src/platform/transition/builder.rs +++ b/packages/rs-sdk/src/platform/transition/builder.rs @@ -9,7 +9,8 @@ use dpp::state_transition::StateTransition; use dpp::version::PlatformVersion; /// Trait for building state transitions -#[allow(async_fn_in_trait)] +#[async_trait::async_trait] +#[async_trait::async_trait] pub trait StateTransitionBuilder { /// Returns the settings for the state transition /// diff --git a/packages/rs-sdk/src/platform/transition/fungible_tokens/burn.rs b/packages/rs-sdk/src/platform/transition/fungible_tokens/burn.rs index f0595d18410..452fccd5833 100644 --- a/packages/rs-sdk/src/platform/transition/fungible_tokens/burn.rs +++ b/packages/rs-sdk/src/platform/transition/fungible_tokens/burn.rs @@ -111,6 +111,7 @@ impl<'a> TokenBurnTransitionBuilder<'a> { } } +#[async_trait::async_trait] impl StateTransitionBuilder for TokenBurnTransitionBuilder<'_> { /// Returns the settings for the token burn transition /// diff --git a/packages/rs-sdk/src/platform/transition/fungible_tokens/destroy.rs b/packages/rs-sdk/src/platform/transition/fungible_tokens/destroy.rs index e82e4becbe0..bb850172dfa 100644 --- a/packages/rs-sdk/src/platform/transition/fungible_tokens/destroy.rs +++ b/packages/rs-sdk/src/platform/transition/fungible_tokens/destroy.rs @@ -119,6 +119,7 @@ impl<'a> TokenDestroyFrozenFundsTransitionBuilder<'a> { } } +#[async_trait::async_trait] impl StateTransitionBuilder for TokenDestroyFrozenFundsTransitionBuilder<'_> { /// Returns the settings for the token destroy transition /// diff --git a/packages/rs-sdk/src/platform/transition/fungible_tokens/emergency_action.rs b/packages/rs-sdk/src/platform/transition/fungible_tokens/emergency_action.rs index b8c45390cd9..51250a1fafd 100644 --- a/packages/rs-sdk/src/platform/transition/fungible_tokens/emergency_action.rs +++ b/packages/rs-sdk/src/platform/transition/fungible_tokens/emergency_action.rs @@ -148,6 +148,7 @@ impl<'a> TokenEmergencyActionTransitionBuilder<'a> { } } +#[async_trait::async_trait] impl StateTransitionBuilder for TokenEmergencyActionTransitionBuilder<'_> { /// Returns the settings for the token emergency action transition /// diff --git a/packages/rs-sdk/src/platform/transition/fungible_tokens/freeze.rs b/packages/rs-sdk/src/platform/transition/fungible_tokens/freeze.rs index 0ac89e66c2d..0a1c9276d08 100644 --- a/packages/rs-sdk/src/platform/transition/fungible_tokens/freeze.rs +++ b/packages/rs-sdk/src/platform/transition/fungible_tokens/freeze.rs @@ -119,6 +119,7 @@ impl<'a> TokenFreezeTransitionBuilder<'a> { } } +#[async_trait::async_trait] impl StateTransitionBuilder for TokenFreezeTransitionBuilder<'_> { /// Returns the settings for the token freeze transition /// diff --git a/packages/rs-sdk/src/platform/transition/fungible_tokens/mint.rs b/packages/rs-sdk/src/platform/transition/fungible_tokens/mint.rs index 380f7cfe21d..d782ce80571 100644 --- a/packages/rs-sdk/src/platform/transition/fungible_tokens/mint.rs +++ b/packages/rs-sdk/src/platform/transition/fungible_tokens/mint.rs @@ -139,6 +139,7 @@ impl<'a> TokenMintTransitionBuilder<'a> { } } +#[async_trait::async_trait] impl StateTransitionBuilder for TokenMintTransitionBuilder<'_> { /// Returns the settings for the token mint transition /// diff --git a/packages/rs-sdk/src/platform/transition/fungible_tokens/transfer.rs b/packages/rs-sdk/src/platform/transition/fungible_tokens/transfer.rs index 281907b0799..5c1956009e5 100644 --- a/packages/rs-sdk/src/platform/transition/fungible_tokens/transfer.rs +++ b/packages/rs-sdk/src/platform/transition/fungible_tokens/transfer.rs @@ -143,6 +143,7 @@ impl<'a> TokenTransferTransitionBuilder<'a> { } } +#[async_trait::async_trait] impl StateTransitionBuilder for TokenTransferTransitionBuilder<'_> { /// Returns the settings for the token transfer transition /// diff --git a/packages/rs-sdk/src/platform/transition/fungible_tokens/unfreeze.rs b/packages/rs-sdk/src/platform/transition/fungible_tokens/unfreeze.rs index 6cb837a18e1..3fecadb05cc 100644 --- a/packages/rs-sdk/src/platform/transition/fungible_tokens/unfreeze.rs +++ b/packages/rs-sdk/src/platform/transition/fungible_tokens/unfreeze.rs @@ -119,6 +119,7 @@ impl<'a> TokenUnfreezeTransitionBuilder<'a> { } } +#[async_trait::async_trait] impl StateTransitionBuilder for TokenUnfreezeTransitionBuilder<'_> { /// Returns the settings for the token unfreeze transition /// From c22fa070a87e3c0479729e0324dc1836746d0391 Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 6 Mar 2025 11:55:58 +0100 Subject: [PATCH 25/27] chore: remove duplicate async_trait --- packages/rs-sdk/src/platform/transition/builder.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/rs-sdk/src/platform/transition/builder.rs b/packages/rs-sdk/src/platform/transition/builder.rs index 091af08cbf5..ed2720d764d 100644 --- a/packages/rs-sdk/src/platform/transition/builder.rs +++ b/packages/rs-sdk/src/platform/transition/builder.rs @@ -10,7 +10,6 @@ use dpp::version::PlatformVersion; /// Trait for building state transitions #[async_trait::async_trait] -#[async_trait::async_trait] pub trait StateTransitionBuilder { /// Returns the settings for the state transition /// From 20a836b51b87ab3f6785084203050fe0fe0f0bfe Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Thu, 6 Mar 2025 11:57:04 +0100 Subject: [PATCH 26/27] chore(sdk): s/core_network()/network()/ --- packages/rs-sdk/src/platform/fetch_unproved.rs | 2 +- packages/rs-sdk/src/sdk.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/rs-sdk/src/platform/fetch_unproved.rs b/packages/rs-sdk/src/platform/fetch_unproved.rs index 2393503effa..09bf287a585 100644 --- a/packages/rs-sdk/src/platform/fetch_unproved.rs +++ b/packages/rs-sdk/src/platform/fetch_unproved.rs @@ -89,7 +89,7 @@ where Self::maybe_from_unproved_with_metadata( request.clone(), response, - sdk.core_network(), + sdk.network(), sdk.version(), ) .map_err(|e| ExecutionError { diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 9fb885bd75a..1299d86eeba 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -276,7 +276,7 @@ impl Sdk { } /// Get configured Dash Core network type. - pub fn core_network(&self) -> Network { + pub fn network(&self) -> Network { self.network } @@ -304,7 +304,7 @@ impl Sdk { SdkInstance::Dapi { .. } => O::maybe_from_proof_with_metadata( request, response, - self.core_network(), + self.network(), self.version(), &provider, ), From bb8dcff74349e19c1117efdb6bd85c369d35b4eb Mon Sep 17 00:00:00 2001 From: Lukasz Klimek <842586+lklimek@users.noreply.github.com> Date: Tue, 18 Mar 2025 15:54:38 +0100 Subject: [PATCH 27/27] build(dpp): remove unused ordered-float dependency --- Cargo.lock | 14 -------------- packages/rs-dpp/Cargo.toml | 1 - 2 files changed, 15 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0a04f312da6..0fb070fb49d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1503,7 +1503,6 @@ dependencies = [ "nohash-hasher", "num_enum 0.7.3", "once_cell", - "ordered-float", "platform-serialization", "platform-serialization-derive", "platform-value", @@ -3425,17 +3424,6 @@ dependencies = [ "vcpkg", ] -[[package]] -name = "ordered-float" -version = "4.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" -dependencies = [ - "num-traits", - "rand", - "serde", -] - [[package]] name = "overload" version = "0.1.1" @@ -3889,7 +3877,6 @@ dependencies = [ "libc", "rand_chacha", "rand_core", - "serde", ] [[package]] @@ -3909,7 +3896,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", - "serde", ] [[package]] diff --git a/packages/rs-dpp/Cargo.toml b/packages/rs-dpp/Cargo.toml index b8981e1d0b5..22026c57cee 100644 --- a/packages/rs-dpp/Cargo.toml +++ b/packages/rs-dpp/Cargo.toml @@ -14,7 +14,6 @@ authors = [ [dependencies] anyhow = { version = "1.0.81" } async-trait = { version = "0.1.79" } -ordered-float = { version = "4.6.0", features = ["serde"] } base64 = "0.22.1" bs58 = "0.5" byteorder = { version = "1.4" }