mcpField
T
testing

testing

github.com/kali-decoder测试与质量18124 次安装4 天前更新
代码仓库

关于 testing

面向 Midnight 开发者的 Compact 测试与调试技能,讲解编译和运行时错误、披露追踪、快速迭代及版本协调。

主要功能

  1. 01区分静态错误与运行时错误
  2. 02解读编译器消息和披露追踪
  3. 03开发时使用 --skip-zk
  4. 04协调六个组件的版本
  5. 05排查常见 Compact 和环境问题

适用场景

  1. 01诊断未声明 disclose() 的错误
  2. 02不生成证明密钥测试合约逻辑
  3. 03解决 Midnight 组件版本不匹配

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/kali-decoder/midnight-skills --skill testing

安装后在 Claude Code 中输入/testing确认已加载。

详细介绍

范围 本技能涵盖 Compact 中的两层错误(静态错误与动态错误)、如何阅读编译器消息(尤其是未声明披露的追踪信息)、使用 --skip-zk 的快速开发循环、6 个组件的版本管理,以及最常见的调试模式。官方测试文档“即将推出”——本文内容经真实开发实践验证。

1) 两层错误

Compact 有两种错误,而不是一种:

静态错误 — 编译器在生成任何输出之前捕获的错误。开发时,你会在终端中看到这些错误。静态错误是你的好帮手——编译器会准确指出问题所在及其位置。

动态错误 — 由生成的 JavaScript 在运行时捕获的错误。电路执行时,你会看到这些错误。这类错误更难调试,因为它们发生在你没有编写的生成代码中。

静态错误(编译时)
错误类型含义捕获时机
语法代码格式错误解析器
类型不匹配使用了错误的类型类型检查器
未声明披露缺少 disclose()见证保护
未定义引用未知标识符名称解析器
泛型未专门化在顶层使用了泛型实体作用域检查器
递归结构体结构体引用自身声明检查器
递归电路电路调用自身声明检查器
for 中的 return循环内的 return语句检查器
密封账本写入在电路中写入密封字段声明检查器

如果编译器没有生成输出,说明至少存在一个静态错误。请检查错误消息。

动态错误(运行时)
错误类型含义示例
类型不匹配参数类型或数量错误使用错误的参数调用
溢出转换后的值对目标类型来说过大1000 as Uint<8>
下溢计数器递减至零以下计数器为 0 时执行 counter -= 1
嵌套值未初始化嵌套账本状态未初始化插入前调用 map.lookup(k).lookup(k2)
默克尔树已满向已满的树中插入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

请从下往上阅读。 该路径追踪见证数据的流向:

  1. 来源: 第 2 行的 getBalance()
  2. 路径: 经过赋值语句右侧
  3. 目标: 第 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 比较结果,也算作披露。请用 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
编译器compactccompact compile --version
运行时@midnight-ntwrk/compact-runtimenpm list
账本@midnight-ntwrk/ledger-v8npm 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 会获取符合条件的最新版本。

更新任何组件后
  1. 一并更新所有相关组件
  2. 重新编译合约
  3. 使用新的 Docker 镜像重启证明服务
  4. 运行测试套件

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_IMPORTNode.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) 获取帮助

查看这些说明后仍无法解决问题:

  1. Discord #dev-chat——发布错误消息和版本详情
  2. 常见问题——docs.midnight.network/troubleshoot/faq
  3. 论坛——forum.midnight.network

请务必附上:

  • 版本检查脚本的输出
  • 完整的错误消息
  • .compact 文件(或相关摘录)
  • 预期结果与实际情况

9) 快速回顾

  • 静态错误——编译器会在生成输出前捕获。请检查错误消息。
  • 动态错误——会在生成代码的运行时发生。请查看行号。
  • 未声明的披露追踪——从底部向上阅读,它会追踪从来源到披露点的路径。
  • 开发期间使用 --skip-zk。最终构建时启用。
  • 在 package.json 中锁定精确版本。使用 npm ci。
  • 更新任何组件前,先检查兼容性矩阵。
  • **每次更新后:**重新编译、重启证明服务并运行测试。

评论

支持 Markdown