Skip to content

refactor(sdk): get rid of static trusted contexts#3043

Merged
QuantumExplorer merged 7 commits into
v3.1-devfrom
refactor/sdk/static-context
Feb 8, 2026
Merged

refactor(sdk): get rid of static trusted contexts#3043
QuantumExplorer merged 7 commits into
v3.1-devfrom
refactor/sdk/static-context

Conversation

@shumkov

@shumkov shumkov commented Feb 2, 2026

Copy link
Copy Markdown
Collaborator

Issue being fixed or feature implemented

The wasm-sdk used 6 Lazy<Mutex<Option<T>>> static globals for managing trusted context and discovered masternode addresses. This shared mutable state made the SDK harder to reason about, prevented multiple SDK instances with different configurations, and coupled context lifetime to the process rather than the SDK instance.

What was done?

Replaced all 6 static globals with instance-owned state by introducing WasmTrustedContext as a JS-exported object with async prefetch factories:

Rust changes:

  • WasmTrustedContext now holds Arc<TrustedHttpContextProvider> + Vec<Address> with prefetchMainnet(), prefetchTestnet(), prefetchLocal(), prefetchLocalWithUrl() async factory methods
  • WasmSdkBuilder gained withTrustedContext(context) that sets the context provider and replaces addresses with discovered ones
  • WasmSdk is now a named struct with trusted_context: Option<WasmTrustedContext> for contract/token cache access
  • Removed prefetchTrustedQuorums* static methods from WasmSdk
  • Removed *Trusted() builder methods (replaced by builder.local().withTrustedContext(context))
  • Removed all 6 Lazy<Mutex<Option<T>>> statics and their once_cell/std::sync::Mutex imports
  • Added with_address_list() to SdkBuilder in rs-sdk
  • Simplified prefetch_token_configuration in queries/token.rs to use self.trusted_context directly

JS changes:

  • EvoSDK.connect() updated to prefetch WasmTrustedContext and pass it via withTrustedContext()
  • Fixed all eslint warnings across js-evo-sdk (max-len, curly, unused vars)

New JS API:

// Before:
await WasmSdk.prefetchTrustedQuorumsLocal();
const builder = WasmSdkBuilder.localTrusted();

// After:
const context = await WasmTrustedContext.prefetchLocal();
const builder = WasmSdkBuilder.local().withTrustedContext(context);

How Has This Been Tested?

  • cargo fmt --all — clean
  • cargo clippy -p wasm-sdk -p dash-sdk — clean
  • wasm-sdk build (./build.sh) — success
  • wasm-sdk unit tests — 212 passed
  • js-evo-sdk build — success
  • js-evo-sdk unit tests — 172 passed (Node.js + Chrome headless)
  • js-evo-sdk eslint — 0 errors, 0 warnings

Breaking Changes

  • WasmSdk.prefetchTrustedQuorumsMainnet/Testnet/Local() removed — use WasmTrustedContext.prefetchMainnet/Testnet/Local() instead
  • WasmSdkBuilder.mainnetTrusted/testnetTrusted/localTrusted() removed — use WasmSdkBuilder.mainnet/testnet/local().withTrustedContext(context) instead
  • WasmSdkBuilder.withAddresses() no longer accepts an optional cache parameter

Checklist:

  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have added or updated relevant unit/integration/functional/e2e tests
  • I have added "!" to the title and described breaking changes in the corresponding section if my code contains any
  • I have made corresponding changes to the documentation if needed

For repository code-owners and collaborators only

  • I have assigned this pull request to a milestone

Summary by CodeRabbit

  • New Features

    • New trusted-context prefetch factories (mainnet/testnet/local) and ability to attach a prefetched trusted context to a builder; builder now supports per-instance wiring, addresses, version, proofs, logs, and settings.
    • Rust SDK: added builder step to replace address lists.
  • Bug Fixes

    • Unknown-network cases now fail fast with explicit errors.
  • Tests

    • Updated unit and functional tests to use the new trusted-context + builder flow.

@github-actions github-actions Bot added this to the v3.1.0 milestone Feb 2, 2026
@github-actions

github-actions Bot commented Feb 2, 2026

Copy link
Copy Markdown
Contributor

✅ gRPC Query Coverage Report

================================================================================
gRPC Query Coverage Report - NEW QUERIES ONLY
================================================================================

Total queries in proto: 53
Previously known queries: 47
New queries found: 6

================================================================================

