# 故障排查

> 按症状列出客户程序未能得到通过验证的证明的每一种情况。退出状态、致命的执行器错误、被拒绝的 ELF、被拒绝的程序、失败的证明和验证者错误，以及各自的原因和修复方法。

客户程序（guest）可能在六个环节止步，得不到通过验证的证明。先找到症状，再找到对应的行。

## 运行以意料之外的状态退出

运行已经结束，并且可以被证明；是客户程序自己选择了失败。SDK 自身使用的状态：

| 状态 | 原因 | 怎么办 |
| --- | --- | --- |
| 70 | `commit` 将超过 16,380 字节 | 提交输出的摘要，而不是输出本身 |
| 71 | 某次分配的末端将高于 `__stack_top − 8 MiB` 或当前的 `sp` | 内存从不释放，所以这次运行的*总*分配量必须能放进映像与 `0x7F80_0000` 之间。在各轮循环之间复用缓冲区，并用 `with_capacity` 设定容量（[堆](https://apogee.gweb3networks.com/docs/launch/write#heap)） |
| 72 | 某个委托返回了其 shim 拒绝接受的结果：一个错误，或者在多次调用操作的第一次调用之后返回的 `-ENOSYS` | 使用 SDK 的函数而不是原始帧，并让操作数保持小于其模数 |
| 101 | panic，不打印任何内容 | 用你的库的宿主机（host）构建运行同样的输入，panic 信息会在那里打印出来（[在宿主机上测试](https://apogee.gweb3networks.com/docs/launch/write#host-first)） |

其他任何状态都来自你自己的 `exit(code)`。

## 运行因致命错误而停止

模拟器返回一个 `EmuError`，既没有退出状态，也没有证明：

| 错误 | 常见原因 |
| --- | --- |
| `OutOfBounds` | 空指针或野指针（`[0, 0x8000)` 是空洞）、读取证明者提示（advice）时超出了宿主程序提供的范围、在没有证明者提示的运行中调用 `advice()`，或者委托帧没有完全位于 RAM 中 |
| `Misaligned` | 通过未对齐指针进行的半字或字访问，或者未对齐的委托帧 |
| `NotAnInstruction` | 跳转到一个没有指令的 pc，包括全零的 `c.unimp` 半字 |
| `IllegalInstruction` | 机器不执行的编码 |
| `Ebreak` | 一条 `ebreak`，它没有证明 |
| `ClockOverflow` | 超过 `2^36 − 1` 个周期 |
| `PublicInputTooLong`、`JournalTooLong` | 输入，或者退出时公开输出（journal）的长度字，超过 16,380 字节 |
| `DelegationFrame` | 其电路无法为之提供见证的帧：`MOD_MUL` 或 `EC_ADD` 的操作数大于或等于其模数、选择子不指向任何东西、keccak 轮次超过 23、SHA-256 轮组编号超过 15、Poseidon2 的某个 lane 大于或等于 `p` |
| `DelegationFamilyAbsent` | 映像从未声明过的委托编号，出现在追踪路径上 |

## ELF 被拒绝

对于加载器无法接受的 ELF，`artifact-dump`、`host::setup` 和各种工具都会以 `LoaderError` 拒绝：

| 拒绝 | 常见原因 |
| --- | --- |
| `NotAnElf`、`Truncated` | 不是客户程序的 ELF：例如 `.d` 文件，或者没有写完整的文件 |
| `NotRiscV`、`UnsupportedElfType`、`RelocatableElf`、`DynamicElf` | 宿主机构建、目标文件、PIE，或者动态链接的构建 |
| `BadSegment`、`NoExecutableSegment`、`EntryNotAnInstruction` | 被修改过的 `link.ld`，或者没有链接 `_start` |
| `RvcIllegal`、`InstructionTooLong`、`TextTruncated` | `.text` 中有数据，例如手写汇编中的表。全零半字绝不会导致这些错误，它是预期之中的 |

## 程序无法登记

ELF 能够加载，但程序无法被解码为一个配置：

| 拒绝 | 原因与修复 |
| --- | --- |
| `Not all opcodes supported: pc=…` | 可执行代码中任何位置（无论是否可达）出现了 RV32IMA 之外的字，例如汇编中的 CSR 访问或 `fence.i`。删除它 |
| `TableTooShort` | 代码超出了电路族解码表的覆盖范围。提高该电路族的高度：`2^22` 可覆盖 7.9375 MiB 代码 |
| `ProgramTooLarge` | 映像超出了 `bytecode_size_words`，默认为 4 MiB。在 `ProgramParams` 中提高这一上限 |
| `ImageOutsideWindow` | 在你的窗口高度下，有来自文件的字节位于 RAM 窗口 0 之外。提高窗口高度 |
| `HeightNotOnMenu` | 高度不是 `2^8`、`2^12`、`2^16`、`2^18`、`2^20` 或 `2^22` 之一 |
| `UnknownDelegation` | 映像声明了一个没有任何电路族响应的委托编号 |

如果程序用到的某个电路族被设置在其下限以下（指令电路族为 `2^20`，RAM 窗口电路族为 `2^16`），密钥也会构建失败，因为那里不存在电路。

## 证明者失败

诚实的证明者在证明模拟器执行过的内容时不会失败，所以失败意味着它接受了不该接受的输入，或者存在 bug。大多数情况属于以下两种：

- **没有证明的调用。** 某个库为获取宿主机数据而发出的、`EXIT` 和委托之外的系统调用，会得到 `-ENOSYS`，运行继续进行，但证明者在填充时会拒绝那一行，并指出对应的周期。找出那个索取随机数或时间的依赖。
- **内存不足。** 进程在分片处理过程中被杀死。调低 `host::prove` 的第三个参数，或者降低高度。

其他情况，打开证明者的调试日志重新构建，然后重新运行：

```sh
cargo run --release -p bench --features prover/debug-info -- prove ...
APOGEE_DEBUG=detail <the run> 2>&1 | tee run.log
grep -c 'begin h=' run.log; grep -c 'gkr done' run.log     # unequal: a shard died
grep 'begin h=' run.log | tail -1                           # which one
grep -E 'FAIL|NOT CANONICAL|UNBALANCED|OVER the|NAMES NO|DISAGREES|NOT LOOPING|ABORTED' run.log
```

`self_check FAILED` 会指出该行第一个不满足的门，以及每个操作数的值。[调试日志](https://apogee.gweb3networks.com/docs/reference/tools#s3)列出了所有标记。

## 验证失败

`verify_shard` 和 `verify_block` 返回一个 `VerifyError`，它的类别说明了哪里出了问题：

| 类别 | 含义 |
| --- | --- |
| `Statement` | 陈述与密钥不符：分片数、窗口规则、载荷长度、列表，或者为证明提供种子的全局摘要 |
| `Malformed` | 证明的形状与其电路不符：承诺、输出、轮次或断言的数量 |
| `Constraint { layer }` | 某个门被违反，或者某一层的求和校验（sumcheck）失败 |
| `Lookup { channel }` | 查找（lookup）的元组不在其表的任何一行中 |
| `MemoryArgument` | 读多重集与写多重集无法核对一致，或者某个公开窗口存放的不是陈述中的字节 |
| `Opening` | 某个承诺的打开失败 |

如果证明是由远地虚拟机自己的证明者、根据模拟器接受的一次执行生成的，那么验证失败意味着验证者和证明者对程序的认识不一致：检查你加载的是否就是生成该证明时所用的密钥，高度是否相同，仪式是否相同。

## 程序身份不符

你计算出的程序身份与预期的不同：

- **另一台机器上的构建。** ELF 嵌入了绝对路径，所以在别处重新构建得到的是另一个映像。要与被证明的那个 ELF 比较，而不是与一次新的构建比较。
- **不同的高度。** 每个高度都被绑定进程序身份。`artifact-dump tables` 报告的是默认高度下的程序身份；你的设置可能用了别的高度。
- **另一场仪式。** Hermez 的 powers-of-tau 文件对应的是另一个 `τ`，所以每个承诺都不同。把文件的 `[τ]_1` 与[该仪式的值](https://apogee.gweb3networks.com/docs/launch/setup#ceremony)核对。
