验证排障指南

这是一份针对 Soroban 合约验证失败的排障指南,系统列出了字节码不匹配、编译失败、合约未找到、源代码格式错误、ABI 不匹配和构建超时等常见问题的原因与解决方法。文章还提供了本地编译、二进制比对、固定依赖版本和 Docker 可复现构建等实用调试策略。

验证故障排查指南

概述

本指南帮助你诊断并解决常见的合约验证失败问题。对于每个问题,我们提供症状、根本原因和逐步解决方案。

快速诊断检查清单

在深入查看具体错误之前,请先完成此检查清单:

  • [ ] 合约已部署并存在于指定网络上
  • [ ] 使用与部署时完全相同的 soroban-sdk 版本
  • [ ] 源代码完整(没有缺失文件或依赖)
  • [ ] 包含 Cargo.tomlCargo.lock
  • [ ] 文件编码为 UTF-8(没有特殊字符问题)
  • [ ] 优化级别与部署设置匹配
  • [ ] 源代码中没有时间戳或非确定性代码

常见验证失败

1. 字节码不匹配

错误:

{
  "error": "BYTECODE_MISMATCH",
  "message": "Compiled bytecode hash does not match on-chain hash",
  "expected_hash": "a3f2b8c9d1e4f5a6b7c8d9e0...",
  "actual_hash": "9f1a2b3c4d5e6f7a8b9c0d1e..."
}

症状:

  • 编译成功,但哈希不匹配
  • “验证失败”状态

根本原因:

原因 1A:错误的编译器版本

最常见的问题——你使用的 soroban-sdk 版本与部署时不同。

诊断:

## 检查实际部署的版本
soroban contract inspect --id CDLZFC3... --network mainnet

## 与你的 Cargo.toml 比较
grep soroban-sdk Cargo.toml

解决方案:

## Cargo.toml - 使用 EXACT 版本(用 = 而不是 ^)
[dependencies]
soroban-sdk = "=21.0.0"  # 锁定到精确版本

然后重新构建并重试验证。

原因 1B:错误的优化级别

Rust 优化标志会影响输出字节码。

常见优化级别:

  • opt-level = 0 — 不优化(调试)
  • opt-level = 1 — 基本优化
  • opt-level = 2 — 完整优化
  • opt-level = 3 — 激进优化
  • opt-level = "s" — 针对大小优化
  • opt-level = "z" — 激进地针对大小优化(Soroban 最常见)

诊断:

## 尝试不同的优化级别
for opt in 0 1 2 3 s z; do
  echo "Testing opt-level=$opt"
  cargo build --release --target wasm32-unknown-unknown
  sha256sum target/wasm32-unknown-unknown/release/*.wasm
done

解决方案:

## Cargo.toml - 与部署优化设置匹配
[profile.release]
opt-level = "z"  # 大多数 Soroban 合约使用 "z"
原因 1C:依赖版本不匹配

不同版本的依赖会生成不同的字节码。

诊断:

## 检查是否存在 Cargo.lock
ls -la Cargo.lock

## 比较依赖版本
cargo tree | grep -v '(*)' | head -20

解决方案:

  1. 从部署中获取原始 Cargo.lock 文件
  2. Cargo.lock 提交到源代码管理
  3. Cargo.toml 中使用精确版本:
[dependencies]
soroban-sdk = "=21.0.0"
some-crate = "=1.2.3"  # 不是 "^1.2.3" 或 "~1.2.3"
原因 1D:构建环境差异

不同的操作系统、架构或工具链版本都会影响输出。

诊断:

## 检查 Rust 版本
rustc --version

## 检查 target
rustup target list --installed | grep wasm32

解决方案: 使用 Docker 进行可复现构建:

FROM rust:1.75-slim

RUN rustup target add wasm32-unknown-unknown
RUN cargo install soroban-cli --version 21.0.0

WORKDIR /build
COPY . .

RUN cargo build --release --target wasm32-unknown-unknown

使用以下命令构建:

docker build -t contract-build .
docker run --rm -v $(pwd)/target:/build/target contract-build
原因 1E:非确定性代码

每次产生不同输出的代码(时间戳、随机数)。

错误示例:

use std::time::SystemTime;

pub fn get_version() -> u64 {
    // 不要:嵌入构建时间戳
    SystemTime::now().duration_since(SystemTime::UNIX_EPOCH).unwrap().as_secs()
}

解决方案: 使用环境变量或 const 值:

pub const VERSION: &str = env!("CARGO_PKG_VERSION");

pub fn get_version() -> &'static str {
    VERSION
}

2. 编译失败

错误:

{
  "error": "COMPILATION_FAILED",
  "message": "Source code failed to compile",
  "details": "error[E0425]: cannot find function `transfer` in this scope"
}

症状:

  • 验证流程早期失败
  • 返回中出现编译错误

根本原因:

原因 2A:缺失依赖

诊断:

## 尝试在本地构建
cargo build --release --target wasm32-unknown-unknown

解决方案: 确保所有依赖都在 Cargo.toml 中:

[dependencies]
soroban-sdk = "21.0.0"
## 添加任何缺失的 crate
serde = { version = "1.0", features = ["derive"] }
原因 2B:语法错误

诊断:

cargo check

解决方案: 修复编译器报告的语法错误。

原因 2C:错误的 Rust edition

诊断:

grep edition Cargo.toml

解决方案:

[package]
edition = "2021"  # Soroban 合约使用 2021 edition
原因 2D:缺少特性标志

诊断: 检查合约是否使用了需要启用的 feature。

解决方案:

[features]
default = ["soroban-sdk/testutils"]

[dependencies]
soroban-sdk = { version = "21.0.0", features = ["alloc"] }

3. 未找到合约

错误:

{
  "error": "CONTRACT_NOT_FOUND",
  "message": "Contract does not exist on specified network",
  "contract_id": "CDLZFC3...",
  "network": "mainnet"
}

症状:

  • 验证立即失败
  • 链上不存在该 Contract ID

根本原因:

原因 3A:错误的网络

你在 mainnet 上验证,但合约在 testnet 上(反之亦然)。

诊断:

## 检查 mainnet
soroban contract inspect --id CDLZFC3... --network mainnet

## 检查 testnet
soroban contract inspect --id CDLZFC3... --network testnet

解决方案: 指定正确的网络:

soroban-registry verify \
  --contract-id CDLZFC3... \
  --source ./src \
  --network testnet  # 正确的网络
原因 3B:Contract ID 输入错误

诊断: 逐字符仔细检查 Contract ID。

解决方案: 直接从部署输出或区块链浏览器复制 Contract ID。

原因 3C:合约尚未部署

诊断: 检查部署状态。

解决方案: 先部署合约,然后再验证:

## 部署
soroban contract deploy \
  --wasm target/wasm32-unknown-unknown/release/my_contract.wasm \
  --network mainnet \
  --source deployer

## 然后验证
soroban-registry verify --contract-id <new_id> --source ./src

4. 无效的源格式

错误:

{
  "error": "INVALID_SOURCE_FORMAT",
  "message": "Source code encoding or format is invalid",
  "details": "Failed to decode base64 source code"
}

症状:

  • 源码上传失败
  • 编码错误

根本原因:

原因 4A:文件编码问题

源文件中存在非 UTF-8 字符。

诊断:

## 检查文件编码
file -i src/**/*.rs