New Query Implementation Status:
--------------------------------------------------------------------------------
✓ getAddressInfo                                /home/runner/work/platform/platform/packages/rs-sdk/src/platform/query.rs
✓ getAddressesBranchState                       /home/runner/work/platform/platform/packages/rs-sdk/src/platform/address_sync/mod.rs
✓ getAddressesInfos                             /home/runner/work/platform/platform/packages/rs-sdk/src/platform/fetch_many.rs
✓ getAddressesTrunkState                        /home/runner/work/platform/platform/packages/rs-sdk/src/platform/query.rs
✓ getRecentAddressBalanceChanges                /home/runner/work/platform/platform/packages/rs-sdk/src/platform/query.rs
✓ getRecentCompactedAddressBalanceChanges       /home/runner/work/platform/platform/packages/rs-sdk/src/platform/query.rs

================================================================================
Summary:
--------------------------------------------------------------------------------
New queries implemented: 6 (100.0%)
New queries missing: 0 (0.0%)

Total known queries: 53
  - Implemented: 50
  - Not implemented: 2
  - Excluded: 1

Not implemented queries:
  - getConsensusParams
  - getTokenPreProgrammedDistributions

@coderabbitai

coderabbitai Bot commented Feb 2, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

Switches from global cached trusted contexts to per-instance trusted contexts: adds WasmTrustedContext prefetch factories, embeds optional trusted_context into WasmSdk and WasmSdkBuilder, replaces trusted builder variants with withTrustedContext(context), and updates SDK logic and tests to prefetch and inject contexts before building.

Changes

