VIEW THIS AS

Auto mode follows the Route Engine until you choose a viewpoint.

YOU ARE HERE

ROUTE CHECK

CONNECTED TO

WHAT NEXT

Use the canonical route for this room, or HELP if you are unsure.

诊断失败的区块链交易:区分拒绝、回退与调用边界

Three students in school uniforms work through open books at a classroom table, with textbooks and stationery nearby and study notes on the whiteboard behind them.

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

区块链学习 · 文章 BC039

三名学生在教室桌旁一起阅读书本,身边放有课本和文具。
学习场景配图;不代表照片中的学生正在学习区块链。

一笔被称为“失败”的交易,可能从未进入区块,可能只是离开某节点的候选池,也可能已经纳入并执行失败。它们对应的证据和影响不同。一个红色标签,不足以判断应用记录、发送者 nonce 或费用是否改变。

本篇使用受控执行练习,先分类结果,再考虑原因。还会检查一种容易忽略的情况:内部调用失败,外层程序处理了失败,整笔交易却成功。目标是准确诊断,不是指导读者重发真实交易。

选择适合你的阅读路线

本篇目录

先看纳入、顶层结果和受影响状态这三个问题,再比较给定的成功、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. 练习:分类六种案例

使用独立快照和给定资源总量,不要把上一案例的结束余额带入下一案例。

  1. 候选交易明确在纳入前被拒绝。练习中的三个字段哪些改变?
  2. 节点不再报告待处理候选对象,却没有链状态证据。能断言应用回退了吗?
  3. 已纳入成功案例计费 25,000 gas。余额、下一 nonce、应用值分别是多少?
  4. 顶层 REVERT 案例计费 30,000。哪些保留,哪些改变?
  5. 顶层 gas 耗尽案例计费 50,000,其余额与 REVERT 案例相比如何?
  6. 子调用回退,外层捕获并成功,计费 35,000。顶层成功可以与子值未变同时成立吗?
  7. 熟悉的解码错误名,能独立证明失败组件身份吗?

答案与理由

  1. 均不改变:余额 200,000、下一 nonce 7、应用值 8。给定案例没有已纳入执行。
  2. 不能。本地池缺席不确定执行结果,也不证明状态回退。
  3. 余额 150,000、下一 nonce 8、应用值 9,费用为 50,000。
  4. 应用值仍为 8,余额变 140,000,下一 nonce 变 8。应用回退不抹去给定交易层效果。
  5. 余额 100,000,比 REVERT 的 140,000 少 40,000,因为计费 gas 多 20,000、单价为 2。
  6. 可以。余额 130,000、下一 nonce 8、子值 8、handled true。外层成功不会让失败子更新保留。
  7. 不能。错误数据需要代码、调用帧和上下文证据;它可能是传播或模仿而来。

延伸:应用状态相同,历史不同

案例 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,不代表所有网络、交易类型或未来规则。

回顾 gas 核算,区分上限、计费用量与单价;回顾存储和事件,比较最终状态与中间或历史观察;接着学习预言机,理解链上规则与外部信息边界处可能出现的问题。

返回目录