智能合约验证工作流

本文详细阐述了 Stellar 链上 Soroban 智能合约的验证工作流,解释了如何通过比对源码编译后的 WASM 字节码哈希与链上数据来建立技术信任。内容涵盖了从验证步骤、常见错误分析、构建可复现性要求到 CLI 和 CI/CD 自动化集成的全方位指南。

智能合约验证工作流

概览

合约验证证明你声称的源代码与部署在 Stellar 区块链上的字节码相匹配。这通过允许用户在交互前审计合约行为来建立信任。

当前实现现在在 API 路径中强制执行验证:

  • POST /api/contracts/verify 先创建一条 pending 验证记录。
  • 后端 verifier 将提交的源代码编译为 WASM,计算编译后字节的 SHA-256,并将其与已部署的 contracts.wasm_hash 进行比较。
  • 验证记录在成功时最终状态为 verified,失败时为 failed,并附带 error_message
  • contracts.is_verified 仅在验证成功时设置为 true

验证流程

┌─────────────────┐
│ 用户提交        │
│ 源代码 +        │──┐
│ 合约 ID         │  │
└─────────────────┘  │
                     │
                     ▼
┌─────────────────────────────────────┐
│ 1. 验证                             │
│  ✓ 合约 ID 在链上存在               │
│  ✓ 源代码格式有效                   │
│  ✓ 没有之前的验证                   │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│ 2. 编译                             │
│  • 解析源代码                       │
│  • 设置构建环境                     │
│  • 使用 soroban-sdk 编译            │
│  • 生成 WASM 字节码                 │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│ 3. 字节码比较                       │
│  • 对编译后的 WASM 进行哈希         │
│  • 获取链上字节码哈希               │
│  • 比较哈希                         │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│ 4. ABI 验证(可选)                 │
│  • 提取合约接口                     │
│  • 与声明的 ABI 比较                │
│  • 验证方法签名                     │
└──────────────┬──────────────────────┘
               │
               ▼
┌─────────────────────────────────────┐
│ 5. 存储结果                         │
│  • 保存验证状态                     │
│  • 存储源代码                       │
│  • 更新合约元数据                   │
│  • 发出验证事件                     │
└─────────────────────────────────────┘
               │
               ▼
        ┌──────┴──────┐
        │             │
    成功          失败
        │             │
        ▼             ▼
   合约上的徽章   带详细信息的
                  错误报告

验证内容

1. 字节码匹配

核心验证确保编译你的源代码生成的 WASM 字节码与链上部署的字节码 完全相同

流程:

  1. 编译源代码 → WASM 字节码
  2. 使用 SHA-256 对字节码进行哈希
  3. 通过 Stellar RPC 获取链上合约字节码哈希
  4. 比较:hash(compiled_wasm) == on_chain_hash

成功标准: 哈希完全匹配(逐字节一致)。

2. ABI 匹配

验证合约接口是否符合预期。

检查项:

  • 函数名称和签名
  • 参数类型和名称
  • 返回类型
  • 自定义类型和 struct

成功标准: 源代码中的所有公开函数都与从字节码中提取的 ABI 匹配。

3. 源代码完整性

确保源代码完整且可构建。

检查项:

  • 有效的 Rust 语法
  • Cargo.toml 中指定了所有依赖
  • 没有缺失文件或模块
  • 正确的 soroban-sdk 版本

成功标准: 代码可无错误编译。

验证方法

方法 1:源代码验证(推荐)

提交完整源代码进行编译和比较。

API 端点:

POST /api/contracts/verify
Content-Type: application/json

{
  "contract_id": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
  "source_code": "base64_encoded_source",
  "compiler_version": "21.0.0",
  "optimization_level": "z"
}

响应(成功):

{
  "verified": true,
  "status": "verified",
  "verification_id": "ver_abc123",
  "contract_id": "f7da1d3a-31f2-40f8-9b6f-ec63fe4a60b7",
  "compiled_wasm_hash": "a3f2b8c9d1e4...",
  "deployed_wasm_hash": "a3f2b8c9d1e4..."
}

响应(失败):

{
  "error": "VerificationFailed",
  "message": "Bytecode mismatch: compiled hash 9f1a2b3c4d5e... does not match deployed hash a3f2b8c9d1e4...",
  "code": 422
}

方法 2:二进制哈希验证

通过直接提供 WASM 字节码哈希进行验证(适用于预编译合约)。

API 端点:

