
Foundry Anvil 修复debug_traceTransaction对未知交易哈希返回成功空 Trace 的问题【免费下载链接】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/anvil-unknown-transaction-trace.md 记录的anvil: patch变更展开剖析 AnvilFoundry 自带的本地以太坊节点如何修复debug_traceTransaction在收到未知交易哈希时错误返回成功空 trace的问题。读完本文你将理解该 RPC 的完整调用链与错误处理机制掌握修复后客户端应当期望的-32001 transaction not found行为并学会通过cast、curl和仓库内测试用例自行验证这一修复。一、变更背景一个会让客户端误判的静默 bugdebug_traceTransaction是 Geth 调试命名空间debug_中的核心 RPC用于返回指定交易哈希对应的 EVM 执行追踪结果是调试合约调用、分析 gas 消耗和审计状态变更的关键手段。Anvil 作为与 Geth 高度兼容的本地开发节点长期支持该接口。本变更记录的问题在于当客户端传入一个未知从未被打包/挖掘过的交易哈希时Anvil 此前会返回一个成功的空 trace例如空的默认 structlog frame 或NoopFrame而不是明确的错误响应。这会造成两类严重误导客户端与工具无法区分交易存在但 trace 为空与交易根本不存在上层自动化流程可能据此认为交易已成功执行从而产生错误的后续判断。修复目标很明确对未知交易哈希返回标准错误而不是伪造一份成功 trace。二、修复后行为返回-32001 transaction not found修复后Anvil 对未知交易哈希统一返回带错误码-32001、错误消息为transaction not found的 RPC 错误响应。该行为由仓库内的集成测试直接锁定crates/anvil/tests/it/traces.rs 中的test_debug_trace_transaction_rejects_unknown_hash测试用例#[tokio::test(flavor multi_thread)] async fn test_debug_trace_transaction_rejects_unknown_hash() { let (_api, handle) spawn(NodeConfig::test()).await; let error handle .http_provider() .debug_trace_transaction(B256::ZERO, GethDebugTracingOptions::default()) .await .unwrap_err(); let error error.as_error_resp().unwrap(); assert_eq!(error.code, -32001); assert_eq!(error.message, transaction not found); }测试使用全零哈希B256::ZERO作为必然不存在的交易哈希断言响应错误码为-32001且消息为transaction not found。这一测试既是对本次修复的回归保护也给出了客户端开发者的期望契约。三、源码级剖析未知哈希是如何被识别的3.1 RPC 入口API Handlerdebug_traceTransaction的 RPC 入口位于 crates/anvil/src/eth/api.rsEthApi层的 handler 只负责记录node_info!(debug_traceTransaction)日志并转发给 backend/// Returns traces for the transaction hash for geths tracing endpoint /// /// Handler for RPC call: debug_traceTransaction pub async fn debug_trace_transaction( self, tx_hash: B256, opts: GethDebugTracingOptions, ) - ResultGethTrace { node_info!(debug_traceTransaction); self.backend.debug_trace_transaction(tx_hash, opts).await }3.2 核心逻辑三层查找与显式报错真正的判断逻辑位于内存后端 crates/anvil/src/eth/backend/mem/mod.rspub async fn debug_trace_transaction( self, hash: B256, opts: GethDebugTracingOptions, ) - ResultGethTrace, BlockchainError { #[cfg(feature js-tracer)] if let Some(tracer_type) opts.tracer.as_ref() tracer_type.is_js() { return self .trace_tx_with_js_tracer(hash, tracer_type.as_str().to_string(), opts.clone()) .await; } if let Some(trace) self.mined_geth_trace_transaction(hash, opts.clone()).await { return trace; } if let Some(fork) self.get_fork() { return Ok(fork.debug_trace_transaction(hash, opts).await?); } Err(BlockchainError::TransactionNotFound) }该函数呈现清晰的优先级链路JS tracer 短路若请求携带 JavaScript 自定义 tracer则直接走trace_tx_with_js_tracer本地已打包交易调用mined_geth_trace_transaction在区块链存储中按哈希查找交易见 crates/anvil/src/eth/backend/mem/mod.rs其实现为self.blockchain.storage.read().transactions.get(hash)——只有哈希命中本地存储才会生成 traceFork 模式兜底本地未命中时若 Anvil 以 fork 模式运行则转发给远端 provider见 crates/anvil/src/eth/backend/fork.rs其中还包含按(hash, opts)维度缓存 trace 的逻辑显式报错以上全部未命中时返回BlockchainError::TransactionNotFound。从源码结构可以推断此前的 bug 正是出在本地未命中这一分支的处理上修复前该路径可能落入某个返回默认空 frame 的分支从而向客户端返回了看似成功的空 trace修复后则以TransactionNotFound错误终结杜绝了误判空间。3.3 错误码映射-32001 从何而来BlockchainError::TransactionNotFound到 JSON-RPC 错误码的映射位于 crates/anvil/src/eth/error/mod.rserr BlockchainError::TransactionNotFound RpcError { // https://eips.ethereum.org/EIPS/eip-1898 code: ErrorCode::ServerError(-32001), message: err.to_string().into(), data: None, },可见-32001ServerError区间的保留码与 EIP-1898 中block/transaction not found的语义一致与transaction not found消息由统一的错误转换逻辑保证与BlockNotFound使用同一错误码区间行为与 Geth 保持兼容。3.4 附带影响debug_traceBlock系列值得注意的连带收益debug_trace_block_by_hash见 crates/anvil/src/eth/backend/mem/mod.rs会逐笔调用debug_trace_transaction并将失败结果包装为TraceResult::Error。因此本次修复同样让debug_traceBlock在遇到内部缺失交易时能够如实返回错误条目而不是产出伪造的空 trace保证了块级追踪结果的真实性。四、手动验证如何在本地复现与确认4.1 启动 Anvilanvil默认监听http://127.0.0.1:8545使用自带 10 个 dev 钱包账户。4.2 用 curl 直接验证错误响应向debug_traceTransaction传入一个必然不存在的哈希如全零curl -X POST http://127.0.0.1:8545 \ -H Content-Type: application/json \ --data { jsonrpc: 2.0, id: 1, method: debug_traceTransaction, params: [ 0x0000000000000000000000000000000000000000000000000000000000000000, {tracer: callTracer} ] }修复后的预期响应为错误对象{ jsonrpc: 2.0, id: 1, error: { code: -32001, message: transaction not found } }对比修复前会得到result为空的成功响应客户端可以通过error字段是否存在来区分两种语义。4.3 用 cast 发送真实交易后再追踪先部署一笔真实交易再对其哈希进行追踪确认正常路径不受影响# 向 dev 账户转账 cast send --private-key 0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80 \ --rpc-url http://127.0.0.1:8545 \ 0x70997970C51812dc3A010C7d01b50e0d17dc79C8 \ --value 1ether # 输出中的 transactionHash 即为 tx_hash然后 cast run transactionHash --rpc-url http://127.0.0.1:8545cast run内部即通过debug_traceTransaction获取 trace相关实现见 crates/cast/src/rpc_trace.rs是验证该 RPC 行为最贴近日常使用的途径。五、对开发者与工具链的实践意义客户端必须处理错误而非空结果依赖debug_traceTransaction的工具调试器、区块浏览器、CI 回归脚本应把-32001视为交易不存在的明确信号而不是把空 trace 当作合法结果。回归测试范式可复用仓库中test_debug_trace_transaction_rejects_unknown_hash用全零哈希作为未知交易的代表这一手法可推广到其他查不到就应报错的 RPC 测试中。行为契约与 Geth 对齐-32001与transaction not found的组合与 Geth 系节点的既有语义一致使得基于该 RPC 的跨节点工具无需为 Anvil 编写特殊分支。六、相关变更与延伸阅读变更记录本体.changelog/anvil-unknown-transaction-trace.md.changelog/目录以 front matter 标记 crate 名与版本类型anvil: patch表示该修复随 Anvil 的下一个 patch 版本发布RPC 入口与 handlercrates/anvil/src/eth/api.rs内存后端核心逻辑crates/anvil/src/eth/backend/mem/mod.rsFork 模式转发与缓存crates/anvil/src/eth/backend/fork.rs错误码映射crates/anvil/src/eth/error/mod.rs回归测试crates/anvil/tests/it/traces.rsdebug_命名空间相关追踪测试含 fork 场景crates/anvil/tests/it/fork.rs 与 crates/anvil/tests/it/traces.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),仅供参考