diff --git a/Cargo.lock b/Cargo.lock index 2f6a8b40374..24a727c3837 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4317,7 +4317,6 @@ version = "3.0.0" dependencies = [ "bincode", "grovedb-version", - "once_cell", "thiserror 2.0.17", "versioned-feature-core 1.0.0 (git+https://github.com/dashpay/versioned-feature-core)", ] diff --git a/packages/js-evo-sdk/src/sdk.ts b/packages/js-evo-sdk/src/sdk.ts index e1ea8049a34..9ef153e010a 100644 --- a/packages/js-evo-sdk/src/sdk.ts +++ b/packages/js-evo-sdk/src/sdk.ts @@ -69,7 +69,9 @@ export class EvoSDK { } get wasm(): wasm.WasmSdk { - if (!this.wasmSdk) throw new Error('SDK is not connected. Call EvoSDK#connect() first.'); + if (!this.wasmSdk) { + throw new Error('SDK is not connected. Call EvoSDK#connect() first.'); + } return this.wasmSdk; } @@ -83,47 +85,63 @@ export class EvoSDK { } async connect(): Promise { - if (this.wasmSdk) return; // idempotent + if (this.wasmSdk) { + return; // idempotent + } await initWasm(); const { network, trusted, version, proofs, settings, logs, addresses } = this.options; - let builder: wasm.WasmSdkBuilder; - - // If specific addresses are provided, use them instead of network presets - if (addresses && addresses.length > 0) { - // Prefetch trusted quorums for the network before creating builder with addresses + // Prefetch trusted context only when trusted mode is requested + let context: wasm.WasmTrustedContext | undefined; + if (trusted) { if (network === 'mainnet') { - await wasm.WasmSdk.prefetchTrustedQuorumsMainnet(); + context = await wasm.WasmTrustedContext.prefetchMainnet(); } else if (network === 'testnet') { - await wasm.WasmSdk.prefetchTrustedQuorumsTestnet(); + context = await wasm.WasmTrustedContext.prefetchTestnet(); } else if (network === 'local') { - await wasm.WasmSdk.prefetchTrustedQuorumsLocal(); + context = await wasm.WasmTrustedContext.prefetchLocal(); + } else { + throw new Error(`Unknown network: ${network}`); } + } + + let builder: wasm.WasmSdkBuilder; + + if (addresses && addresses.length > 0) { builder = wasm.WasmSdkBuilder.withAddresses(addresses, network); } else if (network === 'mainnet') { - await wasm.WasmSdk.prefetchTrustedQuorumsMainnet(); - - builder = trusted ? wasm.WasmSdkBuilder.mainnetTrusted() : wasm.WasmSdkBuilder.mainnet(); + builder = wasm.WasmSdkBuilder.mainnet(); } else if (network === 'testnet') { - await wasm.WasmSdk.prefetchTrustedQuorumsTestnet(); - - builder = trusted ? wasm.WasmSdkBuilder.testnetTrusted() : wasm.WasmSdkBuilder.testnet(); + builder = wasm.WasmSdkBuilder.testnet(); } else if (network === 'local') { - // Default local dashmate gateway and quorum list sidecar - await wasm.WasmSdk.prefetchTrustedQuorumsLocal(); - - builder = trusted ? wasm.WasmSdkBuilder.localTrusted() : wasm.WasmSdkBuilder.local(); + builder = wasm.WasmSdkBuilder.local(); } else { throw new Error(`Unknown network: ${network}`); } - if (version) builder = builder.withVersion(version); - if (typeof proofs === 'boolean') builder = builder.withProofs(proofs); - if (logs) builder = builder.withLogs(logs); + // Attach trusted context for proof verification and discovered addresses + if (context) { + builder = builder.withTrustedContext(context); + } + + if (version) { + builder = builder.withVersion(version); + } + if (typeof proofs === 'boolean') { + builder = builder.withProofs(proofs); + } + if (logs) { + builder = builder.withLogs(logs); + } if (settings) { const { connectTimeoutMs, timeoutMs, retries, banFailedAddress } = settings; - builder = builder.withSettings(connectTimeoutMs ?? null, timeoutMs ?? null, retries ?? null, banFailedAddress ?? null); + builder = builder.withSettings( + connectTimeoutMs ?? null, + timeoutMs ?? null, + retries ?? null, + banFailedAddress ?? null, + ); } this.wasmSdk = builder.build(); diff --git a/packages/js-evo-sdk/tests/unit/facades/addresses.spec.ts b/packages/js-evo-sdk/tests/unit/facades/addresses.spec.ts index 8dedc931098..145d86192a4 100644 --- a/packages/js-evo-sdk/tests/unit/facades/addresses.spec.ts +++ b/packages/js-evo-sdk/tests/unit/facades/addresses.spec.ts @@ -15,7 +15,7 @@ describe('AddressesFacade', () => { beforeEach(async function setup() { await init(); - const builder = wasmSDKPackage.WasmSdkBuilder.testnetTrusted(); + const builder = wasmSDKPackage.WasmSdkBuilder.testnet(); wasmSdk = await builder.build(); client = EvoSDK.fromWasm(wasmSdk); diff --git a/packages/js-evo-sdk/tests/unit/facades/contracts.spec.ts b/packages/js-evo-sdk/tests/unit/facades/contracts.spec.ts index fab1c8f379b..fb97a15e323 100644 --- a/packages/js-evo-sdk/tests/unit/facades/contracts.spec.ts +++ b/packages/js-evo-sdk/tests/unit/facades/contracts.spec.ts @@ -21,7 +21,7 @@ describe('ContractsFacade', () => { beforeEach(async function setup() { await init(); - const builder = wasmSDKPackage.WasmSdkBuilder.testnetTrusted(); + const builder = wasmSDKPackage.WasmSdkBuilder.testnet(); wasmSdk = await builder.build(); client = EvoSDK.fromWasm(wasmSdk); diff --git a/packages/js-evo-sdk/tests/unit/facades/documents.spec.ts b/packages/js-evo-sdk/tests/unit/facades/documents.spec.ts index 57f6728d83e..0b290cb29e5 100644 --- a/packages/js-evo-sdk/tests/unit/facades/documents.spec.ts +++ b/packages/js-evo-sdk/tests/unit/facades/documents.spec.ts @@ -23,7 +23,7 @@ describe('DocumentsFacade', () => { beforeEach(async function setup() { await init(); - const builder = wasmSDKPackage.WasmSdkBuilder.testnetTrusted(); + const builder = wasmSDKPackage.WasmSdkBuilder.testnet(); wasmSdk = await builder.build(); client = EvoSDK.fromWasm(wasmSdk); diff --git a/packages/js-evo-sdk/tests/unit/facades/dpns.spec.ts b/packages/js-evo-sdk/tests/unit/facades/dpns.spec.ts index 92e833cd4f1..94891941d7e 100644 --- a/packages/js-evo-sdk/tests/unit/facades/dpns.spec.ts +++ b/packages/js-evo-sdk/tests/unit/facades/dpns.spec.ts @@ -19,7 +19,7 @@ describe('DPNSFacade', () => { beforeEach(async function setup() { await init(); - const builder = wasmSDKPackage.WasmSdkBuilder.testnetTrusted(); + const builder = wasmSDKPackage.WasmSdkBuilder.testnet(); wasmSdk = await builder.build(); client = EvoSDK.fromWasm(wasmSdk); diff --git a/packages/js-evo-sdk/tests/unit/facades/epoch.spec.ts b/packages/js-evo-sdk/tests/unit/facades/epoch.spec.ts index 0c6c2026071..31ac4d57685 100644 --- a/packages/js-evo-sdk/tests/unit/facades/epoch.spec.ts +++ b/packages/js-evo-sdk/tests/unit/facades/epoch.spec.ts @@ -20,7 +20,7 @@ describe('EpochFacade', () => { beforeEach(async function setup() { await init(); - const builder = wasmSDKPackage.WasmSdkBuilder.testnetTrusted(); + const builder = wasmSDKPackage.WasmSdkBuilder.testnet(); wasmSdk = await builder.build(); client = EvoSDK.fromWasm(wasmSdk); diff --git a/packages/js-evo-sdk/tests/unit/facades/group.spec.ts b/packages/js-evo-sdk/tests/unit/facades/group.spec.ts index 9e60e4a539d..788fb2bda0f 100644 --- a/packages/js-evo-sdk/tests/unit/facades/group.spec.ts +++ b/packages/js-evo-sdk/tests/unit/facades/group.spec.ts @@ -28,7 +28,7 @@ describe('GroupFacade', () => { beforeEach(async function setup() { await init(); - const builder = wasmSDKPackage.WasmSdkBuilder.testnetTrusted(); + const builder = wasmSDKPackage.WasmSdkBuilder.testnet(); wasmSdk = await builder.build(); client = EvoSDK.fromWasm(wasmSdk); diff --git a/packages/js-evo-sdk/tests/unit/facades/identities.spec.ts b/packages/js-evo-sdk/tests/unit/facades/identities.spec.ts index 401e76e79f6..75e8a494956 100644 --- a/packages/js-evo-sdk/tests/unit/facades/identities.spec.ts +++ b/packages/js-evo-sdk/tests/unit/facades/identities.spec.ts @@ -32,6 +32,7 @@ describe('IdentitiesFacade', () => { let getIdentityByNonUniquePublicKeyHashStub: SinonStub; let getIdentityByNonUniquePublicKeyHashWithProofInfoStub: SinonStub; let getIdentitiesContractKeysStub: SinonStub; + // eslint-disable-next-line @typescript-eslint/no-unused-vars let getIdentitiesContractKeysWithProofInfoStub: SinonStub; let getIdentityTokenBalancesStub: SinonStub; let getIdentityTokenBalancesWithProofInfoStub: SinonStub; @@ -43,7 +44,7 @@ describe('IdentitiesFacade', () => { beforeEach(async function setup() { await init(); - const builder = wasmSDKPackage.WasmSdkBuilder.testnetTrusted(); + const builder = wasmSDKPackage.WasmSdkBuilder.testnet(); wasmSdk = await builder.build(); client = EvoSDK.fromWasm(wasmSdk); @@ -75,7 +76,8 @@ describe('IdentitiesFacade', () => { metadata: {}, }); getIdentityContractNonceStub = this.sinon.stub(wasmSdk, 'getIdentityContractNonce').resolves(BigInt(0)); - getIdentityContractNonceWithProofInfoStub = this.sinon.stub(wasmSdk, 'getIdentityContractNonceWithProofInfo').resolves({ + getIdentityContractNonceWithProofInfoStub = this.sinon + .stub(wasmSdk, 'getIdentityContractNonceWithProofInfo').resolves({ data: BigInt(0), proof: {}, metadata: {}, @@ -109,7 +111,8 @@ describe('IdentitiesFacade', () => { proof: {}, metadata: {}, }); - getIdentityByNonUniquePublicKeyHashStub = this.sinon.stub(wasmSdk, 'getIdentityByNonUniquePublicKeyHash').resolves([]); + getIdentityByNonUniquePublicKeyHashStub = this.sinon + .stub(wasmSdk, 'getIdentityByNonUniquePublicKeyHash').resolves([]); getIdentityByNonUniquePublicKeyHashWithProofInfoStub = this.sinon .stub(wasmSdk, 'getIdentityByNonUniquePublicKeyHashWithProofInfo').resolves({ data: [], @@ -124,7 +127,8 @@ describe('IdentitiesFacade', () => { metadata: {}, }); getIdentityTokenBalancesStub = this.sinon.stub(wasmSdk, 'getIdentityTokenBalances').resolves(new Map()); - getIdentityTokenBalancesWithProofInfoStub = this.sinon.stub(wasmSdk, 'getIdentityTokenBalancesWithProofInfo').resolves({ + getIdentityTokenBalancesWithProofInfoStub = this.sinon + .stub(wasmSdk, 'getIdentityTokenBalancesWithProofInfo').resolves({ data: new Map(), proof: {}, metadata: {}, diff --git a/packages/js-evo-sdk/tests/unit/facades/protocol.spec.ts b/packages/js-evo-sdk/tests/unit/facades/protocol.spec.ts index 9f54fb348a3..80130053df7 100644 --- a/packages/js-evo-sdk/tests/unit/facades/protocol.spec.ts +++ b/packages/js-evo-sdk/tests/unit/facades/protocol.spec.ts @@ -14,7 +14,7 @@ describe('ProtocolFacade', () => { beforeEach(async function setup() { await init(); - const builder = wasmSDKPackage.WasmSdkBuilder.testnetTrusted(); + const builder = wasmSDKPackage.WasmSdkBuilder.testnet(); wasmSdk = await builder.build(); client = EvoSDK.fromWasm(wasmSdk); diff --git a/packages/js-evo-sdk/tests/unit/facades/system.spec.ts b/packages/js-evo-sdk/tests/unit/facades/system.spec.ts index d7cc688eb40..c8c179cf36f 100644 --- a/packages/js-evo-sdk/tests/unit/facades/system.spec.ts +++ b/packages/js-evo-sdk/tests/unit/facades/system.spec.ts @@ -19,7 +19,7 @@ describe('SystemFacade', () => { beforeEach(async function setup() { await init(); - const builder = wasmSDKPackage.WasmSdkBuilder.testnetTrusted(); + const builder = wasmSDKPackage.WasmSdkBuilder.testnet(); wasmSdk = await builder.build(); client = EvoSDK.fromWasm(wasmSdk); diff --git a/packages/js-evo-sdk/tests/unit/facades/tokens.spec.ts b/packages/js-evo-sdk/tests/unit/facades/tokens.spec.ts index bf7cc0e9079..d185cad8eb9 100644 --- a/packages/js-evo-sdk/tests/unit/facades/tokens.spec.ts +++ b/packages/js-evo-sdk/tests/unit/facades/tokens.spec.ts @@ -47,7 +47,7 @@ describe('TokensFacade', () => { beforeEach(async function setup() { await init(); - const builder = wasmSDKPackage.WasmSdkBuilder.testnetTrusted(); + const builder = wasmSDKPackage.WasmSdkBuilder.testnet(); wasmSdk = await builder.build(); client = EvoSDK.fromWasm(wasmSdk); diff --git a/packages/js-evo-sdk/tests/unit/facades/voting.spec.ts b/packages/js-evo-sdk/tests/unit/facades/voting.spec.ts index ed164fa03c7..d3fed61c549 100644 --- a/packages/js-evo-sdk/tests/unit/facades/voting.spec.ts +++ b/packages/js-evo-sdk/tests/unit/facades/voting.spec.ts @@ -24,7 +24,7 @@ describe('VotingFacade', () => { beforeEach(async function setup() { await init(); - const builder = wasmSDKPackage.WasmSdkBuilder.testnetTrusted(); + const builder = wasmSDKPackage.WasmSdkBuilder.testnet(); wasmSdk = await builder.build(); client = EvoSDK.fromWasm(wasmSdk); diff --git a/packages/rs-platform-version/Cargo.toml b/packages/rs-platform-version/Cargo.toml index 16ad29dab03..f7b7e5d2e8b 100644 --- a/packages/rs-platform-version/Cargo.toml +++ b/packages/rs-platform-version/Cargo.toml @@ -12,7 +12,6 @@ thiserror = { version = "2.0.12" } bincode = { version = "=2.0.1" } versioned-feature-core = { git = "https://github.com/dashpay/versioned-feature-core", version = "1.0.0" } grovedb-version = { git = "https://github.com/dashpay/grovedb", rev = "33dfd48a1718160cb333fa95424be491785f1897" } -once_cell = "1.19.0" [features] mock-versions = [] diff --git a/packages/rs-sdk/src/sdk.rs b/packages/rs-sdk/src/sdk.rs index 235cdcc3bce..f8e5eefa84f 100644 --- a/packages/rs-sdk/src/sdk.rs +++ b/packages/rs-sdk/src/sdk.rs @@ -889,6 +889,12 @@ impl SdkBuilder { } } + /// Replace the address list on this builder. + pub fn with_address_list(mut self, addresses: AddressList) -> Self { + self.addresses = Some(addresses); + self + } + /// Create a new SdkBuilder that will generate mock client. pub fn new_mock() -> Self { Self::default() diff --git a/packages/simple-signer/Cargo.toml b/packages/simple-signer/Cargo.toml index 4768cb05f6c..d4817d32a91 100644 --- a/packages/simple-signer/Cargo.toml +++ b/packages/simple-signer/Cargo.toml @@ -16,10 +16,13 @@ state-transitions = [ ] [dependencies] -bincode = { version = "=2.0.1", features = ["serde"] } dpp = { path = "../rs-dpp", default-features = false, features = [ "ed25519-dalek", ] } +bincode = { version = "=2.0.1", features = ["serde"] } base64 = { version = "0.22.1" } hex = { version = "0.4.3" } tracing = "0.1.41" + +[package.metadata.cargo-machete] +ignored = ["bincode"] diff --git a/packages/wasm-sdk/src/context_provider.rs b/packages/wasm-sdk/src/context_provider.rs index fc4b1b74b91..3bf5ce0fc6f 100644 --- a/packages/wasm-sdk/src/context_provider.rs +++ b/packages/wasm-sdk/src/context_provider.rs @@ -8,14 +8,23 @@ use dash_sdk::{ }; use wasm_bindgen::prelude::wasm_bindgen; +use crate::error::WasmSdkError; + #[wasm_bindgen] #[derive(Clone)] pub struct WasmContext {} -/// A wrapper for TrustedHttpContextProvider that works in WASM +/// A wrapper for TrustedHttpContextProvider that works in WASM. +/// +/// Holds pre-fetched quorum keys and discovered masternode addresses for +/// proof verification and network connectivity. Create one via the async +/// `prefetchMainnet()`, `prefetchTestnet()`, or `prefetchLocal()` factory +/// methods, then pass it to a builder via `withTrustedContext()`. +#[wasm_bindgen] #[derive(Clone)] pub struct WasmTrustedContext { inner: std::sync::Arc, + discovered_addresses: Vec, } impl ContextProvider for WasmContext { @@ -46,11 +55,9 @@ impl ContextProvider for WasmContext { // For WASM context without trusted provider, we need to fetch token configuration // from the network. This is a simplified implementation that would need to be // enhanced with actual network fetching logic in a production environment. - // TODO: Implement actual token configuration fetching from network // For now, we'll return None which will cause the proof verification to fail // with a clearer error message indicating missing token configuration - tracing::warn!( token_id = %token_id, "Token configuration not available in WASM context - this will cause proof verification to fail. Use trusted context builders for proof verification." @@ -98,82 +105,135 @@ impl ContextProvider for WasmTrustedContext { } } +// JS-exported async factory methods +#[wasm_bindgen] impl WasmTrustedContext { - pub fn new_mainnet() -> Result { + /// Pre-fetch quorum keys and masternode addresses for mainnet. + /// + /// Returns a ready-to-use `WasmTrustedContext` that can be passed to + /// `WasmSdkBuilder.mainnet().withTrustedContext(context)`. + #[wasm_bindgen(js_name = "prefetchMainnet")] + pub async fn prefetch_mainnet() -> Result { let inner = rs_sdk_trusted_context_provider::TrustedHttpContextProvider::new( dash_sdk::dpp::dashcore::Network::Dash, None, std::num::NonZeroUsize::new(100).unwrap(), ) - .map_err(|e| ContextProviderError::Generic(e.to_string()))? - .with_refetch_if_not_found(false); // Disable refetch since we'll pre-fetch + .map_err(|e| WasmSdkError::generic(format!("Failed to create context provider: {}", e)))? + .with_refetch_if_not_found(false); - Ok(Self { - inner: std::sync::Arc::new(inner), + let inner = Arc::new(inner); + + inner + .update_quorum_caches() + .await + .map_err(|e| WasmSdkError::generic(format!("Failed to prefetch quorums: {}", e)))?; + + let discovered_addresses = Self::fetch_addresses_from(&inner).await?; + + Ok(WasmTrustedContext { + inner, + discovered_addresses, }) } - pub fn new_testnet() -> Result { + /// Pre-fetch quorum keys and masternode addresses for testnet. + /// + /// Returns a ready-to-use `WasmTrustedContext` that can be passed to + /// `WasmSdkBuilder.testnet().withTrustedContext(context)`. + #[wasm_bindgen(js_name = "prefetchTestnet")] + pub async fn prefetch_testnet() -> Result { let inner = rs_sdk_trusted_context_provider::TrustedHttpContextProvider::new( dash_sdk::dpp::dashcore::Network::Testnet, None, std::num::NonZeroUsize::new(100).unwrap(), ) - .map_err(|e| ContextProviderError::Generic(e.to_string()))? - .with_refetch_if_not_found(false); // Disable refetch since we'll pre-fetch + .map_err(|e| WasmSdkError::generic(format!("Failed to create context provider: {}", e)))? + .with_refetch_if_not_found(false); + + let inner = Arc::new(inner); - Ok(Self { - inner: std::sync::Arc::new(inner), + inner + .update_quorum_caches() + .await + .map_err(|e| WasmSdkError::generic(format!("Failed to prefetch quorums: {}", e)))?; + + let discovered_addresses = Self::fetch_addresses_from(&inner).await?; + + Ok(WasmTrustedContext { + inner, + discovered_addresses, }) } - pub fn new_local() -> Result { - Self::new_local_with_url("http://127.0.0.1:2444") + /// Pre-fetch quorum keys and masternode addresses for a local network. + /// + /// Uses the default local quorum sidecar URL (`http://127.0.0.1:2444`). + /// + /// Returns a ready-to-use `WasmTrustedContext` that can be passed to + /// `WasmSdkBuilder.local().withTrustedContext(context)`. + #[wasm_bindgen(js_name = "prefetchLocal")] + pub async fn prefetch_local() -> Result { + Self::prefetch_local_with_url("http://127.0.0.1:2444").await } - pub fn new_local_with_url(base_url: &str) -> Result { + /// Pre-fetch quorum keys and masternode addresses for a local network + /// using a custom quorum sidecar URL. + #[wasm_bindgen(js_name = "prefetchLocalWithUrl")] + pub async fn prefetch_local_with_url( + base_url: &str, + ) -> Result { let inner = rs_sdk_trusted_context_provider::TrustedHttpContextProvider::new_with_url( dash_sdk::dpp::dashcore::Network::Regtest, base_url.to_string(), std::num::NonZeroUsize::new(100).unwrap(), ) - .map_err(|e| ContextProviderError::Generic(e.to_string()))? + .map_err(|e| WasmSdkError::generic(format!("Failed to create context provider: {}", e)))? .with_refetch_if_not_found(false); - Ok(Self { - inner: std::sync::Arc::new(inner), - }) - } + let inner = Arc::new(inner); + + inner + .update_quorum_caches() + .await + .map_err(|e| WasmSdkError::generic(format!("Failed to prefetch quorums: {}", e)))?; + + let discovered_addresses = Self::fetch_addresses_from(&inner).await?; - /// Pre-fetch quorum information to populate the cache - pub async fn prefetch_quorums(&self) -> Result<(), ContextProviderError> { - self.inner.update_quorum_caches().await.map_err(|e| { - ContextProviderError::Generic(format!("Failed to prefetch quorums: {}", e)) + Ok(WasmTrustedContext { + inner, + discovered_addresses, }) } +} - pub async fn fetch_masternode_addresses( - &self, - ) -> Result { - let urls = self.inner.fetch_masternode_addresses().await.map_err(|e| { - ContextProviderError::Generic(format!("Failed to fetch masternodes: {}", e)) - })?; +impl WasmTrustedContext { + /// Fetch masternode addresses from the trusted provider and convert to `Vec
`. + async fn fetch_addresses_from( + inner: &rs_sdk_trusted_context_provider::TrustedHttpContextProvider, + ) -> Result, WasmSdkError> { + let urls = inner + .fetch_masternode_addresses() + .await + .map_err(|e| WasmSdkError::generic(format!("Failed to fetch masternodes: {}", e)))?; let mut addresses = Vec::new(); for url in urls { let uri = dash_sdk::sdk::Uri::from_maybe_shared(url.to_string()).map_err(|e| { - ContextProviderError::Generic(format!("Invalid masternode URI '{}': {}", url, e)) + WasmSdkError::generic(format!("Invalid masternode URI '{}': {}", url, e)) })?; let address = rs_dapi_client::Address::try_from(uri).map_err(|e| { - ContextProviderError::Generic(format!( - "Invalid masternode address '{}': {}", - url, e - )) + WasmSdkError::generic(format!("Invalid masternode address '{}': {}", url, e)) })?; addresses.push(address); } - Ok(rs_dapi_client::AddressList::from_iter(addresses)) + Ok(addresses) + } + + /// Get the discovered addresses (for use by the builder). + pub(crate) fn discovered_addresses(&self) -> &[rs_dapi_client::Address] { + &self.discovered_addresses } /// Add a data contract to the known contracts cache @@ -182,13 +242,11 @@ impl WasmTrustedContext { } /// Get a data contract from the known contracts cache - /// Returns None if the contract is not in the cache pub fn get_known_contract(&self, id: &Identifier) -> Option> { self.inner.get_known_contract(id) } /// Remove a data contract from the known contracts cache - /// Returns true if the contract was present and removed, false otherwise pub fn remove_known_contract(&self, id: &Identifier) -> bool { self.inner.remove_known_contract(id) } diff --git a/packages/wasm-sdk/src/queries/token.rs b/packages/wasm-sdk/src/queries/token.rs index a7bb8b68aad..56aec9c64ff 100644 --- a/packages/wasm-sdk/src/queries/token.rs +++ b/packages/wasm-sdk/src/queries/token.rs @@ -881,27 +881,16 @@ impl WasmSdk { &self, token_id: Identifier, ) -> Result<(), WasmSdkError> { - use crate::sdk::{LOCAL_TRUSTED_CONTEXT, MAINNET_TRUSTED_CONTEXT, TESTNET_TRUSTED_CONTEXT}; - use dash_sdk::dpp::dashcore::Network; use dash_sdk::dpp::data_contract::accessors::v1::DataContractV1Getters; use dash_sdk::dpp::tokens::contract_info::v0::TokenContractInfoV0Accessors; use dash_sdk::dpp::tokens::contract_info::TokenContractInfo; - // Step 1: Check trusted context is initialized before doing any network fetches - let network = self.network(); - let context_initialized = match network { - Network::Dash => MAINNET_TRUSTED_CONTEXT.lock().unwrap().is_some(), - Network::Testnet => TESTNET_TRUSTED_CONTEXT.lock().unwrap().is_some(), - Network::Regtest => LOCAL_TRUSTED_CONTEXT.lock().unwrap().is_some(), - _ => false, - }; - - if !context_initialized { - return Err(WasmSdkError::generic(format!( - "Trusted context not initialized for network {:?}. Call prefetch methods first.", - network - ))); - } + // Step 1: Verify trusted context is available + let trusted_context = self.trusted_context().ok_or_else(|| { + WasmSdkError::generic( + "Trusted context not initialized. Use a trusted builder with a prefetched cache.", + ) + })?; // Step 2: Fetch TokenContractInfo to get contract_id and position let token_contract_info = TokenContractInfo::fetch(self.as_ref(), token_id) @@ -931,31 +920,7 @@ impl WasmSdk { .clone(); // Step 5: Add the token configuration to the trusted context cache - // We already verified the context is initialized above, so unwrap is safe - match network { - Network::Dash => { - let guard = MAINNET_TRUSTED_CONTEXT.lock().unwrap(); - guard - .as_ref() - .unwrap() - .add_known_token_configuration(token_id, token_configuration); - } - Network::Testnet => { - let guard = TESTNET_TRUSTED_CONTEXT.lock().unwrap(); - guard - .as_ref() - .unwrap() - .add_known_token_configuration(token_id, token_configuration); - } - Network::Regtest => { - let guard = LOCAL_TRUSTED_CONTEXT.lock().unwrap(); - guard - .as_ref() - .unwrap() - .add_known_token_configuration(token_id, token_configuration); - } - _ => unreachable!(), // Already checked above - } + trusted_context.add_known_token_configuration(token_id, token_configuration); Ok(()) } diff --git a/packages/wasm-sdk/src/sdk.rs b/packages/wasm-sdk/src/sdk.rs index 4b07b611300..d5ac6e243bc 100644 --- a/packages/wasm-sdk/src/sdk.rs +++ b/packages/wasm-sdk/src/sdk.rs @@ -3,25 +3,11 @@ use crate::error::WasmSdkError; use dash_sdk::dpp::version::PlatformVersion; use dash_sdk::sdk::Uri; use dash_sdk::{Sdk, SdkBuilder}; -use once_cell::sync::Lazy; use rs_dapi_client::{Address, RequestSettings}; use std::ops::{Deref, DerefMut}; -use std::sync::Mutex; use std::time::Duration; use wasm_bindgen::prelude::wasm_bindgen; -pub(crate) static MAINNET_TRUSTED_CONTEXT: Lazy>> = - Lazy::new(|| Mutex::new(None)); -pub(crate) static TESTNET_TRUSTED_CONTEXT: Lazy>> = - Lazy::new(|| Mutex::new(None)); -pub(crate) static LOCAL_TRUSTED_CONTEXT: Lazy>> = - Lazy::new(|| Mutex::new(None)); -const DEFAULT_LOCAL_QUORUM_URL: &str = "http://127.0.0.1:2444"; -static MAINNET_DISCOVERED_ADDRESSES: Lazy>>> = - Lazy::new(|| Mutex::new(None)); -static TESTNET_DISCOVERED_ADDRESSES: Lazy>>> = - Lazy::new(|| Mutex::new(None)); -static LOCAL_DISCOVERED_ADDRESSES: Lazy>>> = - Lazy::new(|| Mutex::new(None)); + fn parse_addresses(addresses: &'static [&str]) -> Vec
{ addresses .iter() @@ -32,8 +18,8 @@ fn parse_addresses(addresses: &'static [&str]) -> Vec
{ }) .collect() } +// Mainnet addresses from mnowatch.org fn default_mainnet_addresses() -> Vec
{ - // Trimmed seed list to keep bundle size small; used only if no prefetched cache is available. parse_addresses(&[ "https://149.28.241.190:443", "https://198.7.115.48:443", @@ -42,6 +28,7 @@ fn default_mainnet_addresses() -> Vec
{ "https://5.189.164.253:443", ]) } +// Testnet addresses from https://quorums.testnet.networks.dash.org/masternodes fn default_testnet_addresses() -> Vec
{ parse_addresses(&[ "https://52.12.176.90:1443", @@ -57,91 +44,52 @@ fn default_testnet_addresses() -> Vec
{ fn default_local_addresses() -> Vec
{ parse_addresses(&["https://127.0.0.1:2443"]) } -async fn fetch_and_cache_addresses( - trusted_context: &WasmTrustedContext, - cache: &Lazy>>>, -) -> Result<(), WasmSdkError> { - let address_list = trusted_context - .fetch_masternode_addresses() - .await - .map_err(|e| WasmSdkError::generic(format!("Failed to fetch masternodes: {}", e)))?; - let addresses: Vec
= address_list - .into_iter() - .map(|(addr, _status)| addr) - .collect(); - *cache.lock().unwrap() = Some(addresses); - Ok(()) -} #[wasm_bindgen] -pub struct WasmSdk(Sdk); -// Dereference JsSdk to Sdk so that we can use &JsSdk everywhere where &sdk is needed -impl std::ops::Deref for WasmSdk { +pub struct WasmSdk { + sdk: Sdk, + trusted_context: Option, +} + +// Dereference WasmSdk to Sdk so that we can use &WasmSdk everywhere where &Sdk is needed +impl Deref for WasmSdk { type Target = Sdk; fn deref(&self) -> &Self::Target { - &self.0 + &self.sdk } } impl AsRef for WasmSdk { fn as_ref(&self) -> &Sdk { - &self.0 - } -} - -impl From for WasmSdk { - fn from(sdk: Sdk) -> Self { - WasmSdk(sdk) + &self.sdk } } #[wasm_bindgen] impl WasmSdk { pub fn version(&self) -> u32 { - self.0.version().protocol_version + self.sdk.version().protocol_version } /// Get reference to the inner SDK for direct gRPC calls pub(crate) fn inner_sdk(&self) -> &Sdk { - &self.0 + &self.sdk } - /// Get the network this SDK is configured for - pub(crate) fn network(&self) -> dash_sdk::dpp::dashcore::Network { - self.0.network + /// Get a reference to the trusted context, if available + pub(crate) fn trusted_context(&self) -> Option<&WasmTrustedContext> { + self.trusted_context.as_ref() } } impl WasmSdk { /// Add a data contract to the context provider's cache. - /// This is needed so that subsequent operations (like document transitions) - /// can verify proofs that reference this contract. pub(crate) fn add_contract_to_context_cache( &self, contract: &dash_sdk::dpp::data_contract::DataContract, ) -> Result<(), crate::error::WasmSdkError> { - match self.network() { - dash_sdk::dpp::dashcore::Network::Testnet => { - let guard = TESTNET_TRUSTED_CONTEXT.lock().unwrap(); - if let Some(context) = guard.as_ref() { - context.add_known_contract(contract.clone()); - } - } - dash_sdk::dpp::dashcore::Network::Dash => { - let guard = MAINNET_TRUSTED_CONTEXT.lock().unwrap(); - if let Some(context) = guard.as_ref() { - context.add_known_contract(contract.clone()); - } - } - dash_sdk::dpp::dashcore::Network::Regtest => { - let guard = LOCAL_TRUSTED_CONTEXT.lock().unwrap(); - if let Some(context) = guard.as_ref() { - context.add_known_contract(contract.clone()); - } - } - _ => { - // Other networks don't use trusted context, so nothing to cache - } + if let Some(ref context) = self.trusted_context { + context.add_known_contract(contract.clone()); } Ok(()) } @@ -150,15 +98,9 @@ impl WasmSdk { #[wasm_bindgen] impl WasmSdk { /// Forces reload of the identity nonce from Platform on the next state transition. - /// - /// This clears the cached nonce for the given identity, ensuring that the next - /// state transition will fetch the current nonce from Platform instead of using - /// a potentially stale cached value. - /// - /// @param identityId - The identifier of the identity whose nonce cache should be cleared #[wasm_bindgen(js_name = "refreshIdentityNonce")] pub async fn refresh_identity_nonce(&self, identity_id: wasm_dpp2::identifier::IdentifierWasm) { - self.0.refresh_identity_nonce(&identity_id.into()).await; + self.sdk.refresh_identity_nonce(&identity_id.into()).await; } /// Get a cached contract from the trusted context if available @@ -166,112 +108,53 @@ impl WasmSdk { &self, contract_id: &dash_sdk::platform::Identifier, ) -> Option> { - match self.network() { - dash_sdk::dpp::dashcore::Network::Testnet => { - let guard = TESTNET_TRUSTED_CONTEXT.lock().unwrap(); - guard - .as_ref() - .and_then(|ctx| ctx.get_known_contract(contract_id)) - } - dash_sdk::dpp::dashcore::Network::Dash => { - let guard = MAINNET_TRUSTED_CONTEXT.lock().unwrap(); - guard - .as_ref() - .and_then(|ctx| ctx.get_known_contract(contract_id)) - } - dash_sdk::dpp::dashcore::Network::Regtest => { - let guard = LOCAL_TRUSTED_CONTEXT.lock().unwrap(); - guard - .as_ref() - .and_then(|ctx| ctx.get_known_contract(contract_id)) - } - _ => None, - } + self.trusted_context + .as_ref() + .and_then(|ctx| ctx.get_known_contract(contract_id)) } /// Cache a contract in the trusted context pub(crate) fn cache_contract(&self, contract: dash_sdk::platform::DataContract) { - match self.network() { - dash_sdk::dpp::dashcore::Network::Testnet => { - if let Some(ref context) = *TESTNET_TRUSTED_CONTEXT.lock().unwrap() { - context.add_known_contract(contract); - } - } - dash_sdk::dpp::dashcore::Network::Dash => { - if let Some(ref context) = *MAINNET_TRUSTED_CONTEXT.lock().unwrap() { - context.add_known_contract(contract); - } - } - dash_sdk::dpp::dashcore::Network::Regtest => { - if let Some(ref context) = *LOCAL_TRUSTED_CONTEXT.lock().unwrap() { - context.add_known_contract(contract); - } - } - _ => {} // Other networks don't use trusted context + if let Some(ref context) = self.trusted_context { + context.add_known_contract(contract); } } /// Fetch a contract, checking cache first - /// Returns the contract from cache if available, otherwise fetches from network and caches it pub(crate) async fn get_or_fetch_contract( &self, contract_id: dash_sdk::platform::Identifier, ) -> Result { use dash_sdk::platform::Fetch; - // Check cache first if let Some(cached) = self.get_cached_contract(&contract_id) { return Ok((*cached).clone()); } - // Fetch from network let contract = dash_sdk::platform::DataContract::fetch(self.as_ref(), contract_id) .await? .ok_or_else(|| crate::error::WasmSdkError::not_found("Data contract not found"))?; - // Cache for future use self.cache_contract(contract.clone()); Ok(contract) } /// Remove a contract from the cache - /// This allows forcing a fresh fetch on next access pub(crate) fn remove_cached_contract( &self, contract_id: &dash_sdk::platform::Identifier, ) -> bool { - match self.network() { - dash_sdk::dpp::dashcore::Network::Testnet => { - let guard = TESTNET_TRUSTED_CONTEXT.lock().unwrap(); - guard - .as_ref() - .map(|ctx| ctx.remove_known_contract(contract_id)) - .unwrap_or(false) - } - dash_sdk::dpp::dashcore::Network::Dash => { - let guard = MAINNET_TRUSTED_CONTEXT.lock().unwrap(); - guard - .as_ref() - .map(|ctx| ctx.remove_known_contract(contract_id)) - .unwrap_or(false) - } - dash_sdk::dpp::dashcore::Network::Regtest => { - let guard = LOCAL_TRUSTED_CONTEXT.lock().unwrap(); - guard - .as_ref() - .map(|ctx| ctx.remove_known_contract(contract_id)) - .unwrap_or(false) - } - _ => false, - } + self.trusted_context + .as_ref() + .map(|ctx| ctx.remove_known_contract(contract_id)) + .unwrap_or(false) } } #[wasm_bindgen] impl WasmSdk { /// Remove a data contract from the cache. - /// This forces a fresh fetch from the network on the next access. /// Returns true if the contract was in the cache and was removed. #[wasm_bindgen(js_name = "removeCachedContract")] pub fn remove_cached_contract_js( @@ -284,74 +167,21 @@ impl WasmSdk { } #[wasm_bindgen] -impl WasmSdk { - #[wasm_bindgen(js_name = "prefetchTrustedQuorumsMainnet")] - pub async fn prefetch_trusted_quorums_mainnet() -> Result<(), WasmSdkError> { - let trusted_context = WasmTrustedContext::new_mainnet() - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e)))?; - - trusted_context - .prefetch_quorums() - .await - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e)))?; - - fetch_and_cache_addresses(&trusted_context, &MAINNET_DISCOVERED_ADDRESSES).await?; - - // Store the context for later use - *MAINNET_TRUSTED_CONTEXT.lock().unwrap() = Some(trusted_context); - - Ok(()) - } - - #[wasm_bindgen(js_name = "prefetchTrustedQuorumsTestnet")] - pub async fn prefetch_trusted_quorums_testnet() -> Result<(), WasmSdkError> { - let trusted_context = WasmTrustedContext::new_testnet() - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e)))?; - - trusted_context - .prefetch_quorums() - .await - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e)))?; - - fetch_and_cache_addresses(&trusted_context, &TESTNET_DISCOVERED_ADDRESSES).await?; - - // Store the context for later use - *TESTNET_TRUSTED_CONTEXT.lock().unwrap() = Some(trusted_context); - - Ok(()) - } - - #[wasm_bindgen(js_name = "prefetchTrustedQuorumsLocal")] - pub async fn prefetch_trusted_quorums_local() -> Result<(), WasmSdkError> { - let trusted_context = WasmTrustedContext::new_local_with_url(DEFAULT_LOCAL_QUORUM_URL) - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e)))?; - - trusted_context - .prefetch_quorums() - .await - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e)))?; - - fetch_and_cache_addresses(&trusted_context, &LOCAL_DISCOVERED_ADDRESSES).await?; - - *LOCAL_TRUSTED_CONTEXT.lock().unwrap() = Some(trusted_context); - - Ok(()) - } +pub struct WasmSdkBuilder { + inner: SdkBuilder, + trusted_context: Option, } -#[wasm_bindgen] -pub struct WasmSdkBuilder(SdkBuilder); - impl Deref for WasmSdkBuilder { type Target = SdkBuilder; fn deref(&self) -> &Self::Target { - &self.0 + &self.inner } } impl DerefMut for WasmSdkBuilder { fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 + &mut self.inner } } @@ -368,12 +198,6 @@ impl WasmSdkBuilder { /// # Arguments /// * `addresses` - Array of HTTPS URLs (e.g., ["https://127.0.0.1:1443"]) /// * `network` - Network identifier: "mainnet", "testnet" or "local" - /// - /// # Example - /// ```javascript - /// const builder = WasmSdkBuilder.withAddresses(['https://127.0.0.1:1443'], 'testnet'); - /// const sdk = builder.build(); - /// ``` #[wasm_bindgen(js_name = "withAddresses")] pub fn new_with_addresses( addresses: Vec, @@ -382,7 +206,6 @@ impl WasmSdkBuilder { use dash_sdk::dpp::dashcore::Network; use dash_sdk::sdk::Uri; - // Parse and validate addresses if addresses.is_empty() { return Err(WasmSdkError::invalid_argument( "Addresses must be a non-empty array", @@ -401,7 +224,6 @@ impl WasmSdkBuilder { let parsed_addresses = parsed_addresses.map_err(WasmSdkError::invalid_argument)?; - // Parse network - mainnet, testnet and local are supported let network = match network.to_lowercase().as_str() { "mainnet" => Network::Dash, "testnet" => Network::Testnet, @@ -415,200 +237,95 @@ impl WasmSdkBuilder { }; let address_list = dash_sdk::sdk::AddressList::from_iter(parsed_addresses); - let sdk_builder = match network { - Network::Dash => { - let address_list = address_list.clone(); - - // Use the cached trusted context if available for mainnet - let context = { - let guard = MAINNET_TRUSTED_CONTEXT.lock().unwrap(); - guard.clone() - } - .map(Ok) - .unwrap_or_else(|| { - WasmTrustedContext::new_mainnet() - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e))) - })?; - - SdkBuilder::new(address_list) - .with_network(network) - .with_context_provider(context) - } - Network::Testnet => { - let address_list = address_list.clone(); - - // Use the cached trusted context if available for testnet - let context = { - let guard = TESTNET_TRUSTED_CONTEXT.lock().unwrap(); - guard.clone() - } - .map(Ok) - .unwrap_or_else(|| { - WasmTrustedContext::new_testnet() - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e))) - })?; - - SdkBuilder::new(address_list) - .with_network(network) - .with_context_provider(context) - } - Network::Regtest => { - let address_list = address_list.clone(); - - let context = { - let guard = LOCAL_TRUSTED_CONTEXT.lock().unwrap(); - guard.clone() - } - .map(Ok) - .unwrap_or_else(|| { - WasmTrustedContext::new_local() - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e))) - })?; - - SdkBuilder::new(address_list) - .with_network(network) - .with_context_provider(context) - } - _ => unreachable!("Network already validated to mainnet, testnet or local"), - }; + let sdk_builder = SdkBuilder::new(address_list) + .with_network(network) + .with_context_provider(WasmContext {}); - Ok(Self(sdk_builder)) + Ok(Self { + inner: sdk_builder, + trusted_context: None, + }) } #[wasm_bindgen(js_name = "mainnet")] pub fn new_mainnet() -> Self { - let mainnet_addresses = MAINNET_DISCOVERED_ADDRESSES - .lock() - .unwrap() - .clone() - .unwrap_or_else(default_mainnet_addresses); - - let address_list = dash_sdk::sdk::AddressList::from_iter(mainnet_addresses); + let address_list = dash_sdk::sdk::AddressList::from_iter(default_mainnet_addresses()); let sdk_builder = SdkBuilder::new(address_list) .with_network(dash_sdk::dpp::dashcore::Network::Dash) .with_context_provider(WasmContext {}); - Self(sdk_builder) + Self { + inner: sdk_builder, + trusted_context: None, + } } - /// Create a new SdkBuilder preconfigured for a local network using default dashmate gateway. - #[wasm_bindgen(js_name = "local")] - pub fn new_local() -> Self { - // Dashmate local gateway defaults to 2443 - let local_addresses = vec!["https://127.0.0.1:2443".parse().unwrap()]; - - let address_list = dash_sdk::sdk::AddressList::from_iter(local_addresses); + #[wasm_bindgen(js_name = "testnet")] + pub fn new_testnet() -> Self { + let address_list = dash_sdk::sdk::AddressList::from_iter(default_testnet_addresses()); let sdk_builder = SdkBuilder::new(address_list) - .with_network(dash_sdk::dpp::dashcore::Network::Regtest) + .with_network(dash_sdk::dpp::dashcore::Network::Testnet) .with_context_provider(WasmContext {}); - Self(sdk_builder) + Self { + inner: sdk_builder, + trusted_context: None, + } } - #[wasm_bindgen(js_name = "localTrusted")] - pub fn new_local_trusted() -> Result { - let trusted_context = { - let mut guard = LOCAL_TRUSTED_CONTEXT.lock().unwrap(); - if let Some(ctx) = guard.as_ref() { - ctx.clone() - } else { - let new_ctx = WasmTrustedContext::new_local() - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e)))?; - *guard = Some(new_ctx.clone()); - new_ctx - } - }; - - let local_addresses = LOCAL_DISCOVERED_ADDRESSES - .lock() - .unwrap() - .clone() - .unwrap_or_else(default_local_addresses); - - let address_list = dash_sdk::sdk::AddressList::from_iter(local_addresses); + /// Create a new SdkBuilder preconfigured for a local network using default dashmate gateway. + #[wasm_bindgen(js_name = "local")] + pub fn new_local() -> Self { + let address_list = dash_sdk::sdk::AddressList::from_iter(default_local_addresses()); let sdk_builder = SdkBuilder::new(address_list) .with_network(dash_sdk::dpp::dashcore::Network::Regtest) - .with_context_provider(trusted_context); - - Ok(Self(sdk_builder)) - } - - #[wasm_bindgen(js_name = "mainnetTrusted")] - pub fn new_mainnet_trusted() -> Result { - // Use the cached context if available, otherwise create a new one and store it - let trusted_context = { - let mut guard = MAINNET_TRUSTED_CONTEXT.lock().unwrap(); - if let Some(ctx) = guard.as_ref() { - ctx.clone() - } else { - let new_ctx = WasmTrustedContext::new_mainnet() - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e)))?; - *guard = Some(new_ctx.clone()); - new_ctx - } - }; - - let mainnet_addresses = MAINNET_DISCOVERED_ADDRESSES - .lock() - .unwrap() - .clone() - .unwrap_or_else(default_mainnet_addresses); - - let address_list = dash_sdk::sdk::AddressList::from_iter(mainnet_addresses); - let sdk_builder = SdkBuilder::new(address_list) - .with_network(dash_sdk::dpp::dashcore::Network::Dash) - .with_context_provider(trusted_context); - - Ok(Self(sdk_builder)) - } - - #[wasm_bindgen(js_name = "testnet")] - pub fn new_testnet() -> Self { - let testnet_addresses = TESTNET_DISCOVERED_ADDRESSES - .lock() - .unwrap() - .clone() - .unwrap_or_else(default_testnet_addresses); - - let address_list = dash_sdk::sdk::AddressList::from_iter(testnet_addresses); - let sdk_builder = SdkBuilder::new(address_list) - .with_network(dash_sdk::dpp::dashcore::Network::Testnet) .with_context_provider(WasmContext {}); - Self(sdk_builder) + Self { + inner: sdk_builder, + trusted_context: None, + } } - #[wasm_bindgen(js_name = "testnetTrusted")] - pub fn new_testnet_trusted() -> Result { - // Use the cached context if available, otherwise create a new one and store it - let trusted_context = { - let mut guard = TESTNET_TRUSTED_CONTEXT.lock().unwrap(); - if let Some(ctx) = guard.as_ref() { - ctx.clone() - } else { - let new_ctx = WasmTrustedContext::new_testnet() - .map_err(|e| WasmSdkError::from(dash_sdk::Error::from(e)))?; - *guard = Some(new_ctx.clone()); - new_ctx - } + /// Attach a pre-fetched trusted context to this builder. + /// + /// The context provides quorum keys for proof verification and + /// discovered masternode addresses for network connectivity. + /// If the context has discovered addresses, they replace the + /// builder's current address list. + /// + /// # Example + /// ```javascript + /// const context = await WasmTrustedContext.prefetchTestnet(); + /// const builder = WasmSdkBuilder.testnet().withTrustedContext(context); + /// const sdk = builder.build(); + /// ``` + #[wasm_bindgen(js_name = "withTrustedContext")] + pub fn with_trusted_context(self, context: &WasmTrustedContext) -> Self { + let discovered = context.discovered_addresses(); + + // Replace address list with discovered addresses if available + let inner = if !discovered.is_empty() { + let address_list = dash_sdk::sdk::AddressList::from_iter(discovered.to_vec()); + self.inner + .with_address_list(address_list) + .with_context_provider(context.clone()) + } else { + self.inner.with_context_provider(context.clone()) }; - let testnet_addresses = TESTNET_DISCOVERED_ADDRESSES - .lock() - .unwrap() - .clone() - .unwrap_or_else(default_testnet_addresses); - - let address_list = dash_sdk::sdk::AddressList::from_iter(testnet_addresses); - let sdk_builder = SdkBuilder::new(address_list) - .with_network(dash_sdk::dpp::dashcore::Network::Testnet) - .with_context_provider(trusted_context); - - Ok(Self(sdk_builder)) + Self { + inner, + trusted_context: Some(context.clone()), + } } pub fn build(self) -> Result { - self.0.build().map(WasmSdk).map_err(WasmSdkError::from) + let sdk = self.inner.build().map_err(WasmSdkError::from)?; + Ok(WasmSdk { + sdk, + trusted_context: self.trusted_context, + }) } #[wasm_bindgen(js_name = "withContextProvider")] @@ -616,7 +333,10 @@ impl WasmSdkBuilder { self, #[wasm_bindgen(js_name = "contextProvider")] context_provider: WasmContext, ) -> Self { - WasmSdkBuilder(self.0.with_context_provider(context_provider)) + Self { + inner: self.inner.with_context_provider(context_provider), + trusted_context: None, + } } /// Configure platform version to use. @@ -639,7 +359,10 @@ impl WasmSdkBuilder { )) })?; - Ok(WasmSdkBuilder(self.0.with_version(version))) + Ok(Self { + inner: self.inner.with_version(version), + trusted_context: self.trusted_context, + }) } /// Configure request settings for the SDK. @@ -675,7 +398,10 @@ impl WasmSdkBuilder { settings.ban_failed_address = Some(ban); } - WasmSdkBuilder(self.0.with_settings(settings)) + Self { + inner: self.inner.with_settings(settings), + trusted_context: self.trusted_context, + } } #[wasm_bindgen(js_name = "withProofs")] @@ -683,7 +409,10 @@ impl WasmSdkBuilder { self, #[wasm_bindgen(js_name = "enableProofs")] enable_proofs: bool, ) -> Self { - WasmSdkBuilder(self.0.with_proofs(enable_proofs)) + Self { + inner: self.inner.with_proofs(enable_proofs), + trusted_context: self.trusted_context, + } } } diff --git a/packages/wasm-sdk/tests/functional/addresses.spec.ts b/packages/wasm-sdk/tests/functional/addresses.spec.ts index fb8b9d091c0..9cf621c09d1 100644 --- a/packages/wasm-sdk/tests/functional/addresses.spec.ts +++ b/packages/wasm-sdk/tests/functional/addresses.spec.ts @@ -13,8 +13,8 @@ describe('Platform Address Queries', function describePlatformAddressQueries() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - const builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + const builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); // Use the test addresses created by SDK_TEST_DATA=true during genesis diff --git a/packages/wasm-sdk/tests/functional/contracts.spec.ts b/packages/wasm-sdk/tests/functional/contracts.spec.ts index 0e8a6463b8c..04a2d4ba016 100644 --- a/packages/wasm-sdk/tests/functional/contracts.spec.ts +++ b/packages/wasm-sdk/tests/functional/contracts.spec.ts @@ -11,8 +11,8 @@ describe('Data Contract Queries', function describeDataContractQueries() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - const builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + const builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/dpns.spec.ts b/packages/wasm-sdk/tests/functional/dpns.spec.ts index 6bc67132ee2..ee2732827e7 100644 --- a/packages/wasm-sdk/tests/functional/dpns.spec.ts +++ b/packages/wasm-sdk/tests/functional/dpns.spec.ts @@ -12,8 +12,8 @@ describe('Document Queries', function describeDocumentQueries() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/epochs-blocks.spec.ts b/packages/wasm-sdk/tests/functional/epochs-blocks.spec.ts index c04fbe0ae23..30ae1196352 100644 --- a/packages/wasm-sdk/tests/functional/epochs-blocks.spec.ts +++ b/packages/wasm-sdk/tests/functional/epochs-blocks.spec.ts @@ -9,8 +9,8 @@ describe('Epochs and Evonode Blocks', function describeEpochs() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - const builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + const builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); // Get the proTxHash from the node status diff --git a/packages/wasm-sdk/tests/functional/groups.spec.ts b/packages/wasm-sdk/tests/functional/groups.spec.ts index b91bae5c929..7bb78e4e87a 100644 --- a/packages/wasm-sdk/tests/functional/groups.spec.ts +++ b/packages/wasm-sdk/tests/functional/groups.spec.ts @@ -9,8 +9,8 @@ describe('Groups', function describeGroups() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/identities.spec.ts b/packages/wasm-sdk/tests/functional/identities.spec.ts index 6b5d86cb1c7..2c7a5ce4abc 100644 --- a/packages/wasm-sdk/tests/functional/identities.spec.ts +++ b/packages/wasm-sdk/tests/functional/identities.spec.ts @@ -16,8 +16,8 @@ describe('Identities', function describeIdentities() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/protocol.spec.ts b/packages/wasm-sdk/tests/functional/protocol.spec.ts index da651ca6efd..9c56dca78ba 100644 --- a/packages/wasm-sdk/tests/functional/protocol.spec.ts +++ b/packages/wasm-sdk/tests/functional/protocol.spec.ts @@ -9,8 +9,8 @@ describe('Protocol', function describeProtocol() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - const builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + const builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); // Get the proTxHash from the node status diff --git a/packages/wasm-sdk/tests/functional/status.spec.ts b/packages/wasm-sdk/tests/functional/status.spec.ts index b0d11350197..b4307483159 100644 --- a/packages/wasm-sdk/tests/functional/status.spec.ts +++ b/packages/wasm-sdk/tests/functional/status.spec.ts @@ -9,8 +9,8 @@ describe('Status', function describeStatus() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/system.spec.ts b/packages/wasm-sdk/tests/functional/system.spec.ts index 8bc92446932..12dd81a2ab4 100644 --- a/packages/wasm-sdk/tests/functional/system.spec.ts +++ b/packages/wasm-sdk/tests/functional/system.spec.ts @@ -9,8 +9,8 @@ describe('System', function describeSystem() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/token-pricing.spec.ts b/packages/wasm-sdk/tests/functional/token-pricing.spec.ts index 4c96ea6d70f..c75aa72b180 100644 --- a/packages/wasm-sdk/tests/functional/token-pricing.spec.ts +++ b/packages/wasm-sdk/tests/functional/token-pricing.spec.ts @@ -10,8 +10,8 @@ describe('TokenPricing', function describeTokenPricing() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/tokens.spec.ts b/packages/wasm-sdk/tests/functional/tokens.spec.ts index 3068995aab4..561105398cd 100644 --- a/packages/wasm-sdk/tests/functional/tokens.spec.ts +++ b/packages/wasm-sdk/tests/functional/tokens.spec.ts @@ -16,8 +16,8 @@ describe('Tokens', function describeTokens() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/transitions/contracts.spec.ts b/packages/wasm-sdk/tests/functional/transitions/contracts.spec.ts index 3cd36d15c26..ee7913fc5d2 100644 --- a/packages/wasm-sdk/tests/functional/transitions/contracts.spec.ts +++ b/packages/wasm-sdk/tests/functional/transitions/contracts.spec.ts @@ -25,8 +25,8 @@ describe('Contract State Transitions', function describeContractStateTransitions before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - const builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + const builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/transitions/documents.spec.ts b/packages/wasm-sdk/tests/functional/transitions/documents.spec.ts index a6dc19c393d..2b5d5457541 100644 --- a/packages/wasm-sdk/tests/functional/transitions/documents.spec.ts +++ b/packages/wasm-sdk/tests/functional/transitions/documents.spec.ts @@ -32,8 +32,8 @@ describe('Document State Transitions', function describeDocumentStateTransitions before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - const builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + const builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/transitions/dpns.spec.ts b/packages/wasm-sdk/tests/functional/transitions/dpns.spec.ts index b353af4eb72..d56b2f76403 100644 --- a/packages/wasm-sdk/tests/functional/transitions/dpns.spec.ts +++ b/packages/wasm-sdk/tests/functional/transitions/dpns.spec.ts @@ -30,8 +30,8 @@ describe('DPNS State Transitions', function describeDpnsStateTransitions() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - const builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + const builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/transitions/identity.spec.ts b/packages/wasm-sdk/tests/functional/transitions/identity.spec.ts index b2ef718b3c0..e97e30ad34c 100644 --- a/packages/wasm-sdk/tests/functional/transitions/identity.spec.ts +++ b/packages/wasm-sdk/tests/functional/transitions/identity.spec.ts @@ -28,8 +28,8 @@ describe('Identity State Transitions', function describeIdentityStateTransitions before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - const builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + const builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/transitions/tokens.spec.ts b/packages/wasm-sdk/tests/functional/transitions/tokens.spec.ts index 9b24e120418..ed4d49dcf7a 100644 --- a/packages/wasm-sdk/tests/functional/transitions/tokens.spec.ts +++ b/packages/wasm-sdk/tests/functional/transitions/tokens.spec.ts @@ -32,8 +32,8 @@ describe('Token State Transitions', function describeTokenStateTransitions() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - const builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + const builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/functional/utilities.spec.ts b/packages/wasm-sdk/tests/functional/utilities.spec.ts index 9221098fbad..1e5747b2a2d 100644 --- a/packages/wasm-sdk/tests/functional/utilities.spec.ts +++ b/packages/wasm-sdk/tests/functional/utilities.spec.ts @@ -6,9 +6,9 @@ describe('Utilities', function describeUtilities() { before(async () => { await init(); }); - describe('prefetchTrustedQuorumsLocal()', () => { + describe('WasmTrustedContext.prefetchLocal()', () => { it('should prefetch trusted quorums for local', async () => { - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); + await sdk.WasmTrustedContext.prefetchLocal(); }); }); diff --git a/packages/wasm-sdk/tests/functional/voting.spec.ts b/packages/wasm-sdk/tests/functional/voting.spec.ts index 0b85960330f..09949b5f39d 100644 --- a/packages/wasm-sdk/tests/functional/voting.spec.ts +++ b/packages/wasm-sdk/tests/functional/voting.spec.ts @@ -10,8 +10,8 @@ describe('Voting', function describeVoting() { before(async () => { await init(); - await sdk.WasmSdk.prefetchTrustedQuorumsLocal(); - builder = sdk.WasmSdkBuilder.localTrusted(); + const context = await sdk.WasmTrustedContext.prefetchLocal(); + builder = sdk.WasmSdkBuilder.local().withTrustedContext(context); client = await builder.build(); }); diff --git a/packages/wasm-sdk/tests/unit/builder.spec.ts b/packages/wasm-sdk/tests/unit/builder.spec.ts index 4b047478041..9e7250b4ed4 100644 --- a/packages/wasm-sdk/tests/unit/builder.spec.ts +++ b/packages/wasm-sdk/tests/unit/builder.spec.ts @@ -23,12 +23,12 @@ describe('WasmSdkBuilder', () => { expect(sdk.WasmSdkBuilder.testnet).to.be.a('function'); }); - it('should expose mainnetTrusted method', () => { - expect(sdk.WasmSdkBuilder.mainnetTrusted).to.be.a('function'); + it('should expose local method', () => { + expect(sdk.WasmSdkBuilder.local).to.be.a('function'); }); - it('should expose testnetTrusted method', () => { - expect(sdk.WasmSdkBuilder.testnetTrusted).to.be.a('function'); + it('should expose withAddresses method', () => { + expect(sdk.WasmSdkBuilder.withAddresses).to.be.a('function'); }); });