POST /api/contracts/verify-hash
Content-Type: application/json

{
  "contract_id": "CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC",
  "bytecode_hash": "a3f2b8c9d1e4..."
}

使用场景: 当源代码无法公开,但你想验证字节码哈希是否正确时。

成功标准与失败原因

验证成功

当以下 所有 条件都成立时,验证成功:

  1. ✅ 合约在指定 ID 上链上存在
  2. ✅ 源代码成功编译
  3. ✅ 编译后的字节码哈希与链上哈希匹配
  4. ✅ 从字节码提取的 ABI 与声明的接口匹配
  5. ✅ 没有编译警告或错误

常见失败原因

错误代码 原因 如何修复
CONTRACT_NOT_FOUND 链上不存在该合约 ID 验证合约 ID,检查网络
BYTECODE_MISMATCH 编译字节码 ≠ 链上字节码 检查 compiler 版本、优化设置
COMPILATION_FAILED 源代码无法编译 修复语法错误,确保依赖正确
ABI_MISMATCH 函数签名不匹配 确保源代码与已部署版本一致
INVALID_SOURCE_FORMAT 源代码编码/格式问题 检查文件编码(UTF-8)、正确的 base64
COMPILER_VERSION_MISMATCH 使用了错误的 soroban-sdk 版本 使用最初部署时的精确版本
OPTIMIZATION_MISMATCH 错误的优化级别 尝试不同的 -C opt-level 设置
MISSING_DEPENDENCIES Cargo.toml 缺少依赖 包含完整的依赖树
BUILD_TIMEOUT 编译耗时过长 简化合约或联系支持

重试逻辑与退避

如果验证因瞬态问题(RPC 超时、网络错误)失败,系统会自动重试:

重试策略:

第 1 次尝试:立即
第 2 次尝试:+2 秒
第 3 次尝试:+4 秒
第 4 次尝试:+8 秒
第 5 次尝试:+16 秒(最终)

可重试错误:

  • RPC 超时
  • 网络连接问题
  • 临时服务不可用
  • 限流

不可重试错误:

  • 字节码不匹配
  • 编译失败
  • 无效源代码
  • 找不到合约

使用 CLI 进行验证

基本验证

soroban-registry verify \
  --contract-id CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC \
  --source ./src \
  --network mainnet

高级选项

soroban-registry verify \
  --contract-id CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC \
  --source ./src \
  --compiler-version 21.0.0 \
  --optimization-level z \
  --network mainnet \
  --wait-for-confirmation \
  --verbose

