Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,43 @@ maintenance authority: committee=0 threshold=1 counter=1

The script exits non-zero if either check fails (e.g. it correctly flags contracts deployed from older builds).

### Verifying a contract that is deliberately not locked: `--allow-unlocked`

Locking is a one-way door, so it is only right for a hosted release. Every
devnet/demo deploy leaves the contract **unlocked** on purpose
(`SHIELDED_NIGHT_LOCK=false`) - and the strict run above then exits 1 even when
all 11 verifier keys match, because the LOCK check failed. That makes the
strongest check in the profile unreadable from the exit code.

`--allow-unlocked` measures and prints the lock state exactly as before, but
lets **only the code check decide the exit code**:

```bash
MN_ENV=undeployed CV_ADDRESS=<deployed-address> bun run verify:deployment -- --allow-unlocked
```

(The `--` is what makes `bun run` forward the flag to the script; calling
`bun run scripts/verify-deployment.ts --allow-unlocked` directly works too.)

Output on an unlocked contract whose code matches:

```
maintenance authority: committee=1 threshold=1 counter=0
ℹ NOT locked: 1 committee member(s) can still change the contract (threshold 1). Reported only, not failed: --allow-unlocked was passed.

✅ verified: deployed code matches this repo byte-for-byte. Lock state REPORTED ONLY (--allow-unlocked): this contract is NOT immutable.
```

The flag **never weakens the code check**: a verifier-key mismatch, a missing
circuit or an extra circuit still exits 1 with the flag set. It only ever
changes what an *unlocked* contract does to the exit code. Use it for a demo
stack's verify step; never for a hosted release, where being immutable is part
of the claim.

Unknown arguments are rejected rather than ignored, so a typo
(`--allow-unlock`) fails loudly instead of silently reverting to the strict
behaviour.

## How to run tests

Two tiers (details and env vars in [TESTING.md](TESTING.md)):
Expand Down
39 changes: 39 additions & 0 deletions TESTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ bun run compact:fast # compile contract JS only (--skip-zk, no prover keys)
bun run test:unit
```

Besides the contract simulator suites, this tier also covers the chain-free
script policies: the runtime address override, the network env-var overrides,
the deploy record, and the verifier's `--allow-unlocked` exit-code policy
([test/unit/verify-args.unit.test.ts](test/unit/verify-args.unit.test.ts)).

The simulator ([test/unit/simulators/ShieldedNightSimulator.ts](test/unit/simulators/ShieldedNightSimulator.ts))
executes the compiled circuits directly: state assertions are exact and failed
calls throw the contract's `assert` messages. Token movements are recorded as
Expand Down Expand Up @@ -82,6 +87,40 @@ URLs identify the network itself, and silently repointing `preview` at a local
indexer because a variable was left exported would be an expensive, invisible
bug.

### Verifying a deployment as a gate: `--allow-unlocked`

`scripts/verify-deployment.ts` is the strongest check a stack can run — it
proves the ZK artifacts the page serves are the rules the chain enforces — and
it is meant to be read as an **exit code** from a compose one-shot, not parsed
from stdout.

By default it asserts two things and exits 0 only if both hold: the verifier
keys match, **and** the contract is locked. A devnet contract is deliberately
never locked (`SHIELDED_NIGHT_LOCK=false`), so the default run exits 1 on a
perfectly healthy stack. Pass `--allow-unlocked` there:

```bash
# strict (hosted release): unlocked => exit 1
MN_ENV=preprod CV_ADDRESS=<addr> bun run verify:deployment

# devnet gate: lock state reported, exit code = the verifier-key check only
MN_ENV=undeployed CV_ADDRESS=<addr> bun run verify:deployment -- --allow-unlocked
```

| | keys match | key mismatch / missing / extra circuit |
| --- | --- | --- |
| **locked**, no flag | exit 0 | exit 1 |
| **unlocked**, no flag | exit 1 | exit 1 |
| **locked**, `--allow-unlocked` | exit 0 | exit 1 |
| **unlocked**, `--allow-unlocked` | exit 0 | **exit 1** |

The flag only ever changes what an *unlocked* contract does to the exit code;
it never relaxes the key check. The policy itself is unit-tested in
[test/unit/verify-args.unit.test.ts](test/unit/verify-args.unit.test.ts)
against [scripts/verify-args.ts](scripts/verify-args.ts), so no chain is needed
to prove the table above. Unknown arguments are rejected, so a typo fails
loudly instead of silently reverting to strict.

### Running against a stack you already have (`MN_EXTERNAL_STACK=1`)

The default is unchanged and is what CI runs: the suite owns its stack, so a
Expand Down
Loading
Loading