Skip to content

fix(server): serve product follow aliases and stamp statement expiry - #321

Closed
replghost wants to merge 1 commit into
mainfrom
codex/canonical-live-chain-statements
Closed

fix(server): serve product follow aliases and stamp statement expiry#321
replghost wants to merge 1 commit into
mainfrom
codex/canonical-live-chain-statements

Conversation

@replghost

Copy link
Copy Markdown
Contributor

Problem

Epoca's live A/B against Paseo services (paritytech/epoca#174, evidence in the #168 rollout hold) showed the embedded runtime is not live-equivalent to the shipping legacy host loop, in two ways. Both were reproduced against the live People-next node and hermetically against the shipped wasm bundle:

  1. Rejected papi follow ids → zero Browse products / chain-query timeouts. Every papi product (via @novasamatech/product-sdk) issues chainHead operations carrying the provider's synthetic follow subscription id (follow_0), never the follow subscribe request id. ChainConnection::require_remote_follow strict-matches its own keys and fails with unknown follow subscription id "cN:follow_0", so papi clients never initialize. The host-api protocol documents the field as "the follow subscription ID from the product-SDK (opaque string)", and the native host coordinators (e.g. UserAgentKit's MobileChainFollowCoordinator, Epoca's legacy actor) already resolve it to the session's active follow.
  2. Expiry-less statement submissions rejected live → Statement Store GenericError. Products create proofs for statements without an expiry field and expect the host to stamp one. Deployed statement stores (People-next runs the legacy expiry dialect: u64, unix seconds in the upper 32 bits) refuse expiry-less statements — the node answers {"status":"invalid","reason":"alreadyExpired"} and smoldot's statement store phrases the same rejection as Invalid statement encoding. The runtime signed and submitted the product's statement as-is.

Change

  • chain_runtime.rs: ensure_follow_context now resolves the operation's follow id through ChainConnection::resolve_follow_key. An exact key wins; an unknown session-scoped id is treated as an opaque alias and bound to the session's most recent unaliased follow. Aliases never resolve across session scopes (cN: prefixes), are dropped with their follow, and are bounded per connection. Unknown ids with no active session follow keep the existing error.
  • statement_store: proof creation (create_proof and create_proof_authorized) stamps a one-hour legacy-dialect expiry (priority zero) when the product omitted it, signs the stamped fields, and retains the host-assembled SignedStatement keyed by its proof (entry-bounded bridge in RuntimeServices). Submission prefers those exact retained bytes over the product's pre-proof re-assembly, so the submitted fields always match the proof's signature material; the read-after-write cache serves the statement the store actually accepted.

Validation

  • New regression tests: header_request_binds_product_follow_alias_within_session, header_request_rejects_product_follow_alias_across_sessions, statement_store_create_proof_stamps_missing_expiry_and_retains_statement, statement_store_submit_prefers_host_assembled_statement.
  • cargo test -p truapi-server --lib: 400 passed. cargo clippy -p truapi-server --all-targets clean; cargo check -p truapi-server --target wasm32-unknown-unknown clean; cargo fmt applied.
  • Live-node semantics pinned by direct statement_submit probes against wss://paseo-people-next-system-rpc.polkadot.io: upstream priority: u32 encoding fails decode (Could not decode Field, variant doesn't exist), expiry-less statements return alreadyExpired, future-expiry legacy statements proceed to proof verification.
  • Epoca currently works around both defects by routing the affected tag families to its legacy loop (paritytech/epoca#209); that fallback is removable once this lands and UserAgentKit re-vendors (its truapi-server pin predates current main and needs its own adaptation — useragent-truapi-runtime does not compile against main today).

Live products drive the runtime through @novasamatech/product-sdk, which
established two conventions the runtime did not serve:

- chainHead operations carry the papi provider's synthetic follow
  subscription id ("follow_0"), never the follow subscribe request id.
  The connection now treats an unknown session-scoped id as an alias and
  binds it to the session's most recent unaliased follow, matching the
  native host coordinators. Ids never resolve across session scopes, and
  alias bindings are dropped with their follow.
- statements arrive without an expiry field and rely on the host to
  stamp one; deployed statement stores refuse expiry-less statements as
  already elapsed. Proof creation now stamps a one-hour expiry (unix
  seconds in the upper 32 bits, priority zero) before signing, retains
  the host-assembled signed statement, and submission prefers those
  exact bytes over the product's pre-proof re-assembly so the submitted
  fields always match the proof's signature material.

Both behaviors reproduce the Epoca live A/B failure in
paritytech/epoca#174: zero Browse products and chain-query timeouts from
rejected follow ids, and Statement Store GenericError from expiry-less
submissions.
@replghost
replghost requested a review from a team July 28, 2026 17:54
@pgherveou

Copy link
Copy Markdown
Collaborator

same as #317

reopen if got that wrong

@pgherveou pgherveou closed this Jul 28, 2026
pgherveou added a commit that referenced this pull request Aug 4, 2026
Remove the Product SDK follow_N alias layer from ChainRuntime. Legacy
follow aliases stay out of truapi-server per #317/#321: products upgrade
to the current product-sdk, and hosts that still need tolerance for the
legacy convention bridge it on their side.

Refresh the host-callbacks.ts codegen golden for the AutoSigningKeys
core-storage key.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants