
Foundry 全面支持 MonadTen 硬分叉MIP-8 基于页面的存储 Gas 与 Access-List 生成实战解析【免费下载链接】foundryFoundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.项目地址: https://gitcode.com/GitHub_Trending/fo/foundryMonadTen 是 Monad 区块链的默认硬分叉其核心是 MIP-8 提案引入的基于页面的存储 Gas 计费与页面感知的 Access-List 生成并配套主网与测试网的时间戳激活机制。本指南基于 Foundry 仓库中的 版本变更记录结合foundry-evm-hardforks、anvil与forge的源码与测试讲解 MonadTen 在 Foundry 中的实现原理、如何启用、如何验证 MIP-8 生效以及它对 Gas 估算、交易 Access-List 和硬分叉时间戳推断的影响。一、MonadTen 在 Foundry 中的定位Foundry 将 Monad 作为与 Ethereum、Optimism、Tempo 并列的独立执行族。在 硬分叉定义 中FoundryHardfork枚举包含Monad(MonadHardfork)变体MonadHardfork由monad_revm依赖提供定义了MonadEight、MonadNine、MonadTen、MonadNext等系列分叉。MonadTen 被设为 Monad 网络的默认硬分叉体现在两个层面默认值NodeConfig::test_monad()默认即启用MonadHardfork::MonadTen无需显式指定见 anvil Monad 集成测试 中monad_ten_applies_mip8_storage_gas的第二组用例。Spec 映射SpecId::from(FoundryHardfork::Monad(MonadHardfork::MonadTen))映射到SpecId::OSAKA对应以太坊侧 Osaka 基准见 硬分叉测试。二、MIP-8 基于页面的存储 Gas 计费2.1 机制概述MIP-8 将 Monad 的存储槽位按**页page**分组计价首次访问某一页内的任意存储槽会为该页支付一次性冷页费用同一页内的后续访问包括冷热槽不再重复计费。相比 Ethereum 按单个槽位计费的方式MIP-8 更适合 Monad 面向并行执行的存储布局。2.2 源码中的计价参数页面计价的量化参数可以在 anvil Monad 集成测试 的monad_ten_applies_mip8_storage_gas中找到配置跨页读取增量跨页写入增量MonadNineMIP-8 未启用00MonadTen默认8,00010,800测试通过anvil_setCode分别部署访问槽位 127 与槽位 128 的探针合约用eth_call测量两次调用的 Gas 差。由于槽位 127 与 128 落在不同页面差值即跨页费用。可以推断 MIP-8 页面按每 128 个存储槽位划分0–127 为第 1 页128 起为第 2 页。更进一步的验证来自 forge 测试 的assertMip8Activefunction assertMip8Active() internal { assertEq(storageReadGas(128) - storageReadGas(127), 8_000, MIP-8 page read cost); assertEq(storageWriteGas(128) - storageWriteGas(1), 10_800, MIP-8 page write cost); } function assertMip8Inactive() internal { assertEq(storageReadGas(128), storageReadGas(127), legacy slot read cost); assertEq(storageWriteGas(128), storageWriteGas(1), legacy slot write cost); }即MonadTen 下首次触碰新页读取多付 8,000 Gas、写入多付 10,800 Gas而在 MonadEight/MonadNine 下跨页与同页费用相同。2.3 对 RPC 估算与追踪的影响MIP-8 不仅作用于区块执行也贯穿eth_estimateGas、eth_createAccessList与trace_call。测试monad_ten_rpc_simulations_apply_mip8_storage_gasanvil 集成测试验证了estimate_gas对跨页读取/写入的增量与 MIP-8 一致8,000 / 10,800trace_call返回的根调用 Gas 同样反映 MIP-8 计费。这意味着用户在模拟交易、估算 Gas 时无需手工补偿Anvil 的 RPC 结果即为 MonadTen 真实链上行为。三、页面感知的 Access-List 生成MIP-8 的另一半是page-aware access-list generation生成 Access-List 时不再按单个槽位去重而是按页去重最终只列出每页的代表性存储键。在 anvil 后端实现 中normalize_access_list在MonadTen.is_enabled_in(hardfork)时pub(super) fn normalize_access_list( mut access_list: AccessList, hardfork: MonadHardfork, ) - AccessList { if MonadHardfork::MonadTen.is_enabled_in(hardfork) { for item in mut access_list.0 { item.storage_keys.sort_unstable(); item.storage_keys.dedup_by_key(|slot| { monad_revm::page::page_index(U256::from_be_slice(slot.as_slice())) }); } } access_list }逻辑是先对每个地址的 storage keys 排序再以page_index为去重键保证同一页只保留一个存储键。MonadNine 及更早版本不执行该规范化。测试monad_ten_deduplicates_access_list_storage_pagesanvil 集成测试给出了具体对照访问的槽位MonadNine 返回的 keysMonadTen 返回的 keysMonadTen Gas 增量槽位 1、2同页[1, 2][1]去重0槽位 1、129跨页[1, 129][1, 129]1,900同页的槽位 1、2 被折叠成一个 key跨页访问则两个 key 都保留但相比未开启 MIP-8 的情况会额外产生约 1,900 Gas 的页费用差。四、主网与测试网的时间戳激活MonadTen 的激活不是区块号驱动的而是按时间戳生效。Foundry 通过MonadHardfork::mainnet_activation_timestamp()与MonadHardfork::testnet_activation_timestamp()获取激活时刻再在链 ID 时间戳双维度上解析硬分叉。4.1 时间戳推断的实现在 硬分叉解析 中FoundryHardfork::from_chain_and_timestamp会依次尝试 Ethereum、Optimism、Tempo、Monad 各族的链 时间戳推断Monad 分支最终由MonadHardfork::from_chain_and_timestamp(chain_id, timestamp)决定。测试test_monad_hardfork_from_chain_and_timestamp硬分叉测试验证了边界行为主网在mainnet_ten之前解析为MonadNine到达mainnet_ten之后解析为MonadTen测试网同理在testnet_ten前后分别解析为MonadNine与MonadTen测试使用mainnet_ten - 1/mainnet_ten作为临界点断言确保开区间/闭区间语义正确。4.2 执行环境的动态解析在 evm 核心选项测试 中resolve_execution_spec_uses_monad_ten_activation_timestamp验证了fork 模式下即使evm_version/hardfork未显式配置执行环境也会根据块时间戳自动在MonadNine与MonadTen之间切换并同步更新cfg_env.spec。同时anvil fork replay 逻辑 表明显式指定的 hardfork 优先级最高未指定时回放历史交易会依据source_chain_id timestamp推断目标块的硬分叉并把推断结果写回节点配置inferred_hardfork时持久化保证后续区块延续同一分叉。4.3 Fork 场景的时间戳测试forge 测试 的fork_resolves_monad_hardfork_from_timestamp直接验证了端到端行为用--fork-url指向时间戳位于MonadNine激活前的 Anvil 实例forge test --network monad时evm.getEvmVersion()返回monadeight切换链上时间戳后分别得到monadnine与monadten。五、在 Foundry / Anvil 中启用与验证 MonadTen5.1 通过配置或命令显式指定MonadTen 是默认分叉但也可以显式指定FoundryHardfork支持network:hardfork命名空间语法见 硬分叉定义命令行anvil --hardfork monad:MonadTen等价写法m:MonadTen名字大小写不敏感-/空格归一化为_Solidity 测试内vm.setEvmVersion(monad:MonadTen)随后vm.getEvmVersion()返回monadten见 forge 测试Foundry 配置在foundry.toml中通过evm_version monad:MonadTen或hardfork相关字段设置由foundry-config的 hardfork 解析统一处理。5.2 运行时断言 MIP-8 生效可以在测试中用探针合约断言跨页费用// 在 MonadTen 下跨页读多 8,000 Gas跨页写多 10,800 Gas assertEq(storageReadGas(128) - storageReadGas(127), 8_000); assertEq(storageWriteGas(128) - storageWriteGas(1), 10_800);anvil集成测试则通过eth_createAccessList断言同页去重、通过eth_estimateGas/trace_call断言 Gas 数值方法与上文 2.3、3 节一致。5.3 时间戳相关的注意事项MonadTen 激活按时间戳而非区块号判定fork 场景下务必保证--fork-url节点的最新区块时间戳覆盖目标激活时刻本地非 fork执行环境不会按链上时间表自动切换分叉见resolve_execution_spec_ignores_schedule_for_local_envevm 核心选项测试本地测试的evm_version需显式给出anvil默认NodeConfig::test_monad()即 MonadTen若需模拟升级前后行为可用with_hardfork(Some(MonadHardfork::MonadNine.into()))显式回到旧分叉。六、相关源码与测试索引硬分叉枚举与时间戳解析crates/evm/hardforks/src/lib.rsMonad 执行环境与 Access-List 规范化crates/anvil/src/eth/backend/mem/monad.rsMIP-8 Gas / Access-List / RPC 模拟集成测试crates/anvil/tests/it/monad.rsvm.setEvmVersion与 Fork 时间戳 CLI 测试crates/forge/tests/cli/test_cmd/spec.rs执行环境 spec 解析单元测试crates/evm/core/src/opts.rs变更记录本文主体来源.changelog/monad-ten-mip-8.md七、小结MonadTen 作为 Monad 默认硬分叉在 Foundry 中的落地包含三块能力MIP-8 基于页面的存储 Gas跨页读 8,000 / 跨页写 10,800、页面感知的 Access-List 生成同页去重、跨页保留并产生 1,900 页费用差、以及主网与测试网双时间戳激活。这套机制同时作用于区块执行、历史交易回放、eth_estimateGas、eth_createAccessList与trace_call确保本地开发、fork 测试与真实链上行为完全一致。【免费下载链接】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),仅供参考