Foundry Anvil eth_simulateV1 补丁解析:在模拟执行中保留 EIP-4844 Blob 交易费用上限
Foundry Anvil eth_simulateV1 补丁解析在模拟执行中保留 EIP-4844 Blob 交易费用上限【免费下载链接】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-simulate-blob-fee-cap.md 记录的anvil: patch级变更展开深入剖析 Anvil 在eth_simulateV1模拟执行中**保留 Blob 交易费用上限blob fee cap**的底层实现。读完本文你将理解eth_simulateV1的执行路径、EIP-4844 Blob 费用校验在模拟场景下的处理逻辑以及如何构造包含maxFeePerBlobGas、blobVersionedHashes的模拟请求并在本地测试中验证该行为。一、变更背景一次针对 eth_simulateV1 的 patch该 changelog 条目全文如下--- anvil: patch --- Preserved blob transaction fee caps during eth_simulateV1 execution.虽然条目简短但指向的是一个具体且影响深远的修复点Anvil 的eth_simulateV1RPC 方法在执行模拟时此前未能完整保留 EIP-4844 Blob 类型交易type 3 交易中的费用上限字段maxFeePerBlobGas该补丁修正了这一点使模拟环境中的 Blob 交易与真实交易执行遵循一致的费用校验规则。从源码结构看这一修复同时涉及三个层面模拟请求的字段保真传递preserve_simulation_request_fields后端 EVM 环境构建时的 blob 费用校验BlobFeeCapTooLow模拟专用SimulationHandler对零价格 Blob 调用的豁免逻辑。二、eth_simulateV1 的执行入口与字段保留2.1 RPC 入口simulate_v1Anvil 的eth_simulateV1处理入口位于 crates/anvil/src/eth/api.rs 的EthApi::simulate_v1pub async fn simulate_v1( self, request: SimulatePayload, block_number: OptionBlockId, ) - ResultVecSimulatedBlockAnyRpcBlock { self.simulate_v1_raw(preserve_simulation_request_fields(request), block_number).await }关键点在于进入simulate_v1_raw之前请求先经过preserve_simulation_request_fields预处理。simulate_v1_raw内部会校验空输入、块数量上限MAX_SIMULATE_BLOCKS超限返回-38026 too many blocks、解析区块请求与区块间隔最终在分叉fork模式下走fork.simulate_v1否则调用backend.simulate_raw在阻塞任务中执行模拟crates/anvil/src/eth/api.rs#L3285-L3359。2.2 字段保留preserve_simulation_request_fields补丁的核心机制是preserve_simulation_request_fields实现在 crates/anvil/src/eth/mod.rspub(crate) fn preserve_simulation_request_fields( request: SimulatePayload, ) - SimulatePayloadWithOtherFieldsTransactionRequest { SimulatePayload { block_state_calls: request .block_state_calls .into_iter() .map(|block| SimBlock { block_overrides: block.block_overrides, state_overrides: block.state_overrides, calls: block.calls.into_iter().map(WithOtherFields::new).collect(), }) .collect(), trace_transfers: request.trace_transfers, validation: request.validation, return_full_transactions: request.return_full_transactions, } }这里使用了 alloy 的WithOtherFieldsTransactionRequest它把每个TransactionRequest中标准字段之外的所有其他字段other映射完整保留。对 EIP-4844 交易而言maxFeePerBlobGas、blobVersionedHashes、maxPriorityFeePerGas等字段正是以这类附加字段形式存在。在补丁之前这些字段在模拟请求转换过程中可能被剥离导致模拟执行时 Blob 交易的费用上限丢失补丁通过WithOtherFields::new包装确保这些字段在进入 EVM 上下文前原样保留——这正是 changelog 中 Preserved blob transaction fee caps 的代码级体现。三、模拟执行中的 Blob 费用校验3.1 常规路径BlobFeeCapTooLow 校验在 crates/anvil/src/eth/backend/mem/mod.rs 的交易池校验逻辑中EIP-4844 Blob 费用校验位于 EIP-1559 费用校验之后// EIP-4844 blob fee validation if evm_env.cfg_env.spec SpecId::CANCUN tx.is_eip4844() let Some(max_fee_per_blob_gas) tx.max_fee_per_blob_gas() let Some(blob_gas_and_price) evm_env.block_env.blob_excess_gas_and_price max_fee_per_blob_gas blob_gas_and_price.blob_gasprice { debug!(target: backend, max fee per blob gas{}, too low, block blob gas price{}, max_fee_per_blob_gas, blob_gas_and_price.blob_gasprice); return Err(InvalidTransactionError::BlobFeeCapTooLow( max_fee_per_blob_gas, blob_gas_and_price.blob_gasprice, )); }条件链为硬分叉不低于 CancunSpecId::CANCUN 交易为 EIP-4844 类型 交易携带maxFeePerBlobGas 区块环境包含blob_excess_gas_and_price费用上限低于区块 blob 气体价格→ 返回BlobFeeCapTooLow错误。在后续的资金充足性检查中max_cost也计入blob_gas_used() * max_fee_per_blob_gas()同文件 crates/anvil/src/eth/backend/mem/mod.rs#L9119-L9126。这意味着当eth_simulateV1的调用保留maxFeePerBlobGas后模拟会像真实交易一样对过低的 blob 费用上限报错从而真实反映主网/分叉环境的费用约束而不是静默忽略。3.2 模拟专用路径SimulationHandler 的豁免与普通eth_call走transact不同零价格的 Blob 调用会走模拟专用的SimulationHandlercrates/anvil/src/eth/backend/mem/mod.rs#L544-L578fn validate_env(self, evm: mut Self::Evm) - Result(), Self::Error { let skip_blob_fee_check evm.ctx_ref().cfg().is_base_fee_check_disabled() evm.ctx_ref().tx().tx_type 3 evm.ctx_ref().tx().max_fee_per_blob_gas 0; if !skip_blob_fee_check { return validation::validate_env(evm.ctx()); } let block evm.ctx_ref().block().clone(); let mut validation_block block.clone(); if let Some(blob_gas_and_price) mut validation_block.blob_excess_gas_and_price { blob_gas_and_price.blob_gasprice 0; } evm.ctx().set_block(validation_block); let result validation::validate_env(evm.ctx()); evm.ctx().set_block(block); result }逻辑要点当base fee 校验被禁用且交易类型为 3Blob且max_fee_per_blob_gas 0时跳过标准 blob 费用校验执行校验前将区块环境的blob_gasprice临时置 0校验完再恢复实现零价格 blob 调用也能通过环境校验。这条豁免路径与保留费用上限的补丁形成互补有上限的 blob 模拟按真实规则校验显式传0x0的零价格 blob 调用则被宽容处理便于开发者在不关心 gas 价格时做纯逻辑模拟。四、测试验证零价格 Blob 调用走模拟处理器仓库的集成测试直接印证了上述行为。crates/anvil/tests/it/simulate.rs 中test_simulate_v1_preserves_precompile_warming_rpc第 347-396 行注释明确写道// A zero-priced blob call uses the simulation handler; an ordinary call uses transact.测试构造了两类调用逐一验证for call in [ json!({to: helper}), json!({ to: helper, blobVersionedHashes: [format!(0x01{}, 00.repeat(31))], maxFeePerBlobGas: 0x0 }), ] { let response rpc_request( handle.http_endpoint(), eth_simulateV1, json!([{blockStateCalls: [{ stateOverrides: { source: {movePrecompileToAddress: destination}, helper: {code: helper_code} }, calls: [call] }]}, latest]), ) .await; assert!(response.get(error).is_none(), {response}); // 断言 access_costs 一致 … }该用例同时验证带blobVersionedHashesmaxFeePerBlobGas: 0x0的 blob 调用在eth_simulateV1中不会报错error为 Noneblob 调用与普通调用的模拟结果一致访问成本数组[107, 2607, 107]相同。结合 crates/anvil/tests/it/eip4844.rs、crates/anvil/tests/it/simulate.rs#L1028-L1085test_simulate_scopes_block_overrides_and_derives_base_fee_rpc等可以看到 Anvil 对模拟场景的区块覆盖、base fee 推导与 EIP-4844 参数的组合测试体系。五、实战如何在本地复现与使用5.1 启动 Anvil 并准备分叉环境Blob 费用校验要求硬分叉不低于 Cancun。可以通过--hardfork参数显式指定# 本地开发链显式启用 Cancun 硬分叉 anvil --hardfork cancun # 或分叉主网自动继承主网 hardfork 与 blob 基础费用状态 anvil --fork-url https://eth-mainnet.example.com/rpc --fork-block-number 200000005.2 构造 eth_simulateV1 请求调用eth_simulateV1模拟一个携带 blob 的调用务必保留maxFeePerBlobGas与blobVersionedHashes{ method: eth_simulateV1, params: [ { blockStateCalls: [ { blockOverrides: { blobBaseFee: 0x15 }, calls: [ { to: 0x0000000000000000000000000000000000000000, blobVersionedHashes: [ 0x0100000000000000000000000000000000000000000000000000000000000000 ], maxFeePerBlobGas: 0x2540be400 } ] } ], traceTransfers: false, validation: true, returnFullTransactions: true }, latest ], id: 1, jsonrpc: 2.0 }要点说明blockOverrides.blobBaseFee覆盖模拟区块的 blob 基础费用参考 crates/anvil/tests/it/simulate.rs#L1028-L1085 中blobBaseFee: 0x15的用法若maxFeePerBlobGas低于区块 blob 气体价格模拟将返回BlobFeeCapTooLow类错误——这正是补丁后费用上限被保留的直接体现若显式传maxFeePerBlobGas: 0x0则走SimulationHandler的豁免路径零价格 blob 调用可通过校验见test_simulate_v1_preserves_precompile_warming_rpc。5.3 通过集成测试回归验证仓库已内置相关测试可在本地运行验证该行为cargo test -p anvil --test it simulate其中 crates/anvil/tests/it/simulate.rs 覆盖eth_simulateV1的字段保留、区块覆盖、blob 调用等场景是理解本补丁行为最直接的参考用例。六、小结.changelog/anvil-simulate-blob-fee-cap.md虽然只有一行描述但它对应的是一个贯穿 Anvil RPC 层preserve_simulation_request_fields字段保真、后端 EVM 层BlobFeeCapTooLow校验与资金检查与模拟处理器层SimulationHandler零价格豁免的完整修复层级文件职责RPC 入口crates/anvil/src/eth/api.rssimulate_v1转发前调用字段保留函数字段保留crates/anvil/src/eth/mod.rsWithOtherFields::new保留maxFeePerBlobGas等附加字段费用校验crates/anvil/src/eth/backend/mem/mod.rs常规 blob 费用校验、资金上限计算模拟豁免crates/anvil/src/eth/backend/mem/mod.rs#L544-L578零价格 blob 调用的validate_env豁免测试佐证crates/anvil/tests/it/simulate.rs零价格 blob 调用走模拟处理器的集成测试从源码结构可以推断该补丁的动机是让eth_simulateV1的模拟结果与真实 blob 交易执行保持一致的费用语义既能用maxFeePerBlobGas触发真实的费用校验也能以显式零价格快速进行纯逻辑模拟。对于依赖 Anvil 做 EIP-4844 相关合约开发、分叉模拟与费用分析的开发者理解这一行为有助于构造更贴近主网语义的模拟请求。【免费下载链接】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),仅供参考