Skip to content

feat(zk): admin-gated in-place upgrade for the ZK verifier - #308

Merged
Dione-b merged 6 commits into
mainfrom
feat/zk-verifier-upgrade
Oct 20, 2026
Merged

Dione-b merged 6 commits into
mainfrom
feat/zk-verifier-upgrade

Conversation

@Dione-b

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

Copy link
Copy Markdown
Owner

Stacked on #307 (fix/upgrade-wasm-hash-embed-vk-flow), which fixes ctg upgrade reading the tx hash instead of the WASM hash. Until #307 merges, this diff also shows its three commits; the change here is the last commit (feat(zk): admin-gated in-place upgrade…).

Motivation

Enabling embedded VK changes the verifier's WASM, but the scaffold had no upgrade(new_wasm_hash), so the only path was ctg deploy verifier --upgrade and a new contractId. This restores the in-place story.

Behavior

  • Contract (packages/core/scaffolds/zk-verifier and the byte-identical zk-starter copy): adds __constructor(admin: Address), admin() -> Address and upgrade(new_wasm_hash: BytesN<32>) gated on admin.require_auth(). verify_proof / verify_proof_embedded are unchanged.
  • Who is admin: the deploying identity, via deployArgs: { admin: "${source.address}" } in the verifier entry (zk-starter config, ctg zk init --minimal config, and the block ctg zk init merges into existing projects).
  • ctg zk init merge: a verifier entry that points at ./contracts/verifier and has no deployArgs gets the admin deploy arg added; entries with their own deployArgs or another path are left alone.
  • Hints: ctg zk build --embed-vk and the CAATINGA_ZK_EMBED_VK_UNSUPPORTED hint now point to ctg upgrade verifier --source <admin>, mentioning the one-time redeploy for old verifiers.
  • zk-starter gets a caatinga:upgrade script and a README section.
  • Docs: docs/zk.md (Embedded VK), docs/tutorials/zk-project.md, docs/cheatsheet.md.

Compatibility / release impact

Minor changeset. The verifier now requires a constructor arg, so deploy needs --source (already the case). Verifiers scaffolded before this release have no upgrade entrypoint and need one ctg deploy verifier --upgrade after adopting the new contract code; ctg upgrade works from then on. Rollback: drop the deployArgs entry and the constructor/upgrade functions.

Tests

  • Rust (cargo test on the scaffold): constructor_stores_admin, upgrade_requires_admin_auth (asserts the recorded auth is the admin's, using a minimal hand-built contract WASM), upgrade_rejects_non_admin, upgrade_rejects_unsigned_call, plus the existing proof test — 5/5 pass. Release WASM builds.
  • CAATINGA_CARGO_TESTS=1 … embedded-vk-equivalence.test.ts — 3/3 pass (generator updated for the constructor).
  • TS: merge tests (new block has deployArgs, admin arg added to existing entry and idempotent, existing deployArgs kept, non-scaffold path untouched), create-zk-project config assertion, invoke hint.
  • pnpm lint typecheck build test green.

Live testnet check (2026-10-16, stellar-cli 27.0.0)

Fresh ctg zk init live --minimal → zk build → zk prove → build verifier → deploy verifier --source alice (CA7EPZJY…FVRVD, admin() = alice) → zk invoke ✔ → zk build --embed-vk → zk prove → build verifier →

  • ctg upgrade verifier --source ctg-mallory (non-admin): rejected (CAATINGA_INVOKE_FAILED), artifacts unchanged
  • ctg upgrade verifier --source alice: ✔ same contractId CA7EPZJY…FVRVD, new wasmHash, history upgradeType: in-place
  • ctg zk invoke --embed-vk ✔, dynamic ctg zk invoke still ✔, admin() preserved.

🤖 Generated with Claude Code

Dione-b and others added 6 commits October 16, 2026 17:37
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.
The verifier scaffold gains __constructor(admin), admin() and an
admin-gated upgrade(new_wasm_hash), so ctg upgrade verifier swaps the
WASM in place (same contractId) after ctg zk build --embed-vk. The
scaffold config passes the deploying identity as admin via
deployArgs: { admin: "${source.address}" }, and ctg zk init adds that
deploy arg to an existing scaffold verifier entry that lacks it.

Co-Authored-By: Claude <noreply@anthropic.com>
…t changesets

- Verifier `admin()` and `upgrade` return `Groth16Error::AdminNotSet`
  instead of panicking when no admin is stored (scaffold and zk-starter
  kept identical); covered by a new contract test.
- `ctg zk init` warns when the scaffold verifier entry has no admin
  deploy arg and it could not add one (nested or computed entries).
- Changesets no longer say the verifier has no upgrade entrypoint, and
  the in-place upgrade changeset spells out the constructor-arg break
  for existing configs.
- docs/zk.md notes the admin lives in instance storage.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@Dione-b
Dione-b force-pushed the feat/zk-verifier-upgrade branch from 65d56df to f0571cf Compare October 20, 2026 13:28
@Dione-b
Dione-b merged commit 5ec1487 into main Oct 20, 2026
3 checks passed
@Dione-b
Dione-b deleted the feat/zk-verifier-upgrade branch October 20, 2026 13:48
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