graph LR
Spec[规范定义<br/>合约行为声明] --> Model[数学模型<br/>状态机/霍尔逻辑]
Model --> Tool[验证工具<br/>TLA+/Coq/SMT]
Tool --> Proof[形式化证明<br/>自动/半自动推导]
Proof --> Correct{满足规范?}
Correct -->|是| Safe[可信合约<br/>部署上链]
Correct -->|否| Bug[发现属性违反<br/>修复后重证]
Bug --> Spec
style Tool fill:#e3f2fd
style Safe fill:#c8e6c9
style Bug fill:#ffcdd2
测试只能证明 bug 存在,不能证明其不存在。形式化验证(Formal Verification)用数学声明和证明推导,在编译之前就证明合约满足其规范。
12.6.1 "指定即认知":规范的三种层次
| 规范层次 | 形式 | 工具 | 案例 |
|---|---|---|---|
| 类型系统 | 类型签名 | Solidity 0.8+ | uint256 防溢出 |
| 断言与不变式 | require / assert | 所有编译器 | 运行时检查 |
| 形式化规范 | 一阶逻辑 / 时序逻辑 | Coq / Lean / TLA+ | 数学证明 |
时序逻辑(TLA+)的状态机视角
text
合约核心 = 状态机 (S, S₀, Next, Invariant)
S = 所有可能状态的集合(合约变量赋值)
S₀ = 所有可能初始状态
Next ⊆ S × S 合法转移关系
Invariant ⊆ S 必须在所有可达状态中被满足的谓词
Safety 定理: ∀ s ∈ Reachable(S₀, Next), Invariant(s) = true12.6.2 Solidity 形式化工具入门
12.6.2.1 符号执行(Mythril)
用 SMT 求解器 约束所有路径,查找偏离规范的路径。
12.6.2.2 首个形式化验证工具:Coq + Serokell
text
Coq 逻辑:
Theorem no_reentrancy:
forall s s' old_bal caller target amount,
old_bal = s.balances[caller] /\
s.balances[contract] >= amount /\
step(s, withdraw(caller, amount), s') ->
s'.balances[caller] = 0.
Proof.
intros. unfold step, withdraw.
apply state_before_transfer. // 核心:先扣减再转出的不变式
contradiction. // 任何重入路径都导致矛盾
Qed.12.6.2.3 Certora:工业级验证框架
Certora 使用 CTL(计算树逻辑) 表达规范:
cvl
// 指定 ERC20 Transfer 语义
rule transfer_invariant {
env e;
address from; address to; uint amount;
require e.msg.sender == from;
mathint fromBal_before = balanceOf(e, from);
mathint toBal_before = balanceOf(e, to);
transfer(e, to, amount);
mathint fromBal_after = balanceOf(e, from);
mathint toBal_after = balanceOf(e, to);
// 不变式:from 的余额减少 amount,to 的余额增加 amount
assert from == to
=> fromBal_after == fromBal_before,
"transfer:self-transfer balance shouldn't change";
assert from != to
=> toBal_after == toBal_before + amount
&& fromBal_after == fromBal_before - amount,
"transfer:balance conservation";
}12.6.3 验证的范围与局限
| 可验证 | 难/不可验证 |
|---|---|
| 余额守恒(转账前后总量不变) | 外部预言机行为 |
| 调用顺序约束(先 A 后 B) | 经济均衡(代币价格稳定) |
| 溢出不可能性 | 51% 攻击概率 |
| 权限不变式(只有 owner 可暂停) | 矿工/验证者行为 |
形式化验证假设:
- EVM 语义正确
- 字节码正确对应源码
- 外部依赖(预言机)按规范行为
12.6.4 形式化验证在项目中的实践
| 项目 | 验证工具 | 验证范围 | 发现漏洞? |
|---|---|---|---|
| OpenZeppelin | Certora | ERC20/ERC721 核心 invariant | 未发现新 bug |
| Uniswap V2 | TLA+ | 储备关系不变式 | K = X*Y |
| Compound | Certora | 清算不变式、借贷关系 | 发现边界条件 |
| MakerDAO | K framework | 整系统形式化规约 | 发现装饰用 |
> ← 上一节:12.5 可升级合约 | 前往 → ch12-summary(本章总结) |*
评论
0评论加载中…