Skip to content

fix: ctg upgrade WASM hash parsing and the embedded-VK flow, found on testnet - #307

Merged
Dione-b merged 4 commits into
mainfrom
fix/upgrade-wasm-hash-embed-vk-flow
Oct 20, 2026
Merged

Dione-b merged 4 commits into
mainfrom
fix/upgrade-wasm-hash-embed-vk-flow

Conversation

@Dione-b

@Dione-b Dione-b commented Oct 16, 2026 •

Copy link
Copy Markdown
Owner

Motivation

Before releasing 3.13.0 I ran the ZK flow end to end as a user would: four fresh projects in ctg-teste-release/, built from current main with local @caatinga/* packages, against testnet. Unit tests and the smoke job never exercise ctg upgrade or embedded VK on a live network, and that is where three real problems were hiding.

Behavior

  1. ctg upgrade failed on every new WASM (pre-existing, not ZK-specific). For a WASM the network has not seen, stellar contract upload logs the transaction hash on stderr before printing the WASM hash on stdout. uploadWasm took the first 64-hex token of the combined output, compared the transaction hash with the local WASM hash, and failed with CAATINGA_UPLOAD_FAILED after the upload had succeeded. Verified: the reported 863bf98e… is a SUCCESS testnet transaction. The hash is now read from stdout, and parseWasmHash takes the last hash in mixed output. Adds the real CLI 27 output as a fixture.
  2. Embedded VK cannot be enabled in place. The verifier scaffold has no upgrade(new_wasm_hash), so the ctg upgrade verifier path documented in feat(zk): MPC ceremony import, embedded VK and protocol pre-flight #304 is impossible. It takes a new instance (ctg deploy verifier --upgrade, new contractId). Also, ctg zk build on a dev ceremony generates new keys, so the old proof stops verifying and ctg zk prove must run again; that step was missing from the docs. Docs, tutorial, cheatsheet, the unreleased feat(zk): MPC ceremony import, embedded VK and protocol pre-flight #304 changeset and the zk build --embed-vk messages are corrected. zk build now reminds you to re-prove after a dev setup.
  3. ctg zk invoke --embed-vk against a stale on-chain verifier used to dump a raw UnreachableCodeReached VM trap. It now reports CAATINGA_ZK_EMBED_VK_UNSUPPORTED ("most likely", since any contract panic looks the same on chain). The hint reads the local vk.rs: missing or still the placeholder → run ctg zk build <circuit> --embed-vk first; real key → just ctg build verifier + ctg deploy verifier --upgrade.
  4. ctg status called an imported ceremony "MPC (audited)", which Caatinga cannot know. It now shows MPC (imported, verified <date>) after verify-ceremony, or not verified. --json gains ceremonyVerifiedAt (additive).

Tests

Live on testnet (2026-10-16), fresh projects:

  • p1-starter (full zk init): deploy → prove → dynamic invoke ✔. --embed-vk → re-prove → build → ctg upgrade reproduced bug 1. With the fix, the new WASM uploads and its hash matches, then the call hits the missing upgrade entrypoint (bug 2). deploy verifier --upgrade gives a new contractId; invoke --embed-vk ✔ and dynamic verify_proof on the new instance ✔. Generated bindings include verify_proof_embedded.
  • p2-existing (ctg init --minimal + ctg zk init): both contracts deployed, app.version still answers, dynamic invoke ✔. invoke --embed-vk against the placeholder verifier now gives the new error and hint; following the hint ✔.
  • p3-mpc: an external snarkjs ceremony (2 contributions + beacon) is imported with provenance, then verify-ceremony ✔, deploy/invoke ✔. --embed-vk reuses the MPC keys (proof untouched) and invoke --embed-vk ✔. A tampered VK is refused by verify-ceremony and by mainnet invoke before any tx. estimate verify shows 44.06M / 400M.
  • p4-fresh and p1: npm run build (tsc && vite build) passes with placeholder and with generated bindings; npm audit --audit-level=high reports 0 vulnerabilities.

Unit: new tests for the transaction-hash-first upload output (fails without the fix), the placeholder-trap mapping (with the real diagnostic text), and the status label. Lint, typecheck, docs:check, template imports, build, test and format:check all pass locally (core 658, cli 299, zk 98 + 6 opt-in, client 149).

Release Impact

Patch for @caatinga/core, @caatinga/zk, @caatinga/cli (changeset included). It rides with 3.13.0. No error codes added or removed; ctg zk invoke --embed-vk reports an existing code (CAATINGA_ZK_EMBED_VK_UNSUPPORTED) where it used to report CAATINGA_INVOKE_FAILED. Rollback: revert.

Follow-up worth considering separately: an admin-gated upgrade entrypoint in the verifier scaffold would make embedded VK an in-place change again, but it needs an admin at deploy time.

Checklist

  • Public docs updated when behavior changes.
  • CAATINGA_* errors added or updated when public failures change.
  • --source examples use a local Stellar CLI identity, not a public G... address.
  • Version, lockfile, and workflow pins are aligned when tooling changes.

For a WASM the network has not seen, stellar contract upload logs the
transaction hash on stderr before printing the WASM hash on stdout. uploadWasm
parsed the first 64-hex token of the combined output, so every new upload was
compared against the transaction hash and ctg upgrade failed with
CAATINGA_UPLOAD_FAILED after a successful upload. Read stdout, and make
parseWasmHash take the last hash. Adds a real CLI 27 fixture.
ctg zk invoke --embed-vk against a verifier deployed with the placeholder
vk.rs now reports CAATINGA_ZK_EMBED_VK_UNSUPPORTED with a redeploy hint
instead of a raw VM trap. ctg zk build --embed-vk points at
ctg deploy verifier --upgrade (the verifier has no in-place upgrade entrypoint)
and reminds to re-prove after a dev setup. ctg status shows an imported
ceremony as imported/verified instead of claiming it was audited.
The verifier scaffold has no upgrade(new_wasm_hash), so ctg upgrade cannot
enable embedded VK in place, and a dev ceremony build changes the keys.
Read the local vk.rs to tell a never-generated key (run zk build --embed-vk
first) from a stale deployment (redeploy only), and say "most likely" since
any contract panic surfaces as the same trap.
@Dione-b
Dione-b merged commit 818dc2a into main Oct 20, 2026
3 checks passed
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.

1 participant