拆解 geth callTracer 测试用例 inner_throw_outer_revert:嵌套 revert 的传播与追踪
拆解 geth callTracer 测试用例 inner_throw_outer_revert嵌套 revert 的传播与追踪【免费下载链接】go-ethereumGo implementation of the Ethereum protocol项目地址: https://gitcode.com/gh_mirrors/go/go-ethereum这篇技术指南聚焦于 go-ethereumgeth内置追踪器tracers测试数据目录中的inner_throw_outer_revert测试用例一个内层调用 throw、外层调用 revert的 Solidity 部署场景。读完后你将理解该用例如何由.md场景描述与.json预置状态/期望输出构成、callTracer 的callFrame结构如何在源码层面记录error与revertReason以及如何在本仓库中直接运行并验证这些测试。测试用例的落点tracetest 数据目录该文档位于 geth 追踪器测试套件的数据目录中与同名的 JSON 测试用例文件成对出现场景描述用一段 Solidity 源码说明该用例要验证什么行为测试数据完整的创世预置状态genesis alloc、块上下文context、原始交易输入inputRLP 编码的交易以及期望的 trace 输出result。同目录下还有simple.json、revert.json、revert_reason.json、inner_revert_reason.json、oog.json、delegatecall.json、deep_calls.json等一系列 callTracer 用例分别覆盖简单调用、带原因的回滚、嵌套创建、委托调用等场景。驱动这些数据的测试框架是 calltrace_test.go其中三个测试入口分别对应不同版本的追踪器func TestCallTracerLegacy(t *testing.T) { testCallTracer(callTracerLegacy, call_tracer_legacy, t) } func TestCallTracerNative(t *testing.T) { testCallTracer(callTracer, call_tracer, t) } func TestCallTracerNativeWithLog(t *testing.T) { testCallTracer(callTracer, call_tracer_withLog, t) }testCallTracer的执行流程L87-L174是读取testdata/call_tracer目录下的每个.json文件并反序列化为callTracerTest把input字段做二进制解码还原成交易用tests.MakePreState按genesis.alloc构建内存状态库然后经core.TransactionToMessage转为Message在core.ApplyMessage中执行最后把tracer.GetResult()返回的 JSON 与用例中的result字段逐字节比对。值得注意的是测试主循环只加载.json文件见 L93-L96因此.md文件不参与自动化执行它是给维护者看的场景说明书解释该 JSON 用例背后的合约意图。该目录的 README 还说明了新增用例的方式在 Geth 控制台里用makeTest.js脚本抓取某笔交易的 prestate 并执行指定 tracer把输出落成新的测试数据文件。原始场景一个必然失败的合约部署.md文档给出的场景是一对 Solidity 合约引自 inner_throw_outer_revert.mdcontract Revertor { function run() public pure { require(2 3, This called failed); } } contract Contract { constructor() { Revertor r new Revertor(); r.run(); } }调用链可以拆解为三层顶层部署Contract的交易CREATE执行构造函数中层构造函数内new Revertor()部署子合约内层 CREATE底层紧接着对刚部署的Revertor发起r.run()调用内部 CALL/STATICCALL其中require(2 3, ...)必然失败携带字符串原因This called failedrevert。文档对期望行为的结论是一句话trace 应当显示出 revert并且顶层调用top-call与内层调用inner call都要带出 revert reason。这正是嵌套回滚场景下对 callTracer 的核心要求——错误信息必须逐层向上传播且每一层各自的失败原因都要被独立捕获而不是只有最外层看到一句模糊的错误。读懂配套测试数据 inner_throw_outer_revert.json该 JSON 是同一场景较早时期的一条冻结用例一笔来自 RopstenchainId 3主网历史的真实交易部署在块 2295104context.number上执行创世配置为byzantiumBlock: 1700000的 ethash 链见 inner_throw_outer_revert.json 的genesis.config。文件结构与关键字段用例由四部分构成context执行块的元信息——块高2295104、难度、gasLimit5413248、出块者地址等genesis块2295103的完整头信息与alloc预置状态。alloc 中两个关键账户0x33056b5d...af76nonce1带完整合约代码交易的顶层to即包含回滚逻辑的已部署合约0xe819f024...78d4nonce1带完整合约代码内层被调用的合约其字节码中含CallCodeCoin字符串是经典的 CallCode 风格合约inputRLP 编码的 Legacy 交易0xf86d808504e3b292008307dfa69433056b5d...测试框架会将其解码为types.Transactionresult期望的 trace 输出。期望的 trace 输出result记录的正是内层 throw、外层 revert的传播形态{ calls: [ { error: invalid opcode: INVALID, from: 0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76, gas: 0x75fe3, gasUsed: 0x75fe3, input: 0xa9059cbb000000000000000000000000d4fcab9f0a6dc0493af47c864f6f17a8a5e2e82600000000000000000000000000000000000000000000000000000000000002f4, to: 0xe819f024b41358d2c08e3a868a5c5dd0566078d4, type: CALL, value: 0x0 } ], error: execution reverted, from: 0xd4fcab9f0a6dc0493af47c864f6f17a8a5e2e826, gas: 0x7dfa6, gasUsed: 0x7c1c8, input: 0x, to: 0x33056b5dcac09a9b4becad0e1dcf92c19bd0af76, type: CALL, value: 0xe92596fd6290000 }几个值得注意的细节错误逐层不同但都指向失败内层子调用的error是invalid opcode: INVALID该历史用例中内层合约通过跳到INVALID操作码throw属于 Byzantium REVERT 语义之前的经典失败写法顶层调用则记录execution reverted——外层因内层失败而整体回滚gas 语义内层调用分得0x75fe3约 481,411gas 且全部消耗gasUsed与gas相等顶层调用分得0x7dfa6、消耗0x7c1c8gas/gasUsed在源码中对应callFrame的Gas与GasUsed字段序列化时经gencodec转换为十六进制见 callFrameMarshalingtype字段由callFrame.Typevm.OpCode经TypeString()序列化为CALL/CREATE/STATICCALL等字符串。测试框架比对完 JSON 后还会做一道一致性校验顶层gasUsed必须与ApplyMessage返回的真实vmRet.UsedGas相等calltrace_test.go L161-L171保证用例数据与执行引擎始终同步。源码实现native callTracer 如何记录 error 与 revertReasoncallTracer 的 Go 原生实现位于 native/call.go在init()中注册进tracers.DefaultDirectoryL37-L39名称为callTracer。callFrame一次调用帧的完整记录每个调用帧用一个callFrame结构表示L51-L67type callFrame struct { Type vm.OpCode json:- From common.Address json:from Gas uint64 json:gas GasUsed uint64 json:gasUsed To *common.Address json:to,omitempty rlp:optional Input []byte json:input rlp:optional Output []byte json:output,omitempty rlp:optional Error string json:error,omitempty rlp:optional RevertReason string json:revertReason,omitempty Calls []callFrame json:calls,omitempty rlp:optional Logs []callLog json:logs,omitempty rlp:optional Value *big.Int json:value,omitempty rlp:optional revertedSnapshot bool }Error与RevertReason的分工是理解.md场景的关键Error是执行引擎给出的机器级失败状态如execution reverted、invalid opcode: INVALID而RevertReason是把revert(reason)的 ABI 编码输出解码后得到的人类可读原因字符串。revertedSnapshot标记该帧退出时快照是否真的被回滚failed()方法据此判断L73-L75。processOutputrevertReason 的生成条件revertReason不是无条件产出的其生成逻辑集中在processOutputL77-L103func (f *callFrame) processOutput(output []byte, err error, reverted bool) { output common.CopyBytes(output) // Clear error if tx wasnt reverted. ... if err ! nil !reverted { err nil } if err nil { f.Output output return } f.Error err.Error() f.revertedSnapshot reverted if f.Type vm.CREATE || f.Type vm.CREATE2 { f.To nil } if !errors.Is(err, vm.ErrExecutionReverted) || len(output) 0 { return } f.Output output if len(output) 4 { return } if unpacked, err : abi.UnpackRevert(output); err nil { f.RevertReason unpacked } }从源码结构看只有当该帧满足三个条件时才填充RevertReason错误必须是vm.ErrExecutionReverted、退出时携带的output非空且至少 4 字节ABI selector 最小长度、并且abi.UnpackRevert能成功按Error(string)编码解码出原因串。这就解释了为什么旧版inner_throw_outer_revert.json中只有error而没有revertReason内层是INVALID操作码失败输出根本无法按 revert 原因解码而require(2 3, This called failed)这类带原因的 revert 才会走到abi.UnpackRevert分支。另外注意 CREATE/CREATE2 帧失败时会把To置空L90-L92——因为部署失败意味着新地址上没有落任何代码。OnEnter/OnExit调用栈的维护追踪器通过 EVM 钩子维护调用栈callstack []callFrameOnEnterL159-L182在 EVM 进入新作用域CALL/CREATE/DELEGATECALL 等时压入一个帧depth 0的顶层帧把Gas记为交易的 gas limitt.gasLimit由OnTxStart从tx.Gas()得到OnExitL186-L210在作用域退出时弹出栈顶帧写入GasUsed并调用processOutput然后把该帧挂到父帧的Calls数组上形成嵌套结构。OnExit与processOutput在每一层独立执行因此每一层调用帧都各自携带自己的 error/output/revertReason——这正是.md中顶层与内层都要看到 revert reason这一要求的机制基础子帧不会吞掉父帧的失败信息父帧也不会被子帧覆盖。追踪器还支持两项配置callTracerConfigonlyTopCall为 true 时只记录顶层帧不收集子调用与withLog收集事件日志。.md场景属于全量嵌套模式即两项均为默认的 false。对照用例inner_revert_reason.json 中的现代预期行为同目录下的 inner_revert_reason.json 记录了.md场景在带 revert 原因机制下的完整期望形态一个部署交易的 input 字节码中内嵌了This called failed的 32 字节常量搜索7f546869732063616c6c6564206661696c6564即可定位到7f546869...00的 PUSH32 序列与.md中require(2 3, This called failed)的字符串逐字对应。其期望结果同时呈现了两层都有原因L51-L84{ error: execution reverted, revertReason: This called failed, calls: [ { type: CREATE, to: 0xd15abca351f79181dedfb6d019e382db90f3628a, ... }, { input: 0xc0406226, output: 0x08c379a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000012546869732063616c6c6564206661696c656400..., error: execution reverted, revertReason: This called failed, type: STATICCALL } ], type: CREATE }可以看到顶层 CREATE 帧与内层 STATICCALL 帧的revertReason都是This called failed且output保留了未解码的 ABI 编码字节selector0x08c379a0即Error(string)。这与inner_throw_outer_revert.json的只有 error、无 reason形成鲜明对照——两条用例合起来覆盖了嵌套失败的两个历史阶段REVERT 语义之前的 throwINVALID 操作码与之后的带原因 revert。revertReason字段同样存在于 ERC-7562 flat 追踪器的结构中见 native/erc7562.go L60说明错误状态 解码原因的双字段设计是 geth 追踪输出的一贯约定。运行与验证在本仓库中该用例由TestCallTracerNative自动覆盖只读环境下可直接运行验证不修改任何仓库文件# 运行全部 native callTracer 用例inner_throw_outer_revert 在内 go test -run TestCallTracerNative ./eth/tracers/internal/tracetest/ -v # 只跑这一个用例子测试名为文件名的驼峰形式见 util.go 的 camel 函数 go test -run TestCallTracerNative/innerThrowOuterRevert ./eth/tracers/internal/tracetest/ -v # 追踪器基准测试遍历 call_tracer 目录下所有 json go test -bench BenchmarkTracers ./eth/tracers/internal/tracetest/若用例数据与引擎行为不一致测试会输出trace mismatch / have / want的逐字节 JSON 对比calltrace_test.go L158-L160可直接定位是error、revertReason还是 gas 统计出现偏差。实战启示用 callTracer 诊断嵌套 revert把测试用例的机制映射到实际运维场景当一笔部署交易在链上失败时用debug_traceTransaction指定callTracer输出结构就是本文所述的嵌套callFrame。诊断嵌套 revert 时建议按顺序看三处每一层的error区分execution reverted语义回滚与invalid opcode: INVALID/gas 相关错误状态回滚判断失败发生在哪一层每一层的revertReason按.md场景的要求顶层与内层都会给出原因串直接对应 Solidity 中require/revert的文案可据此反查合约源码output原始字节当revertReason因编码不符而缺失时output仍保留了 ABI 编码输出可手工按0x08c379a0前缀解码。inner_throw_outer_revert这条用例的价值正在于它固化了这条诊断链路最棘手的分支——内层失败原因与外层回滚状态并存、且两层信息都必须在 trace 中完整可见——并为processOutput中ErrExecutionReverted、输出长度与abi.UnpackRevert的三重判定提供了可回归验证的基准数据。【免费下载链接】go-ethereumGo implementation of the Ethereum protocol项目地址: https://gitcode.com/gh_mirrors/go/go-ethereum创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