## 查找非 UTF-8 文件
find src -name "*.rs" -exec file -i {} \; | grep -v utf-8

解决方案: 将文件转换为 UTF-8:

## 在 macOS/Linux 上
iconv -f ISO-8859-1 -t UTF-8 src/lib.rs > src/lib.rs.utf8
mv src/lib.rs.utf8 src/lib.rs
原因 4B:Base64 编码不正确

诊断:

## 测试 base64 编码/解码
base64 -i src/lib.rs | base64 -d > /dev/null && echo "OK" || echo "FAIL"

解决方案: 使用正确的 base64 编码:

## 正确编码
tar czf source.tar.gz src/ Cargo.toml Cargo.lock
base64 -i source.tar.gz > source.b64
原因 4C:缺少必需文件

验证需要 Cargo.tomlCargo.lock 和源文件。

诊断:

## 检查压缩包内容
tar tzf source.tar.gz

解决方案: 确保压缩包包含:

Cargo.toml
Cargo.lock
src/
  lib.rs
  (其他 .rs 文件)

5. ABI 不匹配

错误:

{
  "error": "ABI_MISMATCH",
  "message": "Contract ABI does not match declared interface",
  "details": "Function 'transfer' signature mismatch: expected (Address, Address, i128), found (Address, i128)"
}

症状:

  • 字节码匹配,但接口验证失败
  • 函数签名不一致

根本原因:

原因 5A:错误的源代码版本

你验证的是另一个版本的合约源代码。

诊断: 检查 git 历史:

git log --oneline --graph src/lib.rs

解决方案: 获取用于部署的确切 commit 对应的源代码:

git checkout <deployment-commit-hash>
原因 5B:条件编译

feature 或 cfg 标志会改变接口。

诊断:

// 示例问题:
##[cfg(feature = "extra-functions")]
pub fn special_transfer() { ... }

解决方案: 使用与部署相同的 features:

cargo build --release --features "extra-functions" --target wasm32-unknown-unknown

6. 构建超时

错误:

{
  "error": "BUILD_TIMEOUT",
  "message": "Contract compilation exceeded maximum time limit (300 seconds)"
}

症状:

  • 验证超时
  • 依赖较多的复杂合约

根本原因:

原因 6A:依赖过多

庞大的依赖树会减慢编译。

诊断:

cargo tree --depth 3

解决方案:

  • 移除未使用的依赖
  • 尽可能使用 default-features = false
[dependencies]
heavy-crate = { version = "1.0", default-features = false, features = ["minimal"] }
原因 6B:过程宏

大量宏展开会减慢构建。

解决方案:

  • 尽量减少宏的使用
  • 拆分为更小的 crate
  • 联系支持以提高超时时间(企业版)

调试策略

策略 1:本地编译测试

