定位交易 Revert 根因
从失败状态沿 Execution Trace 定位最内层错误,并用时间参数和执行上下文验证根因。
案例目标
判断交易为什么失败、错误最早在哪里产生,以及链上输入是否足以支持这一结论。
示例交易与背景
本例分析一笔 Ethereum 失败交易:
0x3d48f58695be07b355ba5d5ca42e4a221f3008f63c055aa031b7f4b92b2eee2f在 Skylens 中打开交易 · 在 Etherscan 中核对交易
交易公开错误为 Expired。调用目标为 0x278d858f05b94576C1E6f73285886876ff6eF8D2,入口 selector 为 0x669dc5b6。
预期回答的问题
Expired是在哪个调用节点产生的?- 失败是权限、余额、滑点还是截止时间导致的?
- Revert 后还有哪些最终影响?
分析步骤
- 在 Overview 确认交易状态、From、To、selector 和 Revert 信息。
- 在 Execution Trace 中沿失败标记向内展开,停在第一个直接产生错误且没有更深失败子节点的位置。
- 记录该节点显示的 Trace 编号、合约地址、输入参数、返回数据和父调用。Trace 编号可能随分析版本重新生成,因此同时保留地址和 selector。
- 在 Source Debugger 中检查失败位置的时间比较;源码不可用时,切换 Bytecode Debugger,检查
REVERT前的比较指令和 calldata。 - 回到 Balance Changes 与 State Changes,区分执行过程中尝试发生的行为和 Revert 后真正保留的结果。
关键证据
| 证据 | 值 | 说明 |
|---|---|---|
| 交易执行时间 | 2026-03-03 14:40:11 UTC | 交易被区块打包的时间 |
| calldata 中的 deadline | 0x69a6f254 = 1772548692 | 转换为 2026-03-03 14:38:12 UTC |
| 时间差 | 119 秒 | 执行时间晚于 deadline |
| 失败合约 | 0x278d858f05b94576C1E6f73285886876ff6eF8D2 | 交易直接调用目标 |
| 入口 selector | 0x669dc5b6 | 无需依赖函数名即可稳定定位 |
| Revert 信息 | Expired | 与时间证据一致 |
| Gas | limit 600,000;used 148,785 | 状态回滚,但 Gas 仍被消耗 |
deadline 比执行时间早 119 秒,形成了可独立核对的直接证据。若 Source Debugger 或 Bytecode Debugger 中的失败条件也读取同一 deadline,则可以排除“只根据错误文本猜测”的风险。
案例结论
交易在 deadline 之后 119 秒才执行,目标调用返回
Expired。错误文本、calldata 中的 deadline 和区块执行时间三项证据相互一致,因此根因是截止时间已过,而不是余额不足或资产转移失败。交易状态变化被回滚,最终成本是已消耗的 Gas。
注意事项
- 最内层 Revert 不一定等于业务根因;仍需检查错误参数由哪个上层调用构造。
- 内部调用失败不一定导致整笔交易失败,父合约可能捕获错误。
- Trace 编号是界面内的导航标识,报告中还应记录地址、selector 和输入值。
- 内部 Event 或转移记录不代表最终状态,结论应以 Balance Changes 和 State Changes 为准。
