打开网易新闻 查看精彩图片

以太坊虚拟机(EVM)每秒要拒绝多少笔 malformed transaction?没人统计过,但验证层是第一道闸门。REVM 的 handler 把这件事拆成了两步:先看环境对不对,再算 gas 够不够。本文顺着代码走一遍,看看一笔交易是怎么被"验明正身"的。

环境检查:版本特性有没有配齐

环境检查:版本特性有没有配齐

validate_env 是入口。它从上下文里捞出当前 spec(即 EVM 版本),然后做两件事。

第一,MERGE 之后必须有 prevrandao。 这是 PoS 切换后的随机信标字段,没设置直接报错 PrevrandaoNotSet。

第二,CANCUN 之后必须有 blob 相关配置。 4844 引入的 blob 交易需要 excess_blob_gas_and_price,缺了同样打回。

代码逻辑很直白:if spec.is_enabled_in(SpecId::MERGE) && context.block().prevrandao().is_none(),就 return Err。没有魔法,就是版本特性对齐检查。

完事之后调用 validate_tx_env,进入交易级别的验证。

交易验证:还没执行就要算清 gas 账

交易验证:还没执行就要算清 gas 账

validate_initial_tx_gas 是第二步。它的任务是在执行前算出两笔数:InitialGas 和 FloorGas。

InitialGas 是交易实际能用的 gas——扣掉固有成本(21000 基础 + 数据费用 + 访问列表费用等)。FloorGas 是 4844 引入的"地板价",防止 blob 交易被压价。

如果用户给的 gas_limit 连 InitialGas 都 cover 不住,直接 InvalidTransaction::CallGasCostMoreThanGasLimit。还没进 EVM 就省了算力。

代码结构:为什么拆成两步

代码结构:为什么拆成两步

validate_env 和 validate_initial_tx_gas 分离,是为了错误隔离。环境错是区块配置问题,gas 错是用户输入问题,报错信息能精确定位。

再看 validate_env 内部的委托链:handler.rs → validation.rs → validate_tx_env。每层只做一件事,方便测试和 mock。context 作为泛型参数 CTX: ContextTr 贯穿始终,解耦了具体存储实现。

这种设计让 REVM 可以嵌入不同场景——全节点、轻客户端、甚至游戏引擎里的嵌入式 EVM——只换 context 实现,验证逻辑不动。

一个细节:#[inline] 标记在 Rust 里提示编译器内联展开。验证是高频路径,减少函数调用开销值得。

验证层没有优化空间了吗?CANCUN 之后 blob 验证的逻辑还在膨胀,下次硬分叉会不会再加一条 if 分支?