标志:

  • --source:合约源代码目录路径
  • --compiler-version:指定 soroban-sdk 版本
  • --optimization-level:Rust 优化(0123sz
  • --wait-for-confirmation:等待验证完成
  • --verbose:显示详细编译输出

检查验证状态

soroban-registry info CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC

输出:

Contract: CDLZFC3SYJYDZT7K67VZ75HPJVIEUVNIXF47ZG2FB2RMQQVU2HHGCYSC
Status: Verified ✓
Verified at: 2026-02-24 12:34:56 UTC
Compiler: soroban-sdk 21.0.0
Source available: Yes

通过 Web 界面验证

第 1 步:进入合约页面

前往:https://registry.soroban.example/contracts/{contract_id}

第 2 步:点击 "Verify Contract"

第 3 步:上传源代码

选项 A - 上传 ZIP:

  • 上传包含源代码的 .zip 文件
  • 必须包含 Cargo.tomlsrc/ 目录
  • 最大大小:10 MB

选项 B - 粘贴源代码:

  • 直接粘贴合约源代码
  • 单独指定 Cargo.toml 依赖

选项 C - GitHub 集成:

  • 链接到 GitHub 仓库 + commit hash
  • 自动获取源代码

第 4 步:指定构建设置

  • Compiler Version:选择 soroban-sdk 版本(例如 21.0.0
  • Optimization Level:选择优化(默认:z,用于减小体积)
  • Network:Mainnet、Testnet 或 Futurenet

第 5 步:提交并监控

  • 验证在后台运行(通常 30-120 秒)
  • 显示实时进度更新
  • 完成后发送电子邮件通知

构建可重现性

为了使验证成功,构建必须是可重现的——相同的源代码编译两次应生成相同的字节码。

确保可重现性

  1. Cargo.toml 中固定 soroban-sdk 版本

    [dependencies]
    soroban-sdk = "=21.0.0"  # 使用精确版本
  2. 固定所有依赖:

    [dependencies]
    some-crate = "=1.2.3"  # 不是 "^1.2" 或 "~1.2"
  3. 使用 Cargo.lock

    • Cargo.lock 提交到仓库
    • 确保精确的依赖版本
  4. 显式指定 target:

    [build]
    target = "wasm32-unknown-unknown"
  5. 在构建中禁用时间戳:

    [profile.release]
    opt-level = "z"
    debug = false

在本地检查可重现性

## 构建两次并比较
cargo build --release --target wasm32-unknown-unknown
mv target/wasm32-unknown-unknown/release/my_contract.wasm build1.wasm

cargo clean
cargo build --release --target wasm32-unknown-unknown
mv target/wasm32-unknown-unknown/release/my_contract.wasm build2.wasm

## 比较字节码
sha256sum build1.wasm build2.wasm
## 哈希应该相同

验证时间线

阶段 典型时长 最大时长
验证 < 1 秒 5 秒
编译 10-60 秒 300 秒(5 分钟)
字节码获取 1-5 秒 30 秒
哈希比较 < 1 秒 1 秒
存储 1-2 秒 10 秒
总计 15-90 秒 5 分钟

注意: 依赖较多的复杂合约可能需要更长时间编译。

安全注意事项

源代码隐私

  • 已验证的源代码在 registry 中是公开可见
  • 不要包含密钥、API keys 或私人信息
  • 考虑使用环境变量进行配置

恶意源代码

  • 验证并保证合约安全
  • 已验证合约仍然可能是恶意的
  • 在信任合约之前始终审计源代码
  • 检查常见漏洞(见 安全最佳实践

验证伪造

  • 只信任来自官方 Soroban Registry 的验证
  • 检查验证时间戳和 verifier 身份
  • 对没有 registry 确认的“verified”声明保持警惕

验证徽章

成功验证的合约会显示徽章:

✓ 已于 2026-02-24 验证
源代码与链上字节码匹配

徽章包含:

  • 验证时间戳
  • 使用的 Compiler 版本
  • 查看源代码的链接
  • 已验证字节码的哈希

自动化与 CI/CD

GitHub Actions 示例

name: Verify Contract

on:
  push:
    tags:
      - 'v*'

jobs:
  verify:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3

      - name: Install Soroban CLI
        run: |
          cargo install soroban-cli
          cargo install soroban-registry-cli

      - name: Build Contract
        run: |
          cd contracts/my-contract
          cargo build --release --target wasm32-unknown-unknown

      - name: Deploy to Mainnet
        run: |
          soroban contract deploy \
            --wasm target/wasm32-unknown-unknown/release/my_contract.wasm \
            --network mainnet \
            --source deployer
        env:
          SOROBAN_SECRET_KEY: ${{ secrets.DEPLOYER_SECRET }}

      - name: Verify Contract
        run: |
          soroban-registry verify \
            --contract-id ${{ env.CONTRACT_ID }} \
            --source ./src \
            --network mainnet \
            --wait-for-confirmation

指标与监控

跟踪验证健康状况:

## 验证成功率
rate(soroban_verification_total{result="success"}[10m]) /
  rate(soroban_verification_total[10m])

## P99 验证延迟
histogram_quantile(0.99,
  sum(rate(soroban_verification_latency_seconds_bucket[5m])) by (le))

## 队列深度
soroban_verification_queue_depth

常见问题

Q: 验证需要多长时间?

A: 通常 15-90 秒。复杂合约可能需要长达 5 分钟。

Q: 我可以验证别人部署的合约吗?

A: 可以!任何人都可以提交源代码来验证任何合约。

Q: 如果我的源代码包含专有逻辑怎么办?

A: 已验证源代码是公开的。如果你不能公开源代码,请使用基于哈希的验证,或者不验证。

Q: 为什么我的验证会因 "bytecode mismatch" 失败?

A: 最常见原因是错误的 compiler 版本或优化设置。请参见 故障排查指南

Q: 合约部署后可以更新验证吗?

A: 不可以。验证绑定到特定的链上字节码。如果你升级合约,必须单独验证新版本。

Q: 我需要在每个网络上分别验证吗?

A: 需要。Mainnet、Testnet 和 Futurenet 是分开的,因此需要在合约部署的每个网络上分别验证。

Q: 支持哪些 compiler 版本?

A: 从 20.0.0 版本开始的所有稳定 soroban-sdk 发布版。

相关文档

支持

如遇验证问题:

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

0 条评论

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