以太坊虚拟机最古老的加法和减法指令(ADD、SUB)不带任何报错机制:256 位整数加过了头就从头再来,减穿了底就绕回天文数字,指令本身一声不吭。这在早期尚可自理,但自 Solidity 0.8.0 起、以及 Vyper 自首版起,高级语言默认给每一次算术都包一层溢出检查——代价由 gas 买单。EIP-8219(2026 年 4 月创建,状态 Draft)提议让 EVM 学会说”检查过的算术”:新增 SAFEADD(0x0c)、SAFESUB(0x0d)、SAFEMUL(0x0e)、SAFEDIV(0x0f)四条指令,正常时与对应原始指令等价,一旦溢出、下溢或除以零,直接以空返回数据回滚当前调用帧,效果等价于执行 REVERT(0, 0)。
安全检查现在的过路费
提案引用了一组基准:Solidity 0.8.33(开优化器)里,一次带溢出检查的加法编译出至少五条指令的跳转模式,执行约 79 gas——原始 ADD 只要 3 gas——外加字节码里 12 个字节,部署时每处约 2352 gas。Vyper 0.4.3 稍好,一次约 41 gas、14 字节。把安全加法的倍率算出来:约二十五倍于裸加法,纯粹为了”看看有没有溢出”。链上每一份合约的每一个函数里的每一次算术都重复缴纳这笔税。更要紧的是提案点出的行为学副作用:正因为检查太贵,开发者大量使用 unchecked 代码块,Vyper 干脆提供 unsafe_add 一族显式不安全函数。它们对循环计数器之类可证明不溢出的场景确属正当,但”想省 gas 就关掉保护”的门一开,就有真实事故沿着 unchecked 的减法与乘法发生。安全检查的价格扭曲,本身就是一个安全漏洞的温床。
四条指令的规格
新指令占据 0x0c 到 0x0f 四个当前未分配的编码位,紧挨着既有算术指令组(0x01 至 0x0b)之后,这个排位本身是语义声明:它们就是算术指令,只是自带护栏。gas 定价 SAFEADD 与 SAFESUB 各 5(比裸版本贵 2),SAFEMUL 与 SAFEDIV 各 7。语义刻意做小:只覆盖无符号 256 位;错误处理只回滚、不设状态标志、不返回错误码;回滚时返回数据为空。提案给的选择逻辑是直白的——回滚语义与今天 Solidity 溢出时的行为一致,迁移零心智负担;而”返回标志位供查询”的替代设计会把错误处理重新推回多指令模式。
与两条前辈提案的分歧
溢出检查进 EVM 不是新念头。EIP-1051 曾提议让现有算术指令设置溢出标志,再用专门的检查与清零指令读取;EIP-6888 类似,引入进位与溢出标志加条件跳转。两条的共同软肋被 8219 的对比章节逐条列出:每次运算后仍需”读标志、条件跳转”的至少三条指令组合,标志还是跨指令存活的隐式 EVM 状态——静态分析要先推断标志生命周期,形式验证多了一维状态空间,编译器优化多了一条戒律,最阴的是时序陷阱:连着两次加法只在之后查一次标志,第一次溢出会被静默吞掉。EIP-8219 的立场是彻底不要标志:每条安全指令都是无状态的自足单元,要么给出正确结果要么让整帧回滚,一条指令的活绝不留给三条。基准表显示按此方向每次安全检查从约 79 gas 降到 5、字节码从 12 字节降到 1,省约 93.7%——安全不再是可选项,因为它便宜到没有理由不用。
顺带把提案的一处克制讲清楚:为什么只有无符号四条,没有带符号版本,也没有 SAFEMOD?带符号算术在合约里使用率远低于无符号(余额、供应量、计数几乎全是无符号量),为长尾场景多占编码位、多养一套边界测试,收益不成比例;求模运算的除零与溢出边界可以复用同一套判据,但提案作者选择先小步提交,把语言层的带符号封装留给编译器。这类”少而常用”的裁剪思路和当年 PUSH0 只补一个字节就解决高频痛点是同一设计趣味的两次出场。
快速问答
问:现有 Solidity 合约要改写吗? 答:若被采纳,编译器可把溢出检查直接编译成新指令,源码无需变化。
问:为什么要包括带检查的除法 SAFEDIV? 答:除零今天静默返回零,提案把它对齐其他语言与形式的直觉:除零是错误,该回滚。
问:提案现在生效了吗? 答:Draft,未进入任何已激活升级;主网仍是旧语义。
风险提示:算术边界处理直接关系合约资产安全,迁移决策请以语言与审计官方文档为准,本文不构成投资建议。
发表评论
还没有评论,来说两句吧。
评论区为展示样式,提交不会被处理。