Cohort / File(s) Summary
Core WASM SDK
packages/wasm-sdk/src/sdk.rs
WasmSdk changed from tuple to struct with trusted_context: Option<WasmTrustedContext>. Introduced WasmSdkBuilder wrapping SdkBuilder + trusted_context. Removed global trusted-context caches; moved caching and related methods to per-instance trusted_context; updated wasm-bindgen exports.
Trusted Context / Prefetch
packages/wasm-sdk/src/context_provider.rs
Added WasmTrustedContext prefetch factories (prefetch_mainnet/prefetch_testnet/prefetch_local/prefetch_local_with_url), added discovered_addresses: Vec<...> + accessor, new address fetch helper, and switched error handling to WasmSdkError.
WASM Query Logic
packages/wasm-sdk/src/queries/token.rs
Replaced per-network global trusted-context checks with instance self.trusted_context() usage and centralized trusted_context-based token configuration caching.
WASM Tests (functional)
packages/wasm-sdk/tests/functional/*.spec.ts, packages/wasm-sdk/tests/functional/transitions/*.spec.ts
All functional tests updated to call WasmTrustedContext.prefetchLocal() then WasmSdkBuilder.local().withTrustedContext(context) instead of WasmSdk.prefetchTrustedQuorumsLocal() + WasmSdkBuilder.localTrusted().
WASM Tests (unit builder)
packages/wasm-sdk/tests/unit/builder.spec.ts
Removed expectations for mainnetTrusted() / testnetTrusted() and added checks for local() / withAddresses(); tests updated to reflect removed trusted-builder variants.
JS SDK Core
packages/js-evo-sdk/src/sdk.ts
Reworked builder selection and connect flow to use prefetching of a trusted context and withTrustedContext(context) when applicable; reordered version/proofs/logs/settings application but kept public signatures unchanged.
JS SDK Tests (unit facades)
packages/js-evo-sdk/tests/unit/facades/*.spec.ts
Replaced WasmSdkBuilder.testnetTrusted()WasmSdkBuilder.testnet() across many unit tests; minor formatting and stub reformatting in a few specs.
Rust Sdk Builder
packages/rs-sdk/src/sdk.rs
Added with_address_list(mut self, addresses: AddressList) -> Self to SdkBuilder to replace address list post-construction.
Misc (configs/tests)
packages/rs-platform-version/Cargo.toml, packages/simple-signer/Cargo.toml
Removed once_cell dependency; added package.metadata.cargo-machete ignore for bincode (tooling metadata).

Sequence Diagram(s)

sequenceDiagram
  participant Test as Test / App
  participant JS as WasmTrustedContext (JS/WASM)
  participant Builder as WasmSdkBuilder
  participant SDK as WasmSdk

  Test->>JS: prefetchLocal()
  JS-->>Test: WasmTrustedContext (includes discovered_addresses)
  Test->>Builder: local()
  Test->>Builder: withTrustedContext(context)
  Builder->>Builder: configure inner SdkBuilder + trusted_context
  Test->>Builder: build()
  Builder-->>SDK: WasmSdk (sdk + trusted_context)
  Test->>SDK: use SDK methods (reads trusted_context when needed)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐇 I fetched the trust and tucked it tight,

No globals roaming in the night.
Builders carry what they need to know,
Seeded contexts help the systems grow.
Hops of joy — a tidy change in sight!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'refactor(sdk): get rid of static trusted contexts' directly and accurately describes the main change across the codebase: replacing static global trusted context state with instance-owned state in WasmSdk and WasmSdkBuilder.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refactor/sdk/static-context

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/js-evo-sdk/src/sdk.ts`:
- Around line 93-105: The code destructures a trusted flag from this.options but
always prefetched a trusted context in connect(); update connect() to honor the
trusted option by only calling
wasm.WasmTrustedContext.prefetchMainnet()/prefetchTestnet()/prefetchLocal() when
the instance's trusted property is true (reference the trusted field set in the
constructor and the connect() function), or alternatively remove the trusted
option and associated helpers (testnetTrusted/mainnetTrusted/localTrusted) from
EvoSDKOptions and factories if you decide trusted contexts are mandatory; modify
only the connect() prefetch branch or the options/factory definitions
accordingly so the trusted flag is either used or eliminated consistently.
🧹 Nitpick comments (4)
packages/js-evo-sdk/tests/unit/facades/identities.spec.ts (2)

79-84: Minor: Inconsistent indentation in multiline stub setup.

The object properties inside .resolves({...}) are not indented consistently with similar patterns elsewhere in this file (e.g., lines 101-106). The properties should be indented one level relative to the opening brace.

🔧 Suggested fix for consistent indentation
     getIdentityContractNonceWithProofInfoStub = this.sinon
       .stub(wasmSdk, 'getIdentityContractNonceWithProofInfo').resolves({
-      data: BigInt(0),
-      proof: {},
-      metadata: {},
-    });
+        data: BigInt(0),
+        proof: {},
+        metadata: {},
+      });

130-135: Minor: Same indentation inconsistency as above.

🔧 Suggested fix for consistent indentation
     getIdentityTokenBalancesWithProofInfoStub = this.sinon
       .stub(wasmSdk, 'getIdentityTokenBalancesWithProofInfo').resolves({
-      data: new Map(),
-      proof: {},
-      metadata: {},
-    });
+        data: new Map(),
+        proof: {},
+        metadata: {},
+      });
packages/wasm-sdk/tests/unit/builder.spec.ts (1)

9-29: Consider adding test coverage for withTrustedContext() method.

The static methods are well tested, but the new withTrustedContext() instance method introduced by this PR is only implicitly covered via functional tests. Adding a unit test would provide explicit validation of the API surface.

🧪 Suggested test addition
it('should expose withTrustedContext method on builder instance', () => {
  const builder = sdk.WasmSdkBuilder.local();
  expect(builder.withTrustedContext).to.be.a('function');
});
packages/wasm-sdk/src/context_provider.rs (1)

106-157: Consider extracting shared prefetch logic into a helper method.

prefetch_mainnet and prefetch_testnet have nearly identical implementations, differing only in the Network parameter. A private helper could reduce duplication:

♻️ Optional refactor
+    async fn prefetch_for_network(
+        network: dash_sdk::dpp::dashcore::Network,
+    ) -> Result<WasmTrustedContext, WasmSdkError> {
+        let inner = rs_sdk_trusted_context_provider::TrustedHttpContextProvider::new(
+            network,
+            None,
+            std::num::NonZeroUsize::new(100).unwrap(),
+        )
+        .map_err(|e| WasmSdkError::generic(format!("Failed to create context provider: {}", e)))?
+        .with_refetch_if_not_found(false);
+
+        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,
+        })
+    }
+
     #[wasm_bindgen(js_name = "prefetchMainnet")]
     pub async fn prefetch_mainnet() -> Result<WasmTrustedContext, WasmSdkError> {
-        // ... current implementation
+        Self::prefetch_for_network(dash_sdk::dpp::dashcore::Network::Dash).await
     }

That said, keeping them explicit is also reasonable for JS-exported factory methods where clarity is valued.

Comment thread packages/js-evo-sdk/src/sdk.ts Outdated
@shumkov shumkov self-assigned this Feb 3, 2026
@shumkov shumkov moved this to In review / testing in Platform team Feb 3, 2026

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
packages/wasm-sdk/src/dpns.rs (1)

458-507: ⚠️ Potential issue | 🟠 Major

Return undefined to match the new JS-facing type.

You updated the unchecked return types to ... | undefined, but the absence paths still return JsValue::NULL. This contradicts the declared contract and can break consumers that rely on undefined checks. Return JsValue::UNDEFINED in both functions.

✅ Proposed fix
@@
-        } else {
-            JsValue::NULL
-        };
+        } else {
+            JsValue::UNDEFINED
+        };
@@
-        let username = if usernames.length() > 0 {
-            usernames.get(0)
-        } else {
-            JsValue::NULL
-        };
+        let username = if usernames.length() > 0 {
+            usernames.get(0)
+        } else {
+            JsValue::UNDEFINED
+        };

Also applies to: 559-578

packages/wasm-sdk/src/queries/token.rs (1)

635-637: ⚠️ Potential issue | 🟠 Major

Return value inconsistent with declared TypeScript type.

The unchecked_return_type on line 612 declares TokenTotalSupply | undefined, but the implementation returns JsValue::NULL when no data is found. This creates a type mismatch for TypeScript consumers.

Other methods in this file correctly use JsValue::UNDEFINED (e.g., lines 822 and 868).

🐛 Proposed fix
         let data = supply_result
             .map(|supply| JsValue::from(TokenTotalSupplyWasm::new(supply.token_supply as u64)))
-            .unwrap_or(JsValue::NULL);
+            .unwrap_or(JsValue::UNDEFINED);
packages/wasm-sdk/src/queries/identity.rs (1)

340-343: ⚠️ Potential issue | 🟠 Major

Systematic mismatch between declared TypeScript types and returned values.

The unchecked_return_type annotations across this file were updated to use undefined (e.g., Identity | undefined on line 327), but the implementations still return JsValue::NULL. This pattern repeats in multiple methods:

Method Type Annotation Line Returns NULL at Line
get_identity_with_proof_info 327 342
get_identity_nonce_with_proof_info 555 573
get_identity_contract_nonce_with_proof_info 605 632
get_identities_balances 659 681
get_identity_balance_with_proof_info 913 932
get_identities_balances_with_proof_info 942 971
get_identity_balance_and_revision_with_proof_info 985 1006
get_identity_by_public_key_hash_with_proof_info 1016 1039

TypeScript consumers relying on these types will expect undefined but receive null, which can cause subtle bugs (e.g., === undefined checks will fail).

🐛 Proposed fix (example for get_identity_with_proof_info)
         let data: JsValue = match identity {
             Some(identity) => IdentityWasm::from(identity).into(),
-            None => JsValue::NULL,
+            None => JsValue::UNDEFINED,
         };

Apply the same change to all affected methods listed above.

Replace 6 Lazy<Mutex<Option<T>>> statics with instance-owned state.
Introduce WasmTrustedQuorumCache as an explicit JS-exported object
for prefetching and sharing trusted quorum data.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@shumkov
shumkov force-pushed the refactor/sdk/static-context branch from f93f3d8 to 7368973 Compare February 3, 2026 14:05

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Fix all issues with AI agents
In `@packages/js-evo-sdk/src/sdk.ts`:
- Around line 93-122: The connect logic attaches a trusted context
unconditionally which causes wasm.WasmSdkBuilder.withTrustedContext(context) to
override caller-provided addresses from
wasm.WasmSdkBuilder.withAddresses(addresses, network); change the flow in the
connect method so that if options.addresses is provided (addresses &&
addresses.length > 0) you do NOT prefetch/attach the trusted context (skip
calling wasm.WasmTrustedContext.prefetch* and builder.withTrustedContext),
otherwise keep the existing prefetch and withTrustedContext behavior; reference
the symbols WasmTrustedContext.prefetchMainnet/prefetchTestnet/prefetchLocal,
WasmSdkBuilder.withAddresses, and withTrustedContext to locate and update the
code.

Comment thread packages/js-evo-sdk/src/sdk.ts Outdated
@QuantumExplorer
QuantumExplorer merged commit 4f22b17 into v3.1-dev Feb 8, 2026
103 of 104 checks passed
@QuantumExplorer
QuantumExplorer deleted the refactor/sdk/static-context branch February 8, 2026 23:39
@github-project-automation github-project-automation Bot moved this from In review / testing to Done in Platform team Feb 8, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

3 participants