diff --git a/Cargo.lock b/Cargo.lock index 19c63f23809..30e74e18ff9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1307,6 +1307,7 @@ dependencies = [ name = "dash-sdk" version = "1.0.0-dev.15" dependencies = [ + "arc-swap", "async-trait", "base64 0.22.0", "bincode 2.0.0-rc.3", @@ -1327,6 +1328,7 @@ dependencies = [ "hex", "http 0.2.12", "lru", + "pollster", "rs-dapi-client", "sanitize-filename", "serde", @@ -3657,6 +3659,12 @@ dependencies = [ "windows-sys 0.48.0", ] +[[package]] +name = "pollster" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22686f4785f02a4fcc856d3b3bb19bf6c8160d103f7a99cc258bddd0251dc7f2" + [[package]] name = "portable-atomic" version = "1.6.0" diff --git a/packages/rs-sdk/Cargo.toml b/packages/rs-sdk/Cargo.toml index e514de10925..1c662f7be62 100644 --- a/packages/rs-sdk/Cargo.toml +++ b/packages/rs-sdk/Cargo.toml @@ -4,6 +4,7 @@ version = "1.0.0-dev.15" edition = "2021" [dependencies] +arc-swap = { version = "1.7.1" } dpp = { path = "../rs-dpp", default-features = false, features = [ "dash-sdk-features", ] } @@ -34,7 +35,7 @@ derive_more = { version = "0.99.17" } dashcore-rpc = { git = "https://github.com/dashpay/rust-dashcore-rpc", tag = "v0.15.2" } lru = { version = "0.12.3", optional = true } bip37-bloom-filter = { git = "https://github.com/dashpay/rs-bip37-bloom-filter", branch = "develop" } - +pollster = { version = "0.3.0" } [dev-dependencies] tokio = { version = "1.36.0", features = ["macros", "rt-multi-thread"] } diff --git a/packages/rs-sdk/src/mock/provider.rs b/packages/rs-sdk/src/mock/provider.rs index aa5c6f1a666..0efe92986d5 100644 --- a/packages/rs-sdk/src/mock/provider.rs +++ b/packages/rs-sdk/src/mock/provider.rs @@ -1,16 +1,16 @@ //! Example ContextProvider that uses the Core gRPC API to fetch data from the platform. -use std::hash::Hash; -use std::num::NonZeroUsize; -use std::sync::Arc; - -use dpp::prelude::{DataContract, Identifier}; -use drive_proof_verifier::error::ContextProviderError; -use drive_proof_verifier::ContextProvider; - use crate::core_client::CoreClient; use crate::platform::Fetch; use crate::{Error, Sdk}; +use arc_swap::ArcSwapAny; +use dpp::prelude::{DataContract, Identifier}; +use drive_proof_verifier::error::ContextProviderError; +use drive_proof_verifier::ContextProvider; +use pollster::FutureExt; +use std::hash::Hash; +use std::num::NonZeroUsize; +use std::sync::Arc; /// Context provider that uses the Core gRPC API to fetch data from the platform. /// @@ -24,7 +24,7 @@ pub struct GrpcContextProvider { /// values set by the user in the caches: `data_contracts_cache`, `quorum_public_keys_cache`. /// /// We use [Arc] as we have circular dependencies between Sdk and ContextProvider. - sdk: Option, + sdk: ArcSwapAny>>, /// Data contracts cache. /// @@ -65,7 +65,7 @@ impl GrpcContextProvider { let core_client = CoreClient::new(core_ip, core_port, core_user, core_password)?; Ok(Self { core: core_client, - sdk, + sdk: ArcSwapAny::new(Arc::new(sdk)), data_contracts_cache: Cache::new(data_contracts_cache_size), quorum_public_keys_cache: Cache::new(quorum_public_keys_cache_size), #[cfg(feature = "mocks")] @@ -78,8 +78,8 @@ impl GrpcContextProvider { /// /// Note that if the `sdk` is `None`, the context provider will not be able to fetch data itself and will rely on /// values set by the user in the caches: `data_contracts_cache`, `quorum_public_keys_cache`. - pub fn set_sdk(&mut self, sdk: Option) { - self.sdk = sdk; + pub fn set_sdk(&self, sdk: Option) { + self.sdk.store(Arc::new(sdk)); } /// Set the directory where to store dumped data. /// @@ -157,8 +157,10 @@ impl ContextProvider for GrpcContextProvider { if let Some(contract) = self.data_contracts_cache.get(data_contract_id) { return Ok(Some(contract)); }; + // let sdk_guard = self.sdk.read().expect("lock poisoned"); + let sdk_guard = self.sdk.load(); - let sdk = match &self.sdk { + let sdk = match sdk_guard.as_ref() { Some(sdk) => sdk, None => { tracing::warn!("data contract cache miss and no sdk provided, skipping fetch"); @@ -166,20 +168,11 @@ impl ContextProvider for GrpcContextProvider { } }; - let handle = match tokio::runtime::Handle::try_current() { - Ok(handle) => handle, - // not an error, we rely on the caller to provide a data contract using - Err(e) => { - tracing::warn!( - error = e.to_string(), - "data contract cache miss and no tokio runtime detected, skipping fetch" - ); - return Ok(None); - } - }; + let contract_id = *data_contract_id; + let sdk_cloned = sdk.clone(); - let data_contract = handle - .block_on(DataContract::fetch(sdk, *data_contract_id)) + let data_contract: Option = DataContract::fetch(&sdk_cloned, contract_id) + .block_on() .map_err(|e| ContextProviderError::InvalidDataContract(e.to_string()))?; if let Some(ref dc) = data_contract { diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index bf3618fa754..12f1ddbf2e6 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -707,15 +707,18 @@ impl SdkBuilder { tracing::warn!("ContextProvider not set; mocking with Dash Core. \ Please provide your own ContextProvider with SdkBuilder::with_context_provider()."); - let mut context_provider = GrpcContextProvider::new(Some(sdk.clone()), - &self.core_ip, self.core_port, &self.core_user, &self.core_password, - self.data_contract_cache_size, self.quorum_public_keys_cache_size)?; + let mut context_provider = GrpcContextProvider::new(None, + &self.core_ip, self.core_port, &self.core_user, &self.core_password, + self.data_contract_cache_size, self.quorum_public_keys_cache_size)?; #[cfg(feature = "mocks")] if sdk.dump_dir.is_some() { context_provider.set_dump_dir(sdk.dump_dir.clone()); } - - sdk.context_provider.replace(Arc::new(Box::new(context_provider))); + // We have cyclical dependency Sdk <-> GrpcContextProvider, so we just do some + // workaround using additional Arc. + let context_provider=Arc::new(context_provider); + sdk.context_provider.replace(Arc::new(Box::new(context_provider.clone()))); + context_provider.set_sdk(Some(sdk.clone())); } else{ tracing::warn!( "Configure ContextProvider with Sdk::with_context_provider(); otherwise Sdk will fail"); diff --git a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs index 8a8b1b9b894..b1e27fad740 100644 --- a/packages/wasm-dpp/src/errors/consensus/consensus_error.rs +++ b/packages/wasm-dpp/src/errors/consensus/consensus_error.rs @@ -149,6 +149,12 @@ pub fn from_consensus_error_ref(e: &DPPConsensusError) -> JsValue { DPPConsensusError::StateError(state_error) => from_state_error(state_error), DPPConsensusError::BasicError(basic_error) => from_basic_error(basic_error), DPPConsensusError::DefaultError => JsError::new("DefaultError").into(), + #[cfg(test)] + e => todo!( + "ConsensusError {} not implemented: {}", + std::any::type_name_of_val(e), + e + ), } }