Repository navigation
feat(zk): admin-gated in-place upgrade for the ZK verifier - #308
Merged
Merged
Conversation
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
force-pushed
the
feat/zk-verifier-upgrade
branch
from
October 20, 2026 13:28
65d56df to
f0571cf
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Motivation
Enabling embedded VK changes the verifier's WASM, but the scaffold had no
upgrade(new_wasm_hash), so the only path wasctg deploy verifier --upgradeand a new contractId. This restores the in-place story.Behavior
packages/core/scaffolds/zk-verifierand the byte-identicalzk-startercopy): adds__constructor(admin: Address),admin() -> Addressandupgrade(new_wasm_hash: BytesN<32>)gated onadmin.require_auth().verify_proof/verify_proof_embeddedare unchanged.deployArgs: { admin: "${source.address}" }in the verifier entry (zk-starter config,ctg zk init --minimalconfig, and the blockctg zk initmerges into existing projects).ctg zk initmerge: averifierentry that points at./contracts/verifierand has nodeployArgsgets the admin deploy arg added; entries with their owndeployArgsor another path are left alone.ctg zk build --embed-vkand theCAATINGA_ZK_EMBED_VK_UNSUPPORTEDhint now point toctg upgrade verifier --source <admin>, mentioning the one-time redeploy for old verifiers.caatinga:upgradescript and a README section.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 noupgradeentrypoint and need onectg deploy verifier --upgradeafter adopting the new contract code;ctg upgradeworks from then on. Rollback: drop thedeployArgsentry and the constructor/upgradefunctions.Tests
cargo teston 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).create-zk-projectconfig assertion, invoke hint.pnpm lint typecheck build testgreen.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 unchangedctg upgrade verifier --source alice: ✔ same contractIdCA7EPZJY…FVRVD, new wasmHash, historyupgradeType: in-placectg zk invoke --embed-vk✔, dynamicctg zk invokestill ✔,admin()preserved.🤖 Generated with Claude Code