在验证前始终先在本地测试编译:

## 清理构建
cargo clean
cargo build --release --target wasm32-unknown-unknown

## 检查输出
ls -lh target/wasm32-unknown-unknown/release/*.wasm

## 获取哈希
sha256sum target/wasm32-unknown-unknown/release/*.wasm

策略 2:二进制比较

将本地构建结果与链上字节码进行比较:

## 获取链上合约
soroban contract fetch \
  --id CDLZFC3... \
  --network mainnet \
  --out-file deployed.wasm

## 在本地构建
cargo build --release --target wasm32-unknown-unknown
cp target/wasm32-unknown-unknown/release/my_contract.wasm local.wasm

## 比较哈希
sha256sum deployed.wasm local.wasm

## 如果不同,检查二进制差异
wasm-objdump -d deployed.wasm > deployed.wast
wasm-objdump -d local.wasm > local.wast
diff deployed.wast local.wast

策略 3:分段排查编译器版本

如果不确定使用的是哪个编译器版本:

##!/bin/bash
## 尝试多个版本
for version in 20.0.0 20.5.0 21.0.0 21.2.0; do
  echo "Testing soroban-sdk $version"

  # 更新 Cargo.toml
  sed -i "s/soroban-sdk = .*/soroban-sdk = \"=$version\"/" Cargo.toml

  # 构建
  cargo clean
  cargo build --release --target wasm32-unknown-unknown 2>/dev/null

  # 检查哈希
  sha256sum target/wasm32-unknown-unknown/release/*.wasm
done

策略 4:检查验证日志

查看详细的验证日志:

## 获取验证详情
curl -s https://registry.soroban.example/api/verifications/ver_abc123 | jq

## 查找具体错误
curl -s https://registry.soroban.example/api/verifications/ver_abc123/logs

策略 5:比较可工作的示例

找一个类似且验证成功的合约:

## 搜索已验证合约
soroban-registry search "token" --verified-only

## 下载源代码
soroban-registry source CDLZFC3... --output reference-src/

## 比较构建配置
diff reference-src/Cargo.toml mycontract/Cargo.toml

高级故障排查

可复现构建环境

创建一个完全可复现的构建环境:

Dockerfile:

FROM rust:1.75.0-slim-bookworm

## 精确 Rust 版本
RUN rustup default 1.75.0
RUN rustup target add wasm32-unknown-unknown

## 精确 soroban-cli 版本
RUN cargo install soroban-cli --version 21.0.0 --locked

## 设置构建标志
ENV RUSTFLAGS="-C opt-level=z"
ENV CARGO_PROFILE_RELEASE_OPT_LEVEL=z

WORKDIR /build
COPY Cargo.toml Cargo.lock ./
COPY src/ ./src/

RUN cargo build --release --target wasm32-unknown-unknown --locked

CMD ["sha256sum", "target/wasm32-unknown-unknown/release/*.wasm"]

调试非确定性

查找非确定性的来源:

## 多次构建并比较
for i in {1..5}; do
  cargo clean
  cargo build --release --target wasm32-unknown-unknown
  sha256sum target/wasm32-unknown-unknown/release/*.wasm >> hashes.txt
done

## 检查所有哈希是否一致
sort hashes.txt | uniq | wc -l
## 应输出:1

如果哈希不同,可能原因:

  • 构建中的时间戳
  • 随机数生成
  • 文件系统排序
  • 并行编译竞态条件

检查 WASM 二进制

使用 wasm-objdump 检查字节码:

## 安装 wabt 工具
brew install wabt  # macOS
## 或:apt install wabt  # Linux

## 反汇编
wasm-objdump -d contract.wasm > contract.wast

## 检查自定义 section(可能包含元数据)
wasm-objdump -s contract.wasm

## 查找差异
diff <(wasm-objdump -d deployed.wasm) <(wasm-objdump -d local.wasm)

何时报告 Bug

如果你已经穷尽了所有故障排查并认为这是验证系统的 bug,请提交以下信息:

  1. Contract ID 和网络
  2. 源代码(或公共仓库链接 + commit hash)
  3. 使用的精确构建命令
  4. 本地哈希 vs 预期哈希
  5. 验证错误响应
  6. 本地构建日志

提交至: https://github.com/ALIPHATICHYD/Soroban-Registry/issues

标签:verificationbug


成功检查清单

在提交验证之前:

  • [ ] 合约已部署并已在链上确认
  • [ ] 源代码可在本地无错误构建
  • [ ] 使用与部署时完全相同的 soroban-sdk 版本
  • [ ] Cargo.lock 已提交并包含在内
  • [ ] 所有依赖都已锁定到精确版本
  • [ ] 优化级别与部署匹配
  • [ ] 没有非确定性代码(时间戳、随机数)
  • [ ] 文件编码为 UTF-8
  • [ ] 压缩包包含 Cargo.tomlCargo.locksrc/

相关文档

支持

如需验证帮助:

  • 原文链接: github.com/ALIPHATICHYD/...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
ALIPHATICHYD
ALIPHATICHYD
江湖只有他的大名,没有他的介绍。