这是一份针对 Soroban 合约验证失败的排障指南,系统列出了字节码不匹配、编译失败、合约未找到、源代码格式错误、ABI 不匹配和构建超时等常见问题的原因与解决方法。文章还提供了本地编译、二进制比对、固定依赖版本和 Docker 可复现构建等实用调试策略。
本指南帮助你诊断并解决常见的合约验证失败问题。对于每个问题,我们提供症状、根本原因和逐步解决方案。
在深入查看具体错误之前,请先完成此检查清单:
Cargo.toml 和 Cargo.lock错误:
{
"error": "BYTECODE_MISMATCH",
"message": "Compiled bytecode hash does not match on-chain hash",
"expected_hash": "a3f2b8c9d1e4f5a6b7c8d9e0...",
"actual_hash": "9f1a2b3c4d5e6f7a8b9c0d1e..."
}
症状:
根本原因:
最常见的问题——你使用的 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" # 锁定到精确版本
然后重新构建并重试验证。
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"
不同版本的依赖会生成不同的字节码。
诊断:
## 检查是否存在 Cargo.lock
ls -la Cargo.lock
## 比较依赖版本
cargo tree | grep -v '(*)' | head -20
解决方案:
Cargo.lock 文件Cargo.lock 提交到源代码管理Cargo.toml 中使用精确版本:[dependencies]
soroban-sdk = "=21.0.0"
some-crate = "=1.2.3" # 不是 "^1.2.3" 或 "~1.2.3"
不同的操作系统、架构或工具链版本都会影响输出。
诊断:
## 检查 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
每次产生不同输出的代码(时间戳、随机数)。
错误示例:
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
}
错误:
{
"error": "COMPILATION_FAILED",
"message": "Source code failed to compile",
"details": "error[E0425]: cannot find function `transfer` in this scope"
}
症状:
根本原因:
诊断:
## 尝试在本地构建
cargo build --release --target wasm32-unknown-unknown
解决方案:
确保所有依赖都在 Cargo.toml 中:
[dependencies]
soroban-sdk = "21.0.0"
## 添加任何缺失的 crate
serde = { version = "1.0", features = ["derive"] }
诊断:
cargo check
解决方案: 修复编译器报告的语法错误。
诊断:
grep edition Cargo.toml
解决方案:
[package]
edition = "2021" # Soroban 合约使用 2021 edition
诊断: 检查合约是否使用了需要启用的 feature。
解决方案:
[features]
default = ["soroban-sdk/testutils"]
[dependencies]
soroban-sdk = { version = "21.0.0", features = ["alloc"] }
错误:
{
"error": "CONTRACT_NOT_FOUND",
"message": "Contract does not exist on specified network",
"contract_id": "CDLZFC3...",
"network": "mainnet"
}
症状:
根本原因:
你在 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 # 正确的网络
诊断: 逐字符仔细检查 Contract ID。
解决方案: 直接从部署输出或区块链浏览器复制 Contract ID。
诊断: 检查部署状态。
解决方案: 先部署合约,然后再验证:
## 部署
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
错误:
{
"error": "INVALID_SOURCE_FORMAT",
"message": "Source code encoding or format is invalid",
"details": "Failed to decode base64 source code"
}
症状:
根本原因:
源文件中存在非 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
诊断:
## 测试 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
验证需要 Cargo.toml、Cargo.lock 和源文件。
诊断:
## 检查压缩包内容
tar tzf source.tar.gz
解决方案: 确保压缩包包含:
Cargo.toml
Cargo.lock
src/
lib.rs
(其他 .rs 文件)
错误:
{
"error": "ABI_MISMATCH",
"message": "Contract ABI does not match declared interface",
"details": "Function 'transfer' signature mismatch: expected (Address, Address, i128), found (Address, i128)"
}
症状:
根本原因:
你验证的是另一个版本的合约源代码。
诊断: 检查 git 历史:
git log --oneline --graph src/lib.rs
解决方案: 获取用于部署的确切 commit 对应的源代码:
git checkout <deployment-commit-hash>
feature 或 cfg 标志会改变接口。
诊断:
// 示例问题:
##[cfg(feature = "extra-functions")]
pub fn special_transfer() { ... }
解决方案: 使用与部署相同的 features:
cargo build --release --features "extra-functions" --target wasm32-unknown-unknown
错误:
{
"error": "BUILD_TIMEOUT",
"message": "Contract compilation exceeded maximum time limit (300 seconds)"
}
症状:
根本原因:
庞大的依赖树会减慢编译。
诊断:
cargo tree --depth 3
解决方案:
default-features = false:[dependencies]
heavy-crate = { version = "1.0", default-features = false, features = ["minimal"] }
大量宏展开会减慢构建。
解决方案:
在验证前始终先在本地测试编译:
## 清理构建
cargo clean
cargo build --release --target wasm32-unknown-unknown
## 检查输出
ls -lh target/wasm32-unknown-unknown/release/*.wasm
## 获取哈希
sha256sum target/wasm32-unknown-unknown/release/*.wasm
将本地构建结果与链上字节码进行比较:
## 获取链上合约
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
如果不确定使用的是哪个编译器版本:
##!/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
查看详细的验证日志:
## 获取验证详情
curl -s https://registry.soroban.example/api/verifications/ver_abc123 | jq
## 查找具体错误
curl -s https://registry.soroban.example/api/verifications/ver_abc123/logs
找一个类似且验证成功的合约:
## 搜索已验证合约
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-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,请提交以下信息:
提交至: https://github.com/ALIPHATICHYD/Soroban-Registry/issues
标签:verification、bug
在提交验证之前:
Cargo.lock 已提交并包含在内Cargo.toml、Cargo.lock、src/如需验证帮助:
verification、troubleshooting
- 原文链接: github.com/ALIPHATICHYD/...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!