Skip to content

feat(truapi): JamPeerTransport host service (layer atop #540) - #1010

Draft
replghost wants to merge 40 commits into
feat/pvm-app-runtimefrom
feat/pvm-peer-transport
Draft

replghost wants to merge 40 commits into
feat/pvm-app-runtimefrom
feat/pvm-peer-transport

Conversation

@replghost

@replghost replghost commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

Current repair qualification — 2026-10-02

  • Current source: ab46811b1e02469119a94706d7b4a01c9fc57839. Canonical peer artifact-generation and Wasm revisions are this same commit. Prior main-integration baselines are retained: native bda6ac518c8cc59319491b12e4e23b96777375fd, frontend f4012c50c3400d1186c332ad2ae50298cefd153d.
  • Consumers: dotli #290 at 19a9c5aeb0f0f6ef33151ca66da3bb147efa5936. Complete matching SDK/host packages remain 0.23.0; codegen and Wasm were rebuilt canonically. Generated client bytes are unchanged. Production features: wasm-signing-host; separate testing bundle: wasm-signing-host,test-host.
Canonical artifact SHA-256
Client npm archive 5efd803fff8452ecb1fbc9d23e58a28298d1ec256e7cf66b55ea567b67703077
Client dist/generated/client.js 5fe2e73ed9f9210045a1ad456e29632cff8fa3acbb2cc2054f8774a6633f57a5
Host npm archive 1a99b8c8ab0f9e22ccc24d78273cc2c42d621e368fc31587f93699dc999a8a36
Browser signing Wasm b80462f2f938ccb3aaef6035bb2dccd71159588cc9d8a887f00450c558bc1113
Local QA CLI 56b0027e01fc1d08bb547a4489bbc08ef778f913eea08f68d56f79d114657a91

Native correction and causal limits

Bulletin mortal signatures now anchor to a finalized checkpoint, while nonce/runtime state comes from the freshest available signing snapshot. A checkpoint at least 64 blocks behind is rejected before broadcast. Regression coverage verifies the actual signature with a newer nonce and older finalized checkpoint, and the expiry boundary. Existing transaction retries/deadlines are unchanged; no chain error is suppressed. The affected test fixture uses parking_lot::Mutex.

The former Seity Extrinsic marked as invalid run used noncanonical best-block anchors, but retained evidence lacks the signed bytes and typed pool reason. Fork-sensitive mortality was a real correctness hazard; it is not claimed as the conclusively proved cause of that historical failure. Prior hosted Factory/Genesis timeout causes also remain unproved. No broker/readiness workaround, prewarming, extra retry, or timeout increase was added.

Executed verification

  • Exact-head native CI: success, 25 successful jobs, 1 skipped (E2E (playground inside dotli)); job totals include control jobs. This is the CI workflow result, not an assertion that every advisory PR check or release credential is green.
  • Each of the five native variants passed 21 Bulletin RPC regression tests, all-target Clippy with -D warnings, CLI build, and canonical browser/testing Wasm packaging. Base full library: 1,246 passed.
  • All six frontend consumers passed configured build, typecheck and lint. The later frontend-only formatting correction passed targeted Prettier checks; it did not change runtime source or canonical native artifacts.
Local original sequence Tested frontend head Result, retries=0 Genesis after navigation Factory Submit
#238 0a24db4aa189adad7b93f9ff508c7949e39196ee 42 passed, 20 skipped; no failed/flaky cases 1107ms 9625ms 6057ms
#255 301a235ba13248ef4281e9e3d859919fb6cfbe06 42 passed, 20 skipped; no failed/flaky cases 1045ms 11023ms 13548ms
#287 d3dc8a41807c36b8bcdf001c47eccb9735305499 42 passed, 20 skipped; no failed/flaky cases 1029ms 6496ms 5530ms

The Chat/Seity tested heads above precede documentation-only formatting merges; their native/Wasm pins and runtime code are unchanged. Final hosted frontend results are recorded on the linked consumer PRs, separately from these exact-head local results.

Final hosted retest: failures remain

Frontend PR Tests workflow Functional E2E
#238 success 79 passed 42 passed, 20 skipped
#185 success 89 passed, 3 skipped 41 passed, 1 flaky, 20 skipped
#255 success 89 passed, 3 skipped 42 passed, 20 skipped
#287 failure 85 passed, 4 failed, 3 skipped 42 passed, 20 skipped
#290 success 87 passed, 2 failed, 3 skipped 42 passed, 20 skipped
#291 failure 86 passed, 5 failed, 3 skipped 41 passed, 1 flaky, 20 skipped
  • PVM and JAM Genesis Hash still flaked after navigation: the product stayed pending for the helper's existing 20 seconds; the existing CI retry passed. The helper reports this timeout as error; it is not evidence of a chain rejection. Retained traces include People-chain/local development sockets but do not expose the Asset Hub gateway WebSocket exchange, so these new failures do not establish an upstream or broker cause.
  • Peer: two navigation product-render timeouts at 45 seconds. The existing threshold tolerates these, so its green workflow is not a clean functional suite.
  • Seity: cache-off RPC-gateway resolution timed out; two navigation renders timed out; another navigation case reported failure to connect to trusted provider paseo-bulletin-next-ipfs.polkadot.io. The zero-failure host-settings gate correctly failed.
  • JAM: cache-on reload and two navigation cases reported that same provider connection error; two more navigation cases timed out. The zero-failure host-settings gate correctly failed. These logs do not establish whether the underlying cause was provider availability, runner networking, CORS, or another transport failure.
  • All six final Static Analysis and hosted cold-start Performance workflows passed; all five native CI workflows passed. That does not clear the red functional gates, Genesis flakes, or Doom matrix. No additional CI rerun, timeout/retry increase, threshold relaxation, or speculative transport patch was made.

Doom: criterion corrected, backend matrix still unqualified

The user explicitly approved 35 FPS sustained over 30 seconds, with one frame of sampling-boundary tolerance: frames + 1 >= elapsedMs * 35 / 1000. This replaces the instantaneous FPS >= 35 sample; it is an acceptance-criterion change, not a runtime speedup. Runtime and displayed FPS are unchanged; raw samples are not rounded to force a pass. Update p95 <28.6ms, cold/warm first-frame limits <3,000/<1,000ms, audio and translation-cache checks remain. The revised official RPC benchmark passed once before the vendor replacement.

The later isolated matrix used the rebuilt base pair at frontend 238ab5fa739788b2eb948ba1f807a1876edbacad, with fresh owned Chrome profiles and no concurrent builds/E2E:

Backend Observed result Qualification
smoldot-direct 1,050 frames / 30,001.1ms; p95 17.7ms; cold/warm 202.9/152.8ms; audio/cache passed PASS under the approved criterion
smoldot-shared-worker 1,038 frames / 30,001.4ms = 34.5983854 FPS; p95 17ms; cold/warm 186.4/158.4ms; other checks passed FAIL: cadence deficit retained
rpc-gateway Warm-readiness helper timed out. Its null snapshot conflated missing frame, missing canvas and evaluation errors, and earlier cold/cadence values were not retained by that helper NOT QUALIFIED; iframe disappearance is not established

Distinct diagnostics found no presentation loss in a later instrumented 24-second shared-worker sample and observed a successful hidden RPC new-document reload. Neither diagnostic supersedes the failures or qualifies performance. No evidence-proved runtime fix, guest rebuild, speculative tuning, or further unchanged gate rerun was made. The original strict RPC failure and every new failure remain retained. Next causal capture must instrument the original early 30-second window and distinguish warm lifecycle states before proposing a runtime fix.

Retention and rollout boundary

Local verification used paseo-next-v2, the pinned host-playground fixture f56294cea4430163bf16ec068844b1327441073c, and existing private QA identities. All three corrected sequences paired on their first existing setup attempt. A prior local launch failure and a misconfigured Previewnet-product run (34 passed, 20 skipped, 8 Chain/Contract failures) are retained separately, not presented as reproductions of the hosted Genesis timeout. Private traces/auth/signers were not published.

The first repair heads also exposed a README formatting failure (corrected by documentation-only commits) and a PVM cache-unit-test 5,000ms timeout. No cache runtime/test change, limit increase, or causal claim was made for that isolated timeout. Older in-flight runs superseded by the formatting correction remain recorded as cancelled, not passed.

No PR merge, force push, deployment, environment approval, SDK/npm/product/guest publication, or rollback was performed by this repair. JAM remains JAM-TEST-INSTANCE, never JAM-PUBLIC-DEVNET. The user-owned deploy: paseo.fyi label is retained; repair-triggered deployment runs 36970790399 and 36971286469 were cancelled before deployment. The earlier rollout audit is retained below: an older workflow deployed 56cea5d37577bf82684fb5c6b6e4ba81d2142938; this record does not claim live remained unchanged historically.

Historical integration qualification (superseded; retained verbatim)

Current main refresh and qualification — 2026-10-01

  • Current source: 3cc0e5c44850a5f87606bf065a7603a17c342ed8. Native main bda6ac518c8cc59319491b12e4e23b96777375fd is integrated; the frontend stack includes dotli main f4012c50c3400d1186c332ad2ae50298cefd153d (merged chore(deps): bump postcss from 8.5.15 to 8.5.23 in /explorer #313). Histories and worktrees were preserved; pushes used fetched-head ancestry guards, never force.
  • Canonical peer artifact-generation revision: 79cd7de8a7ccb4ef27e81ae158f6e7cf9aedffd6. Later native changes are test/docs/iOS-only, not SDK/Wasm inputs, so the artifact pin intentionally differs from the current head. Complete matching client and host packages remain 0.23.0, generated rather than hand-edited. Browser signing Wasm uses web-wasm-signing-host without test-host; testing Wasm is separate.
  • Browser consumers: dotli #290 at 44ed4f830a2c8f86990e02fb061c802aa389b0bc.
Canonical artifact SHA-256
Client npm archive 5efd803fff8452ecb1fbc9d23e58a28298d1ec256e7cf66b55ea567b67703077
Client dist/generated/client.js (not dist/index.js) 5fe2e73ed9f9210045a1ad456e29632cff8fa3acbb2cc2054f8774a6633f57a5
Host npm archive a17d04963c096d859699e88f41c473e899a84fa90a5dc3f05ce2018f57752459
Browser signing Wasm cddf79e80de21e517b97ad2156611f09bb77c4c55016994384efb7bb593cbdb2

Qualification

  • Frontend #290 exact-head Tests: functional 89 passed, 3 skipped; E2E 42 passed, 20 skipped. No flaky case in this final hosted Tests run.

  • Current-head Core CI: 24 required jobs green — 22 passed, 2 path-filter skips. This includes core Swift/Android coverage, not a claim that full iOS application CI ran at this head. The separate existing release-signing-credentials advisory failure remains distinct from Core CI.

  • Local: Rust workspace: 1,849 passed across 29 suites, 22 ignored. Client/host SDK: 320/285 passed. Live JAM test passed (1 test, 1.11s). Canonical codegen and complete feature-specific package construction were qualified locally.

  • Browser/native proof: Actual installed PVM host-frame-request path passed with the canonical SDK: trusted product/full-genesis consent, deny/dismiss without dialing, real certificate-verified WebTransport and UP0 open/send/receive, 73-byte handshake and 333-byte block announcement, independent genesis grants, close/reset, stale-frame rejection, pagehide disposal, and replacement-execution re-consent. Target: JAM-TEST-INSTANCE, genesis 0x10c123f02eb6df4c01397d797a112055be691883baa2e82f83b618ed6ce45e46. No TLS bypass or new published guest. Evidence: main-refresh-peer-pvm-live.json and screenshots.

Retained cross-stack limits

  • The isolated strict Doom matrix is not fully green: RPC measured 34.54231433545555 FPS against ≥35 FPS. Direct smoldot measured 35.06721215581914 and shared-worker smoldot 35.48895899032775. All three passed p95/cold/warm/cache/audio criteria; warm runs used a new document and zero translation. No threshold, clock, timeout, or retry policy was weakened.
  • Latest local Seity E2E attempt: 41 passed, 20 existing skips, 1 Submit failure (Extrinsic marked as invalid). Two existing native broadcast attempts were validated then invalidated; none was found included in the inspected canonical range. [INFERENCE] Noncanonical mortality anchors may explain invalidation; the exact cause is not established and signed extrinsic bytes were not retained. The earlier Factory deadline failure is also retained: inclusion took 47,516ms against the unchanged 30s product deadline. A separate unchanged manual Factory attempt passed in 10.918s. These failures are not erased by other passing checks.
  • Evidence JSON/screenshots are retained beside the refresh worktrees; private browser profiles and throwaway harnesses were removed. No bearer references, keys, signing configuration, or .auth contents are included here.

This refresh authorizes no deployment, environment approval, PR merge, SDK/npm publication, or guest/product publication. Its QA writes were testnet-only.

All three refresh-triggered JAM Deploy runs were cancelled before rollout; final-head cancellation proof is for frontend dcdef40499119183aed82a39f784ef740d494341. No refreshed source head was deployed.

The live environment changed during qualification: older Deploy run 36945647296, attempt 3 was approved under GitHub account replghost, explicitly checked out baseline 56cea5d37577bf82684fb5c6b6e4ba81d2142938, and recorded deployment success at 2026-10-02 01:19:01 UTC. Its later published-product smoke failed. The operator/client/session behind that account is unproven; this qualification granted no approval and performed no rollback. The observed live content hash changed from 4a7caf047fb7f350c1833039b93ba634698a47c56f051b8c7fc0525d4c59a5c8 to 5882695ee20df5d24a6ed2feb9e997f176fe27ecf4eafe742fabb39eba92885f; these are content hashes, not Git SHAs, and their exact byte-level mapping to a source commit is unproven. Earlier revision/deployment records below remain historical evidence and do not override this current section.

Execution callback ownership

createProvider(product, callbacks) binds platform callbacks to one execution of a shared native host. Retired executions cannot route later callbacks through the core's default callback scope; wallet authentication and storage retain core ownership. Native contacts installed after core construction remain available unless the execution supplies its own contacts adapter.

Current head: 87868067f1277491723ee5fd454d5ff43fb42a8a. Canonical codegen, default web/testing Wasm, signing-only browser Wasm, host SDK tests, and harness typing are qualified. Hosted CI is green, including Rust workspace, Wasm bridge, Android compilation and iOS Swift/WebKit checks. No package publication.

Earlier source and qualification (superseded)

Head f18d4c8ea676c034704026de7644fbba0d12e0d7 includes main aa6ae62ca038bf4a6356edae8eb78e595d52ce24 through history-preserving merge commits. Client and host package manifests remain 0.23.0 with pending Changesets.

The branch includes the integrated main changes and preserves its feature boundary. Root and combined-stack canonical codegen and TypeScript qualification pass. This branch’s current-head Codegen CI job passes; its downloaded canonical output matches all 45 tracked generated files byte-for-byte. Full workspace/native qualification remains tracked by current-head CI.

Current-head core CI passes, including Rust workspace, default WASM bridge, Android compile/unit checks, and iOS Swift + WebKit. Full local workspace/native qualification was interrupted by workstation disk exhaustion; the full current-head core CI gate completes that qualification. Full iOS application CI also passes, including the in-tree core, application build, simulator preview, and tests. No PR was merged or approved, and no npm package was published. Deployment evidence below belongs to the explicitly named earlier revisions, not this source refresh.

Summary

Adds the JamPeerTransport TrUAPI host service (wire trait 111) so a PolkaVM app can observe a JAM network directly over JAMNP-S, the way a light client does, instead of through an application-specific proof relay. The service is JAM-specific (the JamPeers permission, the jamnp-s ALPN, JAMNP-S peer identity and framing), hence the name.

  • Methods: dial, open, send, recv, reset, close, events. The host terminates QUIC (native) or WebTransport (browser), builds the jamnp-s/1/<genesis8> ALPN from the dialed genesis, pins the peer's certificate identity, and frames/unframes u32-LE JAMNP-S messages. It never interprets JAM messages; the guest verifies everything it receives.
  • Permission: access is a runtime permission, not a manifest capability, matching the existing TrUAPI model (Remote { domains }, WebRtc, ChainSubmit, ...). RemotePermission gains JamPeers { genesis: [u8; 32] }, appended last (SCALE index 5, earlier indices unchanged), displayed as "connections to JAM network 0x<first 8 hex>…". Before a dial connects, the host requires JamPeers { genesis } exactly like ChainSubmit: it reads the product's stored decision, prompts when it is undetermined and persists the answer per product and genesis (the storage key is the canonical request, so each genesis is its own slot). The decision is cached for the execution, so a light client dialing six validators is asked at most once per genesis. Denied or unsupported is NotGranted; the other methods act only on connections a granted dial opened. App manifests declare nothing and there is no host-side allowlist.
  • Rust core: native product runtimes serve the service themselves (see Native implementation). Every dial first runs ProductRuntimeHost::require_jam_peers(genesis), which reads the stored decision, prompts while it is undetermined and persists the answer; a one-use answer is held for the execution rather than spent by the first dial. The browser (wasm) core keeps the trait's NotGranted defaults, since its JavaScript session answers trait 111 before frames reach the core.
  • Browser session: @parity/truapi/jam-peer-transport implements the service over the WebTransport API. createJamPeerTransportSession({ authorize, connect?, now? }) calls authorize(genesisHex) at most once per genesis per session (concurrent dials share the pending answer; false or a rejection is NotGranted). A host with the Rust core implements authorize through permissions.authorizeRemotePermission({ permission: { tag: "JamPeers", value: { genesis } } }). It also ships the deterministic PolkaJAM certificate-hash derivation needed for serverCertificateHashes (PolkaJAM nodes serve WebTransport on their JAMNP-S port with an unsigned P-256 certificate per fixed validity period).
  • Native apps: the Android and iOS product bridges route JamPeers { genesis } through their existing remote-permission prompt and storage, keyed per product and genesis (" would like to connect to JAM network 0x10c123f0…", "Read-only peer access to this network's validators, with no accounts or signing."). The CLI host prompts through its approval policy with the permission's display text.

WebTransport certificate serials. Stock PolkaJAM gives every P-256 WebTransport certificate issuer CN=jam and serial 0, and Firefox's NSS rejects a second, different certificate with the same issuer and serial (SEC_ERROR_REUSED_ISSUER_AND_SERIAL), so Firefox reached one validator of six. jam-explore's polkajam-webtransport-serial.patch derives the serial from the key and validity period (first 8 bytes of SHA-256(compressed key ‖ period as big-endian u64), top bit cleared, 1 if zero). The browser adapter now pins both variants for each of the three periods (six hashes), so stock nodes keep working and every patched node is reachable in Firefox. Vectors are certificates real patched and stock nodes served, byte for byte. The native QUIC path pins the Ed25519 key, not the serial, and is unchanged.

Native implementation

Native product runtimes (iOS, Android, CLI) serve JamPeerTransport themselves: truapi::jam_peer_transport holds a JAMNP-S QUIC client (quinn + rustls/ring, self-signed Ed25519 identity, u32-LE framing, the 8/16/1 MiB/4 MiB caps), and ProductRuntimeHost implements the trait over one session per product connection. The code is the tested jam-peer-transport-native crate from the JAM light-client work, ported into the core. The wasm build is unchanged: the browser core keeps the trait's NotGranted defaults, and the new dependencies are native-only.

  • Every dial runs require_jam_peers(genesis) once per genesis per connection. Concurrent dials share the pending answer, a refusal stays NotGranted without asking again, and the check runs on the runtime spawner, so an answer given after the dial gave up is still persisted.
  • A dial answers within 10 s, prompt included (Unreachable after that, Cancelled on CANCEL), and what it would have opened is dropped without holding a connection slot.
  • The ALPN is jam_peer_transport::alpn(genesis). The peer certificate must carry the dialed Ed25519 key under its JAMNP-S alternative name, and the TLS 1.3 signature is checked against that key. The P-256 key is for WebTransport hosts and is ignored.
  • The first granted dial creates the endpoint, so a refused product binds no socket. ProductRuntime::dispose closes every peer connection, the close frames are sent before the endpoint's runtime stops, and later calls are Denied.
  • Receive semantics follow the browser session: a finish or reset is reported once the queue is drained, after which the receive side is Closed. At most 1024 undrained events are kept.
  • iOS and Android route JamPeers { genesis } through their existing remote-permission prompt and storage, keyed per product and genesis (" would like to connect to JAM network 0x10c123f0…", "Read-only peer access to this network's validators, with no accounts or signing."). The CLI host already prompts through its approval policy with the permission's display text.

Stacking

This is a separate layer on top of #540, not part of the generic PolkaVM app runtime. It must not be merged before #540, and #540 does not depend on it. The browser consumer is paritytech/dotli-community#290, the matching layer on top of paritytech/dotli-community#185.

Security

This is the first outbound-network capability offered to PolkaVM apps. It is scoped to one user-approved genesis per decision, to endpoints the app names, and to the peer identity the app pins (Ed25519 key for QUIC, P-256-derived certificate hashes for WebTransport). Caps: 8 connections, 16 streams per connection, 1 MiB messages, 4 MiB buffered per connection. No HTTP, DNS, arbitrary hosts, accounts, signing, submission or storage authority is implied. Bytes are untrusted until the app verifies them. Like every RemotePermission, products on REMOTE_PERMISSION_TRUSTED_LABELS hold it without a prompt unless a stored decision says otherwise.

Artifacts and qualification

Main is integrated through c5158448f3c4575f40350017d466053d6b19dacb. The consumer paritytech/dotli-community#290 pins matching TrUAPI client/host 0.23.0 and wallet WASM from c73e072c96cff7d363af9a61e378ee22621e9f5b, with exact archive/client/WASM digests in its vendor lock. Later CI/tooling integration does not change that runtime artifact.

Local native checks, wallet/testing WASM builds, 11 JAM-peer tests, and three transport tests pass. At 4a9a390055d5b97cf3d564df9c1ac51a55e4ee1d, all PR checks pass, including core CI, full iOS CI, and Android APK packaging.

The iOS workflow always preserves xcresult, raw build/simulator logs, and available crash reports, and prints the test summary/list. Diagnostic capture was smoke-tested with real Xcode result fixtures and exercised successfully by the hosted run. No tests, retries, or parallelism settings were changed. An earlier iOS test failure discarded its diagnostics, so its cause is not established; the current full test run passes.

The consumer checks pass; the combined deployment is qualified separately in paritytech/dotli-community#291. No new live JAM-validator trial was performed for this refresh.

Adds TrUAPI trait 21, PeerTransport: host-terminated JAMNP-S streams to
JAM peers (dial/open/send/recv/reset/close/events). The host terminates
QUIC or WebTransport, builds the jamnp-s ALPN from the declared genesis
and pins the peer's certificate identity; the guest verifies every byte
it receives.

A host may grant it only to an execution whose App manifest v2 declares
capabilities.network.jam = { genesis }, for that genesis only, with
bounded connections, streams and message sizes. The default
implementation, including the Rust product runtime, returns NotGranted.

Ships the browser WebTransport session and the deterministic PolkaJAM
certificate-hash derivation under @parity/truapi/peer-transport, with
SCALE codec vectors pinned against the Rust types.
@github-actions github-actions Bot added javascript Pull requests that update javascript code rust Pull requests that update rust code labels Sep 26, 2026
@github-actions

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

CI Status: 24 required jobs green, 23 passed and 1 skipped by path filter.

All job results
job result
android-bindings success
bundle-size success
changes success
changeset-guard success
cli-package success
codegen success
e2e skipped
explorer success
headless-install success
host-android-bindings success
host-android-detekt success
host-wasm success
ios-bindings success
ios-swift success
licenses success
playground success
provider-android-bindings success
release-guard success
rust success
ts-client success
ts-debugger success
ts-host success
wasm-provider success
workflow-lint success

Signing credentials: failure as of 2026-10-02, a release may fail

Commit c923399a · run log

@github-actions

github-actions Bot commented Sep 26, 2026 •

Copy link
Copy Markdown
Contributor

iOS simulator preview

Built from 87868067f, stamped with it in TrUAPICommit.

gh run download 36816443890 --name simulator-preview-87868067f
unzip polkadot-app-*.app.zip
xcrun simctl install booted polkadot-app.app
xcrun simctl launch booted io.parity.polkadotapp.develop

Or download it in a browser, which arrives as a zip wrapping
the .app.zip, so it needs unzipping twice.

An arm64 simulator slice, so it needs an Apple Silicon Mac and does not
install on a device. Kept for 14 days, after which the link stops
resolving and a new push rebuilds it.

Contacts (#17) and Game (#990) both claim trait 20, so whichever lands
second is expected to take 21, and Profile holds 22. 23 keeps
PeerTransport clear of all three before any guest bakes the id in.
Peer access is now a runtime permission rather than an App-manifest
capability, matching the rest of TrUAPI (Remote, WebRtc, ChainSubmit).
RemotePermission gains JamPeers { genesis }, appended as variant 5 so
every earlier index is unchanged; its decision is stored per product and
genesis like any other remote permission.

ProductRuntimeHost::require_jam_peers checks the stored decision,
prompts while it is undetermined and persists the answer, keeping a
one-use grant for the execution so a light client dialing several
validators is asked once per genesis. The product runtime's
PeerTransport still answers NotGranted. The manifest grant and its
parser are gone; the genesis parser and ALPN helper stay.

The browser session takes an authorize(genesis) callback instead of a
fixed genesis, asks once per genesis per session and shares a pending
answer between concurrent dials. The Android and iOS product bridges
deny JamPeers without a prompt, as neither ships a JAM transport.
@github-actions github-actions Bot added documentation Improvements or additions to documentation rfc host-ios Touches the iOS host tree host-android Touches the Android host tree labels Sep 27, 2026
replghost added a commit that referenced this pull request Sep 27, 2026
Brings #1010's switch from the manifest grant to the
RemotePermission::JamPeers runtime permission into the Seity layer.
Kept both sides of the permission storage-key test (Chat authority and
JamPeers keys); regenerated the client catalog wire hash with codegen.
A dial waiting on the JamPeers prompt could outlast the guest's request
timeout; the guest retried and the original dial later opened a
connection nobody knew about, holding a slot until the session closed.
Dials now answer within 10 s (prompt + handshake), CANCEL withdraws an
in-flight dial with Cancelled, and anything opened after withdrawal is
closed without holding a slot. The permission decision is still
remembered.
@replghost replghost changed the title feat(truapi): PeerTransport host service (layer atop #540) feat(truapi): JamPeerTransport host service (layer atop #540) Sep 27, 2026
replghost added a commit to paritytech/dotli-community that referenced this pull request Sep 27, 2026
Follows paritytech/trinity-user-agents#1010 at 50284f97, which renames the
TrUAPI service to JamPeerTransport because it is JAM-specific (JamPeers
permission, jamnp-s ALPN, JAMNP-S identity and framing). Wire-identical:
trait 23, methods 0..6, same SCALE layout, same JamPeers permission.

The sandbox now imports @parity/truapi/jam-peer-transport
(createJamPeerTransportSession, JamPeerTransportSession,
JAM_PEER_TRANSPORT_*), and the vendored @parity/truapi and
@parity/truapi-host are rebuilt from that commit.
replghost added a commit that referenced this pull request Sep 28, 2026
Trait ids on main run 1-19 and are handed out in merge order: open PRs
already claim 20 (Contacts, Game) and 22 (Profile), and the next ones are
likely to take 21-24. JamPeerTransport is unmerged, so moving it clear of
that range now costs no deployed compatibility. Methods 0..6 and every
SCALE payload are unchanged; only the trait byte moves from 23 to 111.
replghost added a commit that referenced this pull request Sep 28, 2026
… 111

# Conflicts:
#	rust/crates/truapi-client/src/generated.rs
replghost and others added 2 commits September 28, 2026 19:12
Native product runtimes (iOS, Android, CLI) now implement JamPeerTransport
themselves instead of answering NotGranted. The JAMNP-S QUIC client is
ported from jam-explore's tested jam-peer-transport-native crate (quinn +
rustls/ring, self-signed Ed25519 identity pinned by the peer's JAMNP-S
alternative name, u32-LE framing, per-execution caps) into
truapi_server::jam_peer_transport, native targets only.

Each product connection owns one session. A dial runs require_jam_peers once
per genesis on the runtime spawner, so concurrent dials share one prompt, a
refusal is remembered, and an answer given after the dial gave up is still
persisted. A dial answers within 10 s including the prompt, honours CANCEL,
and never holds a slot past its deadline. The endpoint is created by the
first granted dial, so a refused product binds no socket; dispose closes all
peer connections and flushes their close frames. recv reports Closed once the
end of a stream has been consumed, and undrained events are capped at 1024,
matching the browser session.

The iOS and Android product bridges route RemotePermission::JamPeers through
their existing remote-permission prompt and storage, per product and genesis.

Adds tests/live_jam_public_devnet.rs: an ignored test that dials all six
public-devnet validators through ProductRuntime frames, completes UP 0 and
waits for block announcements, and a Linux test proving a refused product
opens no UDP socket.
@socket-security

socket-security Bot commented Sep 29, 2026 •

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addedcargo/​rcgen@​0.14.109610093100100
Addedcargo/​x509-parser@​0.17.010010093100100

View full report

@github-actions

github-actions Bot commented Sep 29, 2026 •

Copy link
Copy Markdown
Contributor

Bundle size report

Compared with main at 19a6645.

Raw Gzip Brotli
truapi-host 7.75 MiB (-37.9 KiB, -0.5%) 5.68 MiB (+47.4 KiB, +0.8%) 5.40 MiB (+39.7 KiB, +0.7%)
truapi-provider 4.03 MiB (-7 B) 1.27 MiB (-5 B) 959.6 KiB (-180 B)
truapi 5.80 MiB (+93.2 KiB, +1.6%) 822.7 KiB (+17.8 KiB, +2.2%) 674.7 KiB (+14.8 KiB, +2.2%)
Total 17.59 MiB (+55.3 KiB, +0.3%) 7.75 MiB (+65.2 KiB, +0.8%) 7.00 MiB (+54.3 KiB, +0.8%)

WebAssembly modules

Raw Gzip Brotli
truapi-host/wasm/web/truapi_server_bg.wasm 2.62 MiB (-67.4 KiB, -2.4%) 1002.8 KiB (+40.6 KiB, +4.2%) 759.8 KiB (+33.3 KiB, +4.6%)
truapi-host/wasm/web/truapi_verifiable_bg.wasm 4.89 MiB 4.64 MiB (-11 B) 4.61 MiB (+537 B)
truapi-provider/truapi_provider_bg.wasm 3.99 MiB (-7 B) 1.26 MiB (-5 B) 951.9 KiB (-180 B)
Changed files (21)
Raw Gzip Brotli
truapi-host/wasm/web/truapi_server_bg.wasm 2.62 MiB (-67.4 KiB, -2.4%) 1002.8 KiB (+40.6 KiB, +4.2%) 759.8 KiB (+33.3 KiB, +4.6%)
truapi/jam-peer-transport.js (new) 23.1 KiB 5.5 KiB 4.8 KiB
truapi/playground/codegen/truapi-dts.js 294.8 KiB (+22.0 KiB, +8.1%) 50.4 KiB (+3.5 KiB, +7.4%) 40.6 KiB (+2.7 KiB, +7.1%)
truapi/explorer/codegen/types.js 221.7 KiB (+17.3 KiB, +8.5%) 30.4 KiB (+2.6 KiB, +9.3%) 24.5 KiB (+2.0 KiB, +9.0%)
truapi/jam-peer-transport-cert.js (new) 9.0 KiB 3.4 KiB 3.0 KiB
truapi-host/web/create-worker-host-runtime.js 62.1 KiB (+8.5 KiB, +15.8%) 13.1 KiB (+1.4 KiB, +11.7%) 11.4 KiB (+1.2 KiB, +11.4%)
truapi/playground/codegen/services.js 101.4 KiB (+6.8 KiB, +7.2%) 15.4 KiB (+1.1 KiB, +7.8%) 12.9 KiB (+918 B, +7.5%)
truapi-host/wallet-allowances.js (new) 6.5 KiB 1.7 KiB 1.5 KiB
truapi-host/worker-runtime.js 43.3 KiB (+6.2 KiB, +16.8%) 10.6 KiB (+1.1 KiB, +11.1%) 9.3 KiB (+948 B, +11.1%)
truapi/generated/client.js 72.5 KiB (+6.0 KiB, +9.1%) 10.8 KiB (+847 B, +8.3%) 8.9 KiB (+703 B, +8.3%)
truapi-host/worker-local-identity.js (new) 5.7 KiB 1.8 KiB 1.5 KiB
truapi/generated/types.js 65.5 KiB (+5.6 KiB, +9.4%) 7.8 KiB (+625 B, +8.4%) 6.7 KiB (+507 B, +8.0%)
truapi/generated/wire-decode.js 29.7 KiB (+2.5 KiB, +9.2%) 3.1 KiB (+230 B, +7.8%) 2.6 KiB (+190 B, +7.7%)
truapi-host/locale.js (new) 1.9 KiB 689 B 622 B
truapi/generated/wire-table.js 9.3 KiB (+774 B, +8.9%) 1.6 KiB (+85 B, +5.5%) 1.3 KiB (+61 B, +5.0%)
truapi-host/generated/host-callbacks-adapter.js 6.5 KiB (+257 B, +4.0%) 1.5 KiB (+40 B, +2.7%) 1.3 KiB (+33 B, +2.6%)
truapi-host/wasm/web/truapi_server.js 58.0 KiB (+217 B, +0.4%) 10.6 KiB (+63 B, +0.6%) 9.1 KiB (+44 B, +0.5%)
truapi-host/generated/worker-callbacks.js 6.6 KiB (+124 B, +1.9%) 1.4 KiB (+24 B, +1.7%) 1.2 KiB (+42 B, +3.7%)
truapi-host/index.js 80 B (+50 B, +166.7%) 80 B (+30 B, +60.0%) 67 B (+33 B, +97.1%)
truapi-host/web/index.js 181 B (+36 B, +24.8%) 123 B (+9 B, +7.9%) 111 B (-7 B, -5.9%)
truapi-provider/truapi_provider_bg.wasm 3.99 MiB (-7 B) 1.26 MiB (-5 B) 951.9 KiB (-180 B)

Commit: c923399

@github-actions github-actions Bot added the github_actions Pull requests that update GitHub Actions code label Sep 29, 2026
@github-actions

github-actions Bot commented Oct 1, 2026

Copy link
Copy Markdown
Contributor

This pull request touches an app, which is not built by default. Add a label for each build you want:

  • iOS simulator build, ios-simulator-build: builds the iOS app, runs its tests and attaches a build for the iOS Simulator on a Mac.
  • iOS device build, ios-device-build: attaches a signed build that installs on a registered iPhone or iPad.

Each starts as soon as it is added and follows the branch from then on.

replghost added a commit that referenced this pull request Oct 3, 2026
# Conflicts:
#	rust/crates/truapi-client/src/generated.rs

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

android-device-build Build an installable Android APK from this pull request documentation Improvements or additions to documentation github_actions Pull requests that update GitHub Actions code host-android Touches the Android host tree host-ios Touches the iOS host tree javascript Pull requests that update javascript code rfc rust Pull requests that update rust code

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants