Skip to content

bug(wasm-sdk): Custom addresses overwritten by withTrustedContext(), preventing trusted mode with custom nodes #3172

@thephez

Description

@thephez

Expected Behavior

When providing custom masternode addresses via WasmSdkBuilder.withAddresses(), the SDK should be able to use those addresses with trusted mode enabled for proof verification:

// wasm-sdk direct usage
const context = await WasmTrustedContext.prefetchTestnet();
const sdk = WasmSdkBuilder
  .withAddresses(['https://my-node:1443'], 'testnet')
  .withTrustedContext(context)
  .build();
// Should connect to https://my-node:1443 with proof verification enabled
// js-evo-sdk usage
const sdk = new EvoSDK({
  addresses: ['https://my-node:1443'],
  network: 'testnet',
  trusted: true,
});
await sdk.connect();
// Should connect to https://my-node:1443 with proof verification enabled

This is necessary for:

  • Connecting to devnets with full proof verification
  • Debugging against a specific masternode with security guarantees
  • Production use of custom nodes (proof verification is essential)

Current Behavior

Custom addresses are silently overwritten when trusted mode is enabled. In packages/wasm-sdk/src/sdk.rs:304-321, with_trusted_context() unconditionally replaces the address list with addresses discovered from the network's quorum sidecar:

pub fn with_trusted_context(self, context: &WasmTrustedContext) -> Self {
    let discovered = context.discovered_addresses();

    let inner = if !discovered.is_empty() {
        let address_list = AddressList::from_iter(discovered.to_vec());
        self.inner
            .with_address_list(address_list)  // ← overwrites user-provided addresses
            .with_context_provider(context.clone())
    } else {
        self.inner.with_context_provider(context.clone())
    };
    ...
}

Confirmed that prefetchTestnet() discovers ~60 masternodes from https://quorums.testnet.networks.dash.org/masternodes, so discovered.is_empty() is always false for testnet/mainnet. Custom addresses are always overwritten.

Workaround exists but sacrifices security

Custom addresses do work if you skip trusted mode entirely and use unproved queries:

// wasm-sdk: works but NO proof verification
const builder = WasmSdkBuilder.withAddresses(['https://my-node:1443'], 'testnet');
const sdk = builder.build();
const identity = await sdk.getIdentityUnproved(identityId); // must use unproved methods

This works because:

  • Without withTrustedContext(), custom addresses are preserved
  • getIdentityUnproved() bypasses proof verification, avoiding the "Non-trusted mode is not supported in WASM" error that would occur with proved queries

However, this is not suitable for production as responses from the node are trusted blindly without cryptographic proof verification.

The downstream js-evo-sdk (packages/js-evo-sdk/src/sdk.ts:112-129) inherits this issue — when trusted: true is set, custom addresses are silently ignored.

Possible Solution

In packages/wasm-sdk/src/sdk.rs, with_trusted_context() should only replace addresses when the builder was not initialized with user-provided addresses:

// Only use discovered addresses if no user-provided addresses exist
let inner = if !discovered.is_empty() && !self.has_user_addresses {
    let address_list = 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())
};

This could be tracked with a has_user_addresses: bool field on WasmSdkBuilder, set to true in new_with_addresses() and false in the preset constructors (new_mainnet, new_testnet, new_local).

For full devnet support, a way to provide a custom quorum sidecar URL would also be needed (similar to the existing prefetchLocalWithUrl() but for arbitrary networks).

Steps to Reproduce

import init, * as sdk from '@dashevo/wasm-sdk';

await init();
const context = await sdk.WasmTrustedContext.prefetchTestnet();
const builder = sdk.WasmSdkBuilder
  .withAddresses(['https://specific-node:1443'], 'testnet')
  .withTrustedContext(context);
const client = builder.build();
// client connects to discovered testnet nodes, NOT https://specific-node:1443

Context

The combination of two constraints creates a gap:

  1. WASM requires trusted mode for proof verification (WasmContext errors with "Non-trusted mode is not supported in WASM" on get_quorum_public_key)
  2. Trusted mode overwrites custom addresses via withTrustedContext()

This means there is no way to use custom addresses with proof verification in WASM. Users must choose between custom addresses (no proofs) or proof verification (no custom addresses).

Your Environment

  • Package: @dashevo/wasm-sdk / @dashevo/evo-sdk 3.1.0-dev.1
  • Environment: Any WASM environment (browser, Node with WASM)
  • Affected files:
    • packages/wasm-sdk/src/sdk.rs (lines 304-321 — with_trusted_context)
    • packages/wasm-sdk/src/sdk.rs (lines 202-248 — new_with_addresses)
    • packages/js-evo-sdk/src/sdk.ts (lines 112-129 — connect)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions