English version · 区块链学习导航 · 上一篇
区块链学习 · 文章 BC039

一笔被称为“失败”的交易,可能从未进入区块,可能只是离开某节点的候选池,也可能已经纳入并执行失败。它们对应的证据和影响不同。一个红色标签,不足以判断应用记录、发送者 nonce 或费用是否改变。
本篇使用受控执行练习,先分类结果,再考虑原因。还会检查一种容易忽略的情况:内部调用失败,外层程序处理了失败,整笔交易却成功。目标是准确诊断,不是指导读者重发真实交易。
选择适合你的阅读路线
本篇目录
- 1. 先分类阶段,再命名原因
- 2. 使用身份明确的收据,而不是脱离上下文的状态词
- 3. 练习分开三种状态
- 4. 案例 A:已纳入执行之前被拒绝
- 5. 案例 B:本地消失,但链结果未知
- 6. 案例 C:已纳入且成功的调用
- 7. 案例 D:已纳入的顶层 REVERT
- 8. 案例 E:顶层 gas 耗尽
- 9. 案例 F:内部失败被外层程序处理
- 10. 错误文本是线索,不是经过认证的诊断
- 11. 建立以证据为先的诊断
- 12. 自动重试可能回答了错误的问题
- 13. 练习:分类六种案例
- 14. 常见问题
- 15. 资料来源与后续阅读
先看纳入、顶层结果和受影响状态这三个问题,再比较给定的成功、REVERT 和 gas 耗尽情形。不要看到一条错误信息就判断整笔交易结果;应先阅读嵌套调用例子。
账户、数值和资源总量均为虚构。练习借用普通 EVM 风格调用的部分区别,但不是完整以太坊实现。它排除合约创建、委托授权、转移数额、blob 费用及无关服务商收费。
1. 先分类阶段,再命名原因
首先询问候选交易是否纳入某个具体选定区块。提交错误或本地池中消失,本身不等于已纳入执行失败。
确定纳入后,再检查顶层执行状态。然后区分哪些状态变化属于交易层处理,哪些属于应用执行,哪些属于内部调用帧。
这能防止常见错误:先猜“gas 不够”,再把所有观察都解释成支持这个猜测。同一个界面失败标签,可能涵盖输入无效、缺少依赖、应用条件失败,或程序有意处理过的内部错误。
有用的初步报告应说明已知阶段和缺失证据。“这个接口拒绝了提交,尚未确定纳入”比“区块链把它回退了”准确;后者声称发生了某项执行,而它可能从未发生。
2. 使用身份明确的收据,而不是脱离上下文的状态词
EIP-658创建于 2017 年 6 月 30 日,状态为 Final,规定了适用以太坊上下文中的交易收据顶层成功或失败状态。它是有价值的证据,却不完整解释每个应用条件。
已纳入失败可以有收据,因此失败并不意味着交易从区块里消失。反过来,某接口在某时没有返回收据,也不能证明其他观察者都没有看到纳入。
应记录网络、交易标识、所在区块身份和接口的选定链上下文。不再选定分支上的收据,与当前选定历史中的收据,是不同证据。
成功状态也不证明人已经得到预期业务结果。程序可能正常返回却未做所需更新,或者通过替代路径处理了内部失败。因此,还要看应用状态和执行行为,不能只看顶层状态。
3. 练习分开三种状态
各主要案例都独立从同一个快照开始。发送者 A 拥有 200,000 个虚构点数,普通下一 nonce 为 7;应用记录值为 8。预期成功调用会把该值改为 9。
已纳入案例使用 nonce 7;案例 A 明确改用错误的候选 nonce 6。交易 gas 上限 50,000,有效执行单价为每 gas 2 点。每种结果的最终计费 gas 直接给定,不从字节码推导。在已纳入案例中,所需支付能力和普通交易有效性条件都满足。
不向其他账户转移价值,发送者余额变化只来自给定执行费用。资源总量已代表相关最终核算,不需要读者再加退款、最低计费或其他费用部分。
分别跟踪发送者余额、发送者下一 nonce 和应用值。重点是理解:应用更新失败,不会自动让整个交易处理流程的每个字段都回到原值。
Geth v1.16.5 状态转移实现提供带版本的具体参考:普通调用路径在 EVM 调用前推进发送者 nonce。本文使用这一限定区别,不声称该版本覆盖所有未来分叉或账户机制。
4. 案例 A:已纳入执行之前被拒绝
这个独立案例中,候选交易未通过执行前必需的有效性条件,没有被纳入。具体而言,候选 nonce 为 6,而给定状态要求 7。给定案例明确是拒绝,而不是原因未知的延迟。
没有为该候选对象执行已纳入操作。练习中,余额保持 200,000,下一 nonce 保持 7,应用值保持 8;该次被拒绝尝试没有链上执行费用。
不能把结果推广到所有携带未来 nonce 的对象。节点可能按策略暂存等待,本地保留与立即执行资格不同。本案例的证据明确说明尝试被拒绝且未纳入。
如果应用执行根本没有开始,就不应把值未改变称为“回滚了”。“没有发生已接受的应用状态转移”更符合证据。
5. 案例 B:本地消失,但链结果未知
假设节点此前保留候选交易,后来不再在池中报告它,但没有提供纳入证据。这是本地观察,不是完整执行结果。
候选对象可能被容量策略移除、按策略替换、失去资格,或因其他原因不在该接口视图中。调查必须取得相应证据,而不能自动任选解释。
此时不能仅因消失就推断新的余额、nonce 或应用值。如果练习额外说明选定链状态未变,那么字段仍为初始快照;如果没有这个额外事实,正确答案是链结果尚未确定。
另一候选交易也可能在别处使用相同发送者位置。“已丢弃”这种本地标签,不能说明选定链究竟接受了哪笔交易,甚至不能确定是否接受过。交易池课程提供观察方法;此处关键是,不能从池条目缺失编造出回退过程。
6. 案例 C:已纳入且成功的调用
成功案例已纳入,给定最终计费 gas 为 25,000。单价 2,因此费用为 50,000 点。
发送者余额变为 200,000−50,000=150,000,普通 nonce 从 7 前进到 8,应用更新成功,值变为 9。
这构成比较失败案例的基线。三个字段都改变,但原因不同:处理收费、使用普通发送者序列位置,以及成功应用写入。
练习同时给定顶层成功和应用更新。在真实诊断中,不能仅从成功状态推断具体数值为 9;相关代码路径与状态证据必须支持这一额外结论。
7. 案例 D:已纳入的顶层 REVERT
重新从原快照独立执行。应用尝试操作,但顶层调用遇到 REVERT 条件。给定最终计费 gas 为 30,000。
在本案例执行回退下,应用值回到 8。费用为 30,000×2=60,000,发送者余额剩 140,000。普通 nonce 为 8,而不是 7。交易仍然已纳入,只是顶层执行结果失败。
EIP-140创建于 2017 年 2 月 6 日,状态为 Final,规定 REVERT 回退受影响执行变化,但不会必然消耗全部剩余 gas。它不表示已经核算的处理工作变成免费。
关键边界在于哪些内容回退。“应用写入未保留”在此正确;“任何地方都什么也没发生”则不正确,因为选定历史包含交易、发送者序列位置被使用,而且收取了给定费用。
执行轨迹可能显示中途临时写入,随后又回退。这种轨迹观察不能证明最终持久应用值改变。应区分中间执行步骤与结果选定状态。
8. 案例 E:顶层 gas 耗尽
另一个独立案例中,顶层执行耗尽给定交易 gas 预算。练习给定最终计费 gas 为全部 50,000,没有额外核算调整。
费用为 50,000×2=100,000,发送者余额剩 100,000,nonce 前进到 8,失败的应用执行让最终值仍为 8。
它与 REVERT 案例给定的 30,000 用量不同,虽然两者顶层均失败,最终应用值也相同。笼统“失败”标签不能区分资源结果。
Geth v1.16.5 EVM 调用实现在恢复调用快照和处理剩余 gas 时,区分执行回退错误与其他异常调用错误。这支持检查真实失败类别和调用帧,而不是把错误全部视为同一种情况。
不能把顶层练习扩大为“任何内部 gas 耗尽都会消耗整笔交易上限”。内部调用有自己的分配执行上下文,外层可能保留不同资源并采用不同处理方式。下一案例明确展示这一边界。
9. 案例 F:内部失败被外层程序处理
额外设置一个外层应用字段 handled,初始为 false。外层程序调用子操作,尝试把子记录从 8 改成 9;子调用回退,因此子记录仍为 8。
给定外层代码捕获这次外部调用失败,把 handled 设为 true,并成功完成。因此,本情形整笔交易顶层成功,即使轨迹里存在一个失败子调用。
该独立案例最终计费 gas 为 35,000。按单价 2,费用 70,000,发送者余额变为 130,000,普通下一 nonce 变为 8。最终应用事实是子记录值 8、外层 handled true。
Solidity 0.8.30 控制结构参考说明外部调用与合约创建的异常处理。案例假设相关失败被捕获,剩余外层执行成功;并不声称所有位置的所有失败都能捕获。
如果外层选择传播错误,最终顶层回退,那就是另一个案例。调用边界和错误处理路径是证据的一部分,不能看到第一条错误信息后就忽略。
10. 错误文本是线索,不是经过认证的诊断
错误字符串或解码后的自定义错误,可以帮助定位条件,却不能完整证明哪个组件导致问题,或整笔交易是否失败。
Solidity 0.8.30 ABI 规范提醒,错误数据可以沿调用传播,也可被其他合约模仿。因此,熟悉的错误名必须结合调用轨迹、代码和执行上下文解释。
有用诊断应识别相关调用帧、那里评估的条件,以及结果如何传播,也应区分应用主动拒绝、资源耗尽和其他异常。
这不是要求信任任意轨迹服务。应记录来源与限制,再与已纳入交易、收据及最终状态比较。解码后的解释,是建立在执行证据上的解释层。
11. 建立以证据为先的诊断
真实报告应围绕具体问题组织调查,而不是先在网络上重试。
- 检查的是哪个网络、交易标识和区块上下文?
- 已确定纳入,还是只有提交与交易池观察?
- 适用规则下的顶层收据状态是什么?
- 哪个调用帧首先报告相关失败,它被捕获还是继续传播?
- 哪些应用变化回退,哪些交易层效果保留?
- 相关费用部分的最终计费 gas 与有效单价是什么?
- 状态查询是否与收据、轨迹指向同一选定历史?
- 因资料或上下文缺失,还存在哪些不确定性?
案例 D 的简明结论是:“已纳入、顶层 REVERT;应用值保持 8,普通发送者 nonce 为 8,给定处理费用使余额剩 140,000。”这比“交易什么都没做”更有用。
案例 F 应说:“子更新回退,但外层程序处理后完成;子值仍为 8,handled 变为 true。”不能只因一个子帧被标红,就改成“全部失败”。
12. 自动重试可能回答了错误的问题
重复指令不是诊断。相关状态、nonce、截止条件或应用条件可能已经改变。即使表面用户请求相似,后续交易也可能走不同路径。
普通模型中的已纳入失败之后,发送者 nonce 已前进。把旧序列位置当成尚未使用,与给定状态矛盾。反过来,本地消失也不能证明该位置是否已在别处使用。
如果顶层交易通过替代路径成功,重试也可能不合适。决定另一个动作应做什么之前,应先确认实际应用结果和用户希望的下一步。
本篇有意止于证据记录,不建议在真实网络提高费用、替换 nonce 或重发。可迁移的技能是:在任何人选择有后果的后续行动前,知道必须先确认哪些事实。
13. 练习:分类六种案例
使用独立快照和给定资源总量,不要把上一案例的结束余额带入下一案例。
- 候选交易明确在纳入前被拒绝。练习中的三个字段哪些改变?
- 节点不再报告待处理候选对象,却没有链状态证据。能断言应用回退了吗?
- 已纳入成功案例计费 25,000 gas。余额、下一 nonce、应用值分别是多少?
- 顶层 REVERT 案例计费 30,000。哪些保留,哪些改变?
- 顶层 gas 耗尽案例计费 50,000,其余额与 REVERT 案例相比如何?
- 子调用回退,外层捕获并成功,计费 35,000。顶层成功可以与子值未变同时成立吗?
- 熟悉的解码错误名,能独立证明失败组件身份吗?
答案与理由
- 均不改变:余额 200,000、下一 nonce 7、应用值 8。给定案例没有已纳入执行。
- 不能。本地池缺席不确定执行结果,也不证明状态回退。
- 余额 150,000、下一 nonce 8、应用值 9,费用为 50,000。
- 应用值仍为 8,余额变 140,000,下一 nonce 变 8。应用回退不抹去给定交易层效果。
- 余额 100,000,比 REVERT 的 140,000 少 40,000,因为计费 gas 多 20,000、单价为 2。
- 可以。余额 130,000、下一 nonce 8、子值 8、handled true。外层成功不会让失败子更新保留。
- 不能。错误数据需要代码、调用帧和上下文证据;它可能是传播或模仿而来。
延伸:应用状态相同,历史不同
案例 A、D、E 都让应用值保持 8,但发送者字段不同。A 余额 200,000、nonce 7;D 为 140,000、8;E 为 100,000、8。
因此,只查询应用值,无法判断候选交易是被拒绝、纳入后回退,还是耗尽顶层预算。不同历史可以到达相同应用快照。
14. 常见问题
失败交易可以出现在有效区块中吗?
可以。在适用执行模型中,已纳入交易的应用执行可以失败,而交易本身仍是被有效处理的。不要混淆交易有效性要求与应用行为成功。
REVERT 会退回所有东西吗?
不会。它按规则回退受影响执行变化,不会让已经计费的处理全部消失,也不会普遍恢复所有交易层字段。
收据成功代表所有嵌套调用都成功吗?
不代表。外层程序可以处理内部失败后完成,应检查相关调用和应用结果。
没有收据等于失败吗?
不等于。接口可能尚无纳入信息,候选对象可能仍待处理,或观察本身不完整。分类之前先确认上下文。
15. 资料来源与后续阅读
资料于新加坡时间 2026 年 10 月 12 日核对。实现参考固定为 Geth v1.16.5 和 Solidity 0.8.30,不代表所有网络、交易类型或未来规则。
- EIP-658:Final,创建于 2017 年 6 月 30 日;顶层收据状态。
- EIP-140:Final,创建于 2017 年 2 月 6 日;REVERT 语义。
- Geth v1.16.5 状态转移:普通发送者检查与执行周边的 nonce 推进。
- Geth v1.16.5 EVM 调用:调用快照与错误类别处理。
- Solidity 0.8.30 控制结构:外部调用异常处理。
- Solidity 0.8.30 ABI 规范:信任解码错误数据的边界。
回顾 gas 核算,区分上限、计费用量与单价;回顾存储和事件,比较最终状态与中间或历史观察;接着学习预言机,理解链上规则与外部信息边界处可能出现的问题。
