testing について
Midnight 開発者向けの Compact テスト・デバッグスキルです。コンパイル時と実行時のエラー、開示トレース、高速な反復開発、バージョン管理を解説します。
主な機能
- 01静的エラーと実行時エラーの区別
- 02コンパイラーメッセージと開示トレースの解読
- 03開発中の --skip-zk の利用
- 046 コンポーネントのバージョン整合
- 05Compact と環境の一般的な問題の調査
活用シーン
- 01disclose() の宣言漏れエラーの診断
- 02証明鍵を生成せずにコントラクトロジックをテスト
- 03Midnight コンポーネントのバージョン不一致の解消
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ kali-decoder/ midnight-skills --skill testingインストール後、Claude Code で/testingを入力して読み込まれたか確認します。
詳細
対象範囲
このスキルでは、Compact の 2 つのエラーレイヤー(静的と動的)、コンパイラーのメッセージの読み方(特に未宣言の開示トレース)、--skip-zk を使った高速な開発ループ、6 つのコンポーネント間のバージョン管理、そして最も一般的なデバッグパターンを扱います。公式のテストドキュメントは「近日公開予定」です。ここでの内容は実際の開発で実証済みです。
1) 2 つのエラーレイヤー
Compact には 1 種類ではなく、2 種類のエラーがあります。
静的エラー — 出力が生成される前にコンパイラーが検出します。開発中にターミナルで確認できます。静的エラーは心強いものです。コンパイラーが問題の内容と場所を正確に教えてくれます。
動的エラー — 生成された JavaScript が実行時に検出します。回路の実行時に発生します。自分で書いていない生成コード内で起きるため、デバッグがより困難です。
静的エラー(コンパイル時)
| エラーの種類 | 内容 | 検出されるタイミング |
|---|---|---|
| 構文 | 不正なコード | パーサー |
| 型の不一致 | 誤った型の使用 | 型チェッカー |
| 未宣言の開示 | disclose() がない | Witness 保護 |
| 未定義の参照 | 不明な識別子 | 名前解決 |
| ジェネリックが特殊化されていない | ジェネリックエンティティがトップレベルで使用されている | スコープチェッカー |
| 再帰的な構造体 | 構造体が自身を参照している | 宣言チェッカー |
| 再帰的な回路 | 回路が自身を呼び出している | 宣言チェッカー |
for 内の return | ループ内の return | 文チェッカー |
| Sealed 台帳への書き込み | 回路内で Sealed フィールドに書き込んでいる | 宣言チェッカー |
コンパイラーが何も出力しない場合、少なくとも 1 つの静的エラーがあります。メッセージを確認してください。
動的エラー(実行時)
| エラーの種類 | 内容 | 例 |
|---|---|---|
| 型の不一致 | 引数の型または数が誤っている | 誤った引数で呼び出す |
| オーバーフロー | キャストする値が変換先の上限を超えている | 1000 as Uint<8> |
| アンダーフロー | カウンターが 0 未満に減算される | 0 のときに counter -= 1 |
| 未初期化のネスト値 | ネストされた台帳状態が初期化されていない | 挿入前に map.lookup(k).lookup(k2) |
| Merkle ツリーが満杯 | 満杯のツリーに挿入する | isFull() のときに tree.insert() |
動的エラーはデバッグがより困難です。ソースファイルの行番号については、エラーメッセージを確認してください。
2) コンパイラーのエラーメッセージの読み方
型エラー
/path/contract.compact line 12 char 5:
type error: expected Uint<64>, got Field
読み方:行:文字位置、期待される型、実際の型。キャレット(^)が問題のトークンを指しています。
未宣言の開示
Exception: /path/contract.compact line 6 char 11:
potential witness-value disclosure must be declared but is not:
witness value potentially disclosed:
the return value of witness getBalance at line 2 char 1
nature of the disclosure:
ledger operation might disclose the witness value
via this path through the program:
the right-hand side of = at line 6 char 11
下から上へ読みます。 この経路は、Witness データがどのように伝わったかを示しています。
- 発生元: 2 行目の
getBalance() - 経路: 代入式の右辺を通過
- 到達先: 6 行目の台帳操作
修正方法: その経路上のできるだけ開示地点に近い場所に disclose() を追加します。
戻り値の disclose() の不足
Exception: line 5 char 3:
potential witness-value disclosure must be declared but is not:
witness value potentially disclosed:
the return value of witness getBalance at line 2 char 1
nature of the disclosure:
the value returned from exported circuit check might disclose
the result of a comparison involving the witness value
Boolean の比較結果も開示に該当します。Witness 呼び出し、または戻り値を disclose() で囲みます。
バージョンの不一致
Error: runtime version mismatch: expected 0.15.0, got 0.14.2
コンパイル済みコントラクトが、異なるランタイムバージョンを想定しています。以下のバージョン管理を参照してください。
3) --skip-zk を使った開発ループ
証明鍵の生成には時間がかかります。反復的な開発中は、これをスキップします。
compact compile --skip-zk contracts/contract.compact contracts/managed/contract
これにより contract/index.js と compiler/contract-info.json が生成され、ロジックのテストには十分です。最終ビルドでは再度有効にしてください。
4) バージョン管理
Midnight には、同期を保つ必要がある6 つのコンポーネントがあります。同期していないと、バージョン不一致に関する分かりにくいランタイムエラーが発生します。
| コンポーネント | 内容 | 確認方法 |
|---|---|---|
| CLI ツール | compact バイナリ | compact --version |
| コンパイラー | compactc | compact compile --version |
| ランタイム | @midnight-ntwrk/compact-runtime | npm list |
| 台帳 | @midnight-ntwrk/ledger-v8 | npm list |
| JS ライブラリ | @midnight-ntwrk/midnight-js-* | npm list |
| 証明サーバー | Docker イメージ | イメージタグ |
現在のバージョンを確認する
compact --version
compact compile --version
npm list @midnight-ntwrk/compact-runtime
npm list @midnight-ntwrk/ledger-v8
互換性マトリックスを確認する
公式リリース互換性マトリックスが信頼できる唯一の情報源です。確認せずにバージョンを混在させないでください。
package.json でバージョンを正確に固定する
{
"dependencies": {
"@midnight-ntwrk/compact-runtime": "0.15.0",
"@midnight-ntwrk/ledger-v8": "8.0.3"
}
}
^ や ~ は使用しないでください — 自動更新が許可され、互換性が気付かないうちに損なわれる可能性があります。
再現可能なインストールには npm ci を使用する
rm -rf node_modules
npm ci
npm ci は package-lock.json に記載された内容を正確にインストールします。npm install は条件に一致する最新バージョンを取得します。
コンポーネントを更新した後は
- 関連するコンポーネントをすべてまとめて更新する
- コントラクトを再コンパイルする
- 新しい Docker イメージで証明サーバーを再起動する
- テストスイートを実行する
5) よくある間違いと修正方法
Ledger への書き込みで disclose() を忘れた
// wrong — compiler error
balance = getBalance();
// correct
balance = disclose(getBalance());
戻り値で disclose() を忘れた
// wrong — compiler error (comparison of witness data)
export circuit check(n: Uint<64>): Boolean {
return getSecret() > n;
}
// correct — declare the disclosure
export circuit check(n: Uint<64>): Boolean {
return disclose(getSecret()) > n;
}
for ループ内での return
// wrong — static error
circuit findFirst(v: Vector<4, Field>, target: Field): Boolean {
for (const x of v) {
if (x == target) return true;
}
return false;
}
// correct — use fold
circuit findFirst(v: Vector<4, Field>, target: Field): Boolean {
return fold((found, x) => found || x == target, false, v);
}
再帰的な回路
// wrong — static error: recursion not allowed
circuit factorial(n: Uint<64>): Uint<64> {
return n == 0 ? 1 : n * factorial(n - 1);
}
fold または明示的な展開を使って書き換えてください。Compact では有限の回路が必要です。
縮小キャストが実行時にオーバーフローする
const x: Uint<64> = 1000;
const y = x as Uint<8>; // dynamic error: 1000 doesn't fit
キャストする前に、値が範囲内に収まることを必ず確認してください。assert または範囲制限付きの型を使用してください。
ネストされた Ledger 状態が初期化されていない
ledger fld: Map<Boolean, Map<Field, Counter>>;
// wrong — dynamic error (inner map not initialized)
export circuit increment(b: Boolean, n: Field): [] {
fld.lookup(b).lookup(n) += 1;
}
// correct — initialize first
export circuit init(b: Boolean): [] {
fld.insert(disclose(b), default<Map<Field, Counter>>);
}
transientHash の結果を disclose() なしで使用している
// wrong — compiler error (witness-tainted)
ledger h: Field;
export circuit store(v: Field): [] {
h = transientHash<Field>(v);
}
// correct — declare disclosure
h = disclose(transientHash<Field>(v));
// or use transientCommit (nonce provides hiding, no disclose needed)
h = transientCommit<Field>(v, nonce);
6) よくある環境の問題
| エラー | 原因 | 修正方法 |
|---|---|---|
compact: command not found | バイナリが PATH にない | export PATH="$HOME/.compact/bin:$PATH" |
ERR_UNSUPPORTED_DIR_IMPORT | Node.js がディレクトリをインポートしようとした | 新しいターミナルを開き、キャッシュをクリアする |
| Docker 接続エラー | Docker Desktop が起動していない | Docker Desktop を起動する |
| ポート 6300 が使用中 | 同じポート上に別のコンテナがある | -p 6301:6300 |
| 実行時のバージョン不一致 | ランタイムパッケージが古い | 互換性マトリックスを確認して更新する |
7) バージョン確認スクリプト
バグを報告する前に実行してください:
#!/bin/bash
echo "=== Midnight Version Check ==="
echo "CLI:"; compact --version || echo "not found"
echo "Compiler:"; compact compile --version || echo "not found"
echo "Runtime:"
npm list --depth=0 | grep @midnight-ntwrk || echo "none found"
echo "Node.js:"; node --version
echo "Compare with: docs.midnight.network/relnotes/support-matrix"
8) ヘルプを受ける
これらのメモを確認しても解決しない場合は、次を参照してください:
- Discord
#dev-chat— エラーメッセージとバージョン情報を投稿してください - FAQ — docs.midnight.network/troubleshoot/faq
- フォーラム — forum.midnight.network
必ず次の情報を含めてください:
- バージョン確認スクリプトの出力
- エラーメッセージ全体
.compactファイル(または関連する抜粋)- 期待していた動作と実際に起きたこと
9) 要点のおさらい
- 静的エラー — 出力前にコンパイラーが検出します。メッセージを確認してください。
- 動的エラー — 生成されたコード内で実行時に発生します。行番号を確認してください。
- 未宣言の開示トレース — 下から上に読みます。起点から開示までの経路をたどります。
- 開発中は
--skip-zkを使用してください。最終ビルドでは有効にしてください。 package.jsonでは バージョンを正確に固定してください。npm ciを使用してください。- コンポーネントを更新する前に、互換性マトリックスを確認してください。
- 更新後は必ず: 再コンパイルし、証明サーバーを再起動して、テストを実行してください。