Markdown内嵌HTML实战:字体颜色、渲染器兼容与避坑

Markdown内嵌HTML实战:字体颜色、渲染器兼容与避坑

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 5:58:24 阅读更多 →
FineReport V11.0安装激活部署全流程详解与避坑指南

FineReport V11.0安装激活部署全流程详解与避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/21 4:51:04 阅读更多 →
MATLAB实现钢筋混凝土梁经济截面优化设计

MATLAB实现钢筋混凝土梁经济截面优化设计

简介:本资源是一份面向土木工程专业高年级本科生及结构设计工程师的MATLAB结构优化实践资料,聚焦钢筋混凝土简支梁的经济性与安全性协同优化问题。文档系统阐述了以材料费用最小化为目标的数学建模方法,明确设计变量(截面宽b、高h…

2026/9/21 1:43:42 阅读更多 →

最新新闻

企业网站做电脑营销避坑指南:选哪家好别只看价格,看这套设计规范

企业网站做电脑营销避坑指南:选哪家好别只看价格,看这套设计规范

企业网站做电脑营销避坑指南:选哪家好别只看价格,看这套设计规范 改个需求建站公司拖一周,这种憋屈事谁没经历过?很多老板找企业网站做电脑营销,问得最多的一句话就是“哪家好”。其实,网站好不好用,营销转不转化,核心不在你付了多少钱,而在前端代码写得够不够规范,设计逻辑是否支撑你的业务目标。…

2026/9/21 8:00:00 阅读更多 →
做品管圈网站哪家好?3步避开被黑挂马陷阱

做品管圈网站哪家好?3步避开被黑挂马陷阱

做品管圈网站哪家好?3步避开被黑挂马陷阱 网站上线三天,后台突然多了个奇怪的脚本,页面弹出一堆博彩广告,SEO排名一夜清零。如果你正面临这种“网站被黑挂马不知道怎么办”的噩梦,先别慌着删库重装。很多站长在找做品管圈网站哪家好时,只盯着价格和功能,却忽略了最底层的代码安全与架构选型。今天咱们不聊虚的,…

2026/9/21 7:44:43 阅读更多 →
Voyager 資料夾管理指南:為 Gemini 與 AI Studio 的 AI 對話打造真正的「檔案系統」

Voyager 資料夾管理指南:為 Gemini 與 AI Studio 的 AI 對話打造真正的「檔案系統」

AI 应用前端 【免费下载链接】voyager Enhancement suite for Gemini, AI Studio, Claude & ChatGPT — plus a prompt manager for any websites, DeepSeek Harness included. / 面向 Gemini、AI Studio、Claude 与 ChatGPT 的增强套件;其中的提示词管理器可用…

2026/9/21 7:41:44 阅读更多 →
gatsby-source-graphql 插件全解析:将任意第三方 GraphQL API 缝合进 Gatsby 数据层

gatsby-source-graphql 插件全解析:将任意第三方 GraphQL API 缝合进 Gatsby 数据层

前端静态站点Web框架 【免费下载链接】gatsby React-based framework with performance, scalability, and security built in. 项目地址: https://gitcode.com/gh_mirrors/ga/gatsby 点击查看 免费下载 本篇技术指南以 gatsby-source-graphql 插件的 CHANGELOG 版…

2026/9/21 7:41:44 阅读更多 →
Lightweight Charts v3 到 v4 迁移指南:破坏性变更逐项分析与实战改造方案

Lightweight Charts v3 到 v4 迁移指南:破坏性变更逐项分析与实战改造方案

Lightweight Charts v3 到 v4 迁移指南:破坏性变更逐项分析与实战改造方案 【免费下载链接】lightweight-charts Performant financial charts built with HTML5 canvas 项目地址: https://gitcode.com/gh_mirrors/li/lightweight-charts 本指南以 Lightweig…

2026/9/21 7:41:44 阅读更多 →
FoundationDB 存储基准测试上 RAM Disk:mako_storage_bench.sh 在 okteto 开发 Pod 上的 tmpfs 实践指南

FoundationDB 存储基准测试上 RAM Disk:mako_storage_bench.sh 在 okteto 开发 Pod 上的 tmpfs 实践指南

分布式数据库KV存储数据库后端 【免费下载链接】foundationdb FoundationDB - the open source, distributed, transactional key-value store 项目地址: https://gitcode.com/gh_mirrors/fo/foundationdb 点击查看 免费下载 mako_storage_bench.sh 是 FoundationD…

2026/9/21 7:41:44 阅读更多 →

日新闻

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程

agents-generator 决策矩阵全解析:从项目检测到 AGENTS.md 规则生成的 16 步判定流程 【免费下载链接】agentic-awesome-skills AAS Core is the local, agent-first control plane for complete catalog discovery, agent-owned selection, stack validation, and …

2026/9/21 0:00:01 阅读更多 →
gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析

gin-vue-admin 前端工具函数全景指南:src/utils 复用规范与源码级解析 【免费下载链接】gin-vue-admin 🚀ViteVue3Gin拥有AI辅助的基础开发平台,企业级业务AI开发解决方案,内置mcp辅助服务,内置skills管理,…

2026/9/21 0:00:01 阅读更多 →
Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

Wox 全功能插件开发实战指南:基于 Python / Node.js 宿主与 WebSocket 的持久化插件体系

桌面应用AI 应用插件系统 【免费下载链接】Wox A cross-platform launcher that simply works 项目地址: https://gitcode.com/gh_mirrors/wo/Wox 点击查看 免费下载 全功能插件(Full-featured Plugin)是 Wox 三类插件实现方式中能力最完整的…

2026/9/21 0:00:01 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/21 3:13:20 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/21 2:19:36 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/21 4:51:05 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/19 23:01:36 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/19 17:50:38 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/19 23:35:34 阅读更多 →