拓冰建站拓冰建站
首页 / 资讯中心 / 正文

Foundry Anvil 本地区块重放修复:应用协议预执行变更并透传准备错误(EIP-2935 / EIP-4788 追溯)

Foundry Anvil 本地区块重放修复应用协议预执行变更并透传准备错误EIP-2935 / EIP-4788 追溯【免费下载链接】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-replay-preexecution-errors.md记录的 Anvil patch 展开修复了本地区块重放local block replay不应用协议层预执行变更pre-execution changes、且不向 tracing RPC 返回准备错误preparation errors的问题。读完本文你将理解 Anvil 的trace_replayBlockTransactions等重放接口在 Prague/Cancun 硬分叉下为何必须模拟 EIP-2935 历史区块哈希与 EIP-4788 信标根的系统调用掌握重放准备阶段各条校验链的源码位置以及该修复如何通过集成测试 eip2935.rs 得到验证。一、背景为什么“本地区块重放”必须模拟预执行变更Anvil 支持通过 tracing RPC 重放本地挖出的区块。在以太坊主网共识中区块头里的协议字段parent_beacon_block_root、prevrandao等会在区块执行前通过系统级调用写入存储EIP-4788Cancun 起信标根被写入BEACON_ROOTS_ADDRESS0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02合约存储EIP-2935Prague 起父区块哈希被写入HISTORY_STORAGE_ADDRESS0x0000F90827F1C53a10cb7A02335B175320002935合约存储。如果重放时跳过这两类协议预执行变更那么依赖BLOCKHASH或信标根的系统合约重放结果就会与真实链上执行不一致。本次 patch 正是修复了本地区块重放不应用协议预执行变更的缺陷相关实现位于 executor.rs 的apply_pre_execution_changes。二、修复的核心apply_pre_execution_changes捕获变更集Anvil 的区块执行器AnvilBlockExecutorE实现了BlockExecutortrait其apply_pre_execution_changes方法见 executor.rs负责在每条交易执行前应用协议层变更fn apply_pre_execution_changes(mut self) - Result(), BlockExecutionError { if let Some(transitions) self.ethereum_transitions { // Historical fork-prefix publication needs the individual changesets after executing // against its disposable overlay. Preserve canonical ordering while capturing them. if let Some(state_changes) mut self.state_changes { if transitions.hardfork EthereumHardfork::Prague { // EIP-2935: 将 parent_hash 写入 HISTORY_STORAGE_ADDRESS let result self.evm.transact_system_call( eip4788::SYSTEM_ADDRESS, eip2935::HISTORY_STORAGE_ADDRESS, Bytes::copy_from_slice(self.parent_hash.as_slice()), )...; state_changes.push(result.state.clone()); self.evm.db_mut().commit(result.state); } if transitions.hardfork EthereumHardfork::Cancun { // EIP-4788: 将 parent_beacon_block_root 写入 BEACON_ROOTS_ADDRESS let result self.evm.transact_system_call( eip4788::SYSTEM_ADDRESS, eip4788::BEACON_ROOTS_ADDRESS, Bytes::copy_from_slice(parent_beacon_block_root.as_slice()), )...; state_changes.push(result.state.clone()); self.evm.db_mut().commit(result.state); } return Ok(()); } apply_ethereum_pre_execution_changes(mut self.evm, self.parent_hash, transitions)?; } Ok(()) }从代码可以推断该方法的两个执行路径分别服务于不同场景常规路径apply_ethereum_pre_execution_changesexecutor.rs通过SystemCaller按共识顺序调用apply_blockhashes_contract_call与apply_beacon_root_contract_call变更直接提交到当前数据库重放/追溯路径当state_changes被捕获时逐条transact_system_call并把result.state单独压入state_changes再提交。从注释可知这是为了historical fork-prefix publication需要独立的 changeset——patch 前重放过程直接沿用了前者导致预执行变更没有被应用到重放数据库且错误没有通过 tracing RPC 返回。修复后的关键点在于重放执行通过execute_historical_replay系列函数对每条交易使用execute_transaction_without_commit_withcommit_transaction见 replay.rs而预执行变更现在通过apply_pre_execution_changes被正确捕获并提交到重放使用的AnvilCacheDBoverlay 上。三、重放的完整链路从交易哈希 fork 到 tracing RPC3.1 交易哈希 fork 的准备prepare_fork_transaction_replayAnvil 既支持按区块号 fork也支持按交易哈希forkForkChoice::Transaction见 config.rs。此时会先取交易所在区块内目标交易之前含目标交易的全部交易作为前缀派生逻辑在derive_block_and_replayconfig.rs严格校验在validate_fork_transaction_replayconfig.rs中完成包括交易报告的blockHash/blockNumber与拉取的区块一致交易确实存在于该区块且仅出现一次目标交易不能位于创世区块没有父区块可回放。prepare_fork_transaction_replayreplay.rs随后做类型转换与签名恢复每条源交易转换为FoundryTxEnvelope并断言哈希不变recover_signer恢复发送方Monad 特性下允许信任协议系统发送方每条交易携带source_index用于在诊断信息中定位其在源区块中的位置。一个值得注意的细节Anvil 无法执行的交易类型会被跳过。例如 Arbitrum 每个区块开头的ArbitrumInternalTxtype0x6a没有 EVM 语义若它只是前缀中的一条则跳过并sh_warn!警告但若它就是目标交易整个重放直接报错因为那样得到的 fork 状态不是调用方所要求的。该行为有对应单元测试 replay.rsskips_unsupported_prefix_transactions与rejects_unsupported_target_transaction。3.2 重放执行与变更集捕获apply_fork_transaction_replay准备工作完成后apply_fork_transaction_replaymem/mod.rs接管执行校验重放前缀非空解析执行链 IDexecution_chain_id会校验前缀内所有交易的 chainId 一致见 replay.rs在AnvilCacheDBoverlay 上构造重放环境replay_env以源区块的timestamp为块时间戳推算prevrandao设置parent_beacon_block_root按源链与时间戳确定硬分叉FoundryHardfork::from_chain_and_timestamp调用execute_with_replay_block_executor在 overlay 上执行得到ExecutedHistoricalReplay { block_result, transactions, transaction_infos, state_changes }计算出state_root后将重放结果作为新块写入供trace_replayBlockTransactions等 tracing RPC 使用。正是在第 3 步中apply_pre_execution_changes的捕获变更集分支被触发把 EIP-2935 / EIP-4788 系统调用的状态变更与普通交易的变更区分开保证 state diff 追溯结果与真实链上一致。3.3 追溯错误透传patch 的另一半变更日志的第二句是return preparation errors through tracing RPCs。patch 之前如果预执行阶段如 EIP-2935 历史存储合约调用出错错误往往在内部被吞掉或未正确映射为 JSON-RPC 错误。修复后重放准备/执行阶段的错误通过BlockExecutionError传播最终以 JSON-RPC 错误code-32603返回给调用方而不是返回空结果或静默失败。四、集成测试如何验证修复补丁配套的集成测试位于 eip2935.rs正好对应变更日志的两个方面4.1eip2935_local_block_replay_applies_pre_execution_changes测试流程eip2935.rs以 Prague 硬分叉启动节点部署一个探针合约转发 calldata 到 EIP-2935 历史存储合约地址0x0000...2935仅当返回的父哈希非零时将其写入自己的 slot 0关闭自动挖矿发送一笔把父区块号作为 calldata 的交易并手动mine_one调用trace_replayBlockTransactions(block_number, [StateDiff])重放该区块断言重放结果的 state diff 中探针合约 slot 0 从零变为父区块哈希——这只有在重放时正确执行了 EIP-2935 预执行变更把父哈希写入历史存储合约才能成立同时验证trace_blockOpcodeGas中出现了SSTORE操作码。若 patch 未生效重放时历史存储合约中不存在父哈希探针合约将返回 0 而不写槽位测试必然失败。4.2eip2935_local_block_replay_propagates_pre_execution_errors该测试使用一个会失败的预编译工厂FailingHistoryPrecompile在重放前开启故障标志然后依次调用五种 tracing 接口eip2935.rstrace_replayBlockTransactionstrace_replayTransactiontrace_transactionOpcodeGastrace_blockOpcodeGas目标区块与空区块两种测试断言所有这些调用都返回 code 为-32603的 JSON-RPC 错误且错误消息包含哨兵字符串REPLAY_PRE_EXECUTION_ERROR定义于 eip2935.rs。同时还验证创世区块的trace_blockOpcodeGas返回空交易列表、节点最新块高度不受失败重放影响。这组断言直接证明了准备错误通过 tracing RPC 返回这一修复目标。五、与其他重放路径的关系本次修复针对的是本地区块重放local block replay与交易哈希 fork 前缀重放共享同一套预执行变更逻辑重放场景入口预执行变更路径本地区块 tracing 重放trace_replayBlockTransactions等apply_pre_execution_changes捕获 changeset 分支交易哈希 fork 前缀重放ForkChoice::Transaction同上经execute_with_replay_block_executor常规出块mine_blockapply_ethereum_pre_execution_changes直接提交从 mem/mod.rs 可以看到execute_historical_replay同样被 fork 前缀重放使用而 monad.rs 通过execute_historical_replay_with传入 Monad 特有的交易入口点。这些路径统一受益于本补丁对预执行变更的正确应用。六、实操验证建议在本地源码环境复现本补丁行为可参考以下步骤阅读变更记录.changelog/anvil-replay-preexecution-errors.md确认补丁类型为anvil: patch运行相关集成测试验证修复行为cargo test -p anvil --test it eip2935 -- --nocapture其中eip2935_local_block_replay_applies_pre_execution_changes与eip2935_local_block_replay_propagates_pre_execution_errors分别覆盖应用变更与错误透传两个修复面结合 replay.rs 的单元测试skips_unsupported_prefix_transactions、rejects_unsupported_target_transaction理解重放前缀的过滤与校验规则若你正在维护基于 Anvil 的本地开发/审计工具建议针对trace_replayBlockTransactions的 state diff 结果与真实链上状态做对照确保 Prague/Cancun 合约依赖BLOCKHASH或信标根的系统合约在重放语义下行为一致。七、小结本次 Anvil patch 从两个方面修正了本地区块重放应用协议预执行变更重放时以捕获 changeset 的方式执行 EIP-2935Prague 历史区块哈希与 EIP-4788Cancun 信标根系统调用保证 state diff 与链上真实执行一致透传准备错误预执行阶段失败时错误以 JSON-RPC 错误-32603形式返回给所有相关 tracing RPC而不是静默失败。核心实现位于 executor.rsapply_pre_execution_changes与 replay.rs重放准备与执行配套测试位于 eip2935.rs是理解 Anvil 追溯语义与硬分叉兼容性的重要参考。【免费下载链接】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),仅供参考
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门