Foundry 新特性详解:`cast call` 输出解码后的 Revert 数据(Decoded Revert Data)

发布时间:2026/9/16 1:10:48
Foundry 新特性详解:`cast call` 输出解码后的 Revert 数据(Decoded Revert Data) Foundry 新特性详解cast call输出解码后的 Revert 数据Decoded Revert Data【免费下载链接】foundryFoundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.项目地址: https://gitcode.com/GitHub_Trending/fo/foundry导读本文围绕 Foundry 仓库 changelog 记录 cast-call-decode-reverts.md 中的一项 patch 级新特性展开当cast call发起的调用因目标合约 revert 而失败时只要错误签名已知CLI 就会在错误输出中直接解码并展示 revert 数据而不再只是抛出一段难读的原始十六进制。读完本文你将掌握该特性的使用场景、错误输出的两种形态已知签名解码 / 在线签名识别、底层解码链路RevertDecoder 与签名缓存以及如何用测试用例验证这一行为。变更说明.changelog/cast-call-decode-reverts.md原文仅一句话——Decoded revert data incast callerror output when the error signature is known.当错误签名已知时在cast call错误输出中解码 revert 数据归类为cast: patch补丁级变更不破坏现有命令行接口。本文以该行为主骨架结合仓库源码与测试展开。一、特性背景为什么需要解码 revert 数据cast call本质上是对目标合约执行一次eth_call模拟调用见 crates/cast/src/cmd/call.rs 中run_with_network_and_opts的 provider 调用逻辑。当合约执行revert(...)或抛出自定义错误custom error时RPC 节点返回的错误响应里携带一段 ABI 编码的 revert dataSolidity 内置的Error(string)编码为0x08c379a0 字符串的 ABI 编码内置Panic(uint256)编码为0x4e487b71 uint256 码值自定义错误如RequestLimitExceeded(uint256,uint256)编码为其 4 字节选择器 参数的 ABI 编码。在没有解码能力之前cast call只能把这段原始字节原样打印用户必须自己用cast decode之类的工具二次处理才能看懂合约到底因为什么原因回滚。本特性正是为了消除这个心智负担在错误输出阶段直接给出人可读的 revert 原因。二、核心实现错误输出中的解码逻辑2.1 捕获 revert data 的入口在 crates/cast/src/cmd/call.rs 的 provider 调用错误分支中let res match call.await { Ok(res) res, Err(err) { let data err.as_error_resp().and_then(|payload| payload.as_revert_data()); if let Some(data) data { let decoded match RevertDecoder::new().maybe_decode_known(data) { Some(decoded) Some(decoded), None crate::tx::decode_custom_error(data).await.ok().flatten(), }; if let Some(decoded) decoded { return Err(err).wrap_err(format!(execution reverted: {decoded})); } } return Err(err.into()); } };关键点拆解提取 revert dataerr.as_error_resp().and_then(|payload| payload.as_revert_data())从 JSON-RPC 错误响应中取出data字段对应的字节序列两级解码策略先尝试用RevertDecoder::new().maybe_decode_known(data)做本地已知签名解码失败后再调用crate::tx::decode_custom_error(data)走在线签名识别见下文第三节错误包装一旦解码成功就用execution reverted: {decoded}作为错误上下文信息包裹原始错误用户最终在 stderr 中看到的就是可读的失败原因。这正好呼应 changelog 中 when the error signature is known 的前提本地解码与在线识别两条路径共同决定签名是否已知。2.2 本地解码核心RevertDecoderRevertDecoder定义在 crates/evm/core/src/decode.rs是 Foundry EVM 核心中通用的 revert 解码工具。它的核心方法是maybe_decode_knowndecode.rs按优先级依次尝试SolidityError(string)通过RevertReason::decode(err)匹配0x08c379a0前缀成功则直接返回字符串内容剥离revert:前缀SolidityPanic(uint256)与Vm的 cheatcode 错误通过ContractError::Vm::VmErrors::abi_decode(err)统一解码自定义错误取前 4 字节作为选择器在内部errors: HashMapSelector, VecError索引中查找命中后用error.abi_decode_input(data)解码参数输出为ErrorName(arg1, arg2, ...)形式。注意maybe_decode_known与maybe_decodedecode.rs的区别后者在已知签名失败后还会回退到非空字符串解码和泛化自定义错误表示如custom error 0xXXXX: data而前者只返回已知签名的解码结果这正是cast call想要的语义——签名未知就不妄加猜测留给在线识别路径处理。RevertDecoder也提供了with_abis/with_abi/push_error方法可把项目的JsonAbi中的自定义错误批量注册进索引方便复用同一套解码逻辑例如 forge 测试结果解码。2.3 在线识别兜底decode_custom_error当本地maybe_decode_known返回None时cast call会调用 crates/cast/src/tx.rs 中的decode_custom_errorpub(crate) async fn decode_custom_error(data: [u8]) - ResultOptionString { let Some(selector) data.get(..4) else { return Ok(None) }; let Some(known_error) SignaturesIdentifier::new(false)?.identify_error(selector.try_into().unwrap()).await else { return Ok(None); }; let mut decoded_error known_error.name.clone(); if !known_error.inputs.is_empty() let Ok(error) known_error.decode_error(data) { write!(decoded_error, ({}), format_tokens(error.body).format(, ))?; } Ok(Some(decoded_error)) }它的工作方式是取 revert data 的前 4 字节选择器交给SignaturesIdentifier签名识别器来自 foundry-common 的选择器解析基础设施从本地签名缓存中识别错误签名识别到后再用该签名解码参数并格式化为Name(arg1, arg2)。从源码看SignaturesIdentifier::new(false)的布尔参数控制是否强制联网——这也是为什么测试中设置FOUNDRY_OFFLINEtrue依然能离线解码见第四节。三、签名从哪来本地缓存与识别链特性标题里的 when the error signature is known 对应的签名来源有两处本地 ABI 注册RevertDecoder可以通过with_abis批量注入合约 ABI 中的错误定义但cast call的默认路径使用RevertDecoder::new()空解码器此时内置只认识 Solidity 标准错误Error(string)、Panic(uint256)和Vmcheatcode 错误签名缓存signature cachedecode_custom_error依赖SignaturesIdentifier读取用户主目录下的.foundry/cache/signatures缓存文件缓存中记录了选择器 → 签名的映射既有函数也有错误。这正是 crates/cast/tests/cli/call.rs 测试里预先写入缓存、再离线验证解码的原因。从源码结构可以推断该特性优先保证离线、确定性只要签名缓存里已有该选择器对应的错误签名即使 RPC 不可达FOUNDRY_OFFLINEtrue也能完成解码。四、验证行为测试用例如何证明该特性仓库中的集成测试 crates/cast/tests/cli/call.rs 完整覆盖了这一特性测试cast_call_decodes_custom_error的核心步骤启动 anvil 测试节点构造自定义错误RequestLimitExceeded(uint256,uint256)取其 4 字节选择器ABI 编码参数(5, 3)拼出 revert payload手工生成一段运行时代码把该 payload 拷入内存后revert0xfd并通过--override-code把它覆盖到目标地址上预置签名缓存在$HOME/.foundry/cache/signatures中写入{errors: {selector: RequestLimitExceeded(uint256,uint256)}}并设置HOME环境变量隔离缓存目录以FOUNDRY_OFFLINEtrue离线执行cast call addr --data 0x --override-code ... --rpc-url ...断言命令失败且 stderr 输出Error: execution reverted: RequestLimitExceeded(5, 3)该测试同时验证了普通终端输出非 JSON 模式与--json模式错误信息进入errors数组消息为execution reverted: RequestLimitExceeded(5, 3)并带cast.error.context上下文两种呈现形态说明特性对两种输出通道都生效。五、使用场景与输出对比5.1 特性生效的典型场景调用只读函数如balanceOf时目标合约因业务逻辑revert之前只能看到execution reverted, data: 0x08c379a0...这样的原始串合约抛出自定义错误如RequestLimitExceeded(5, 3)且签名已被 Foundry 缓存或能通过签名识别获得时错误信息直接可读配合--rpc-url、--block、--from等常规参数使用不影响cast call原有的所有调用能力见 CallArgs 定义。5.2 修复前后的输出对比示意修复前仅原始数据Error: server returned an error response: error code 3: execution reverted, data: 0x08c379a0...5472616e73616374696f6e20746f6f206f6c64修复后签名已知时Error: execution reverted: Transaction too old对于自定义错误Error: execution reverted: RequestLimitExceeded(5, 3)上述第二个示例的输出文本直接取自仓库测试断言 crates/cast/tests/cli/call.rs第一个示例的十六进制片段为receipt测试中出现的典型Error(string)编码形态此处仅作格式示意。六、边界与限制签名已知是前提若maybe_decode_known与decode_custom_error都识别失败错误仍会以原始 revert data 形式呈现return Err(err.into())不会强行猜测Error(string)/Panic(uint256)始终可解码这两类 Solidity 内置错误不需要任何签名缓存属于签名必然已知的情况依赖签名缓存目录自定义错误的在线识别依赖.foundry/cache/signatures首次使用而未缓存时可能需要联网获取签名SignaturesIdentifier负责该逻辑测试中通过预置缓存并设置FOUNDRY_OFFLINE保证了离线确定性适用范围本特性作用于cast call的eth_call错误路径--trace/--debug-trace-call走的是 trace 渲染路径call.rsrevert 的呈现方式由handle_traces负责不在本次变更范围内。七、总结.changelog/cast-call-decode-reverts.md记录的这一 patch 级特性为cast call的日常排障体验补上了关键一环错误签名已知时revert 原因直接以可读文本输出。实现上它复用了 EVM 核心的RevertDecoder内置标准错误解码与 cast 自身的签名识别器缓存 在线兜底并由cast_call_decodes_custom_error集成测试锁定行为。对于脚本化调用合约、CI 排障或日常合约交互这个改动让cast call的失败信息从需要二次解码的十六进制变成了一眼可懂的错误原因。相关代码与文档索引变更记录.changelog/cast-call-decode-reverts.mdcast call命令实现crates/cast/src/cmd/call.rsrevert 解码核心RevertDecoder/maybe_decode_knowncrates/evm/core/src/decode.rs在线签名识别兜底decode_custom_errorcrates/cast/src/tx.rs集成测试离线解码自定义错误crates/cast/tests/cli/call.rs【免费下载链接】foundryFoundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.项目地址: https://gitcode.com/GitHub_Trending/fo/foundry创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询