Skip to content

wasm32: statement-store / Bulletin allowance allocation is stubbed, so no browser host can create a statement proof (UnableToSign) #363

Description

@tommyldev

Summary

On wasm32, allocate_statement_store_allowance and allocate_bulletin_allowance are hard stubs. Because those functions are what derive and return the statement-store secret, no browser-hosted product can create a statement proof at all — statement_store.create_proof_authorized fails UnableToSign.

Still present on main (rust/crates/truapi-server/src/runtime/signing_host/sso_responder.rs, unchanged from vendored revision b0e70f91):

// native, line 852 — real work, returns the key material:
Ok(allowance.secret.to_bytes().to_vec())

// wasm32, line 1014:
#[cfg(target_arch = "wasm32")]
pub(super) async fn allocate_statement_store_allowance(
    _services: &Arc<RuntimeServices>,
    _signing_host: &SigningHost,
    _product_id: &str,
    _policy: OnExistingAllowancePolicy,
) -> Result<Vec<u8>, AllowanceAllocationError> {
    Err(AllowanceAllocationError::NativeOnly { resource: "statement-store" })
}

// wasm32, line 1026: same stub for `allocate_bulletin_allowance`

Observed behaviour

A product calls RFC-0010 resource_allocation.request for
[StatementStoreAllowance, BulletinAllowance, SmartContractAllowance, AutoSigning] and gets:

["NotAvailable", "NotAvailable", "NotAvailable", "Allocated"]

with, per refused item:

WARN truapi_server::runtime::signing_host: direct resource allocation item failed
  {product_id=…, reason=signing host: statement-store allowance allocation is native-only}

Then statement_store.create_proof_authorized returns UnableToSign (i.e. RemoteStatementStoreCreateProofError::UnableToSign — signing failed, not UnknownAccount), and statement_store.submit is never reached. These are one defect, not two: no allocation ⇒ no ss_secret ⇒ nothing to sign with.

Not account state

Reproduced against live paseo-next-v2 with a freshly minted BIP-39 identity registered as a lite person via the DotSpark attester, holding a confirmed on-chain statement-store allowance (ring committed at index 156). Under full TRACE the resource_allocation.request span opens and closes with no nested chain query — the refusal is unconditional. Sibling capabilities on the same transport all work: local_storage.*, statement_store.subscribe, permissions.request_remote_permission, account.get_user_id, chain.*.

Impact

Any wasm32 embedder is affected. Concretely, Epoca (Firefox fork, vendors @useragent-kit/wasm@0.6.13) cannot serve statement writes for any product: its own nightly packaged-live-contracts reports statement-store=non-passing / chain-query=non-passing against production dot://t3ams-spa.dot, and the T3ams SPA loses DM/group/channel messaging entirely. Embedders cannot compensate — the missing artifact is secret key material produced inside these functions, so there is no host callback or product-side workaround.

Porting notes

The wasm-hostile parts of the native implementation (852-1011) look bounded:

  • current_unix_secs() uses std::time::SystemTime (also cfg(not(wasm32)), ~line 1036) — chain-derived time is already available in the runtime;
  • the Bulletin/People RPC path (BulletinRpcClient, wait_bulletin_authorization) — host_rpc_client already serves chain RPC on wasm for chain.* and statement_store.subscribe;
  • the MissingLitePeopleMembership ring check — same RPC surface.

Alternatively, accept an already-confirmed on-chain allowance on wasm instead of performing the allocation, and/or expose a host hook so an embedder that can already claim it (Epoca does, in EpocaAllowance.ensure()) can satisfy the slot.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions