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

Foundry Anvil 收据优化:为非 Blob 交易省略 Blob Gas 字段的实现解析

Foundry Anvil 收据优化为非 Blob 交易省略 Blob Gas 字段的实现解析【免费下载链接】foundryFoundry is a blazing fast, portable and modular toolkit for Ethereum application development written in Rust.项目地址: https://gitcode.com/GitHub_Trending/fo/foundry导读本篇文章围绕 Foundry 仓库中一条 Anvil 变更记录.changelog/anvil-omit-non-blob-gas-price.md展开Anvil 在返回交易收据receipt时对非 BlobEIP-4844交易不再填充blobGasUsed与blobGasPrice两个字段而是输出null。读完本文你将理解这一行为变更的动机、EIP-4844 收据字段的规范背景、Anvil 中收据构造的底层调用链以及如何通过集成测试验证该行为。变更背景一条 patch 级 Changelog 记录Foundry 仓库使用tempoxyz/changelogs维护变更记录所有 Pull Request 都要求在.changelog/目录下新增或更新一个 Markdown 片段详见.changelog/README.md。每个片段以 YAML frontmatter 声明受影响的包与 bump 级别正文则是面向用户的发布说明。本主题对应的片段anvil-omit-non-blob-gas-price.md内容如下--- anvil: patch --- Omit blob gas fields from receipts for non-blob transactions.frontmatteranvil: patch表示这是对anvil包的一次补丁级patch变更不影响语义化版本号的 minor/major 部分发布说明一句话点明变更本质——对非 Blob 交易生成的收据中省略 blob gas 相关字段。这正是 Anvil 需要修复的一类兼容性问题在主网上eth_getTransactionReceipt对普通交易返回的收据中blobGasUsed与blobGasPrice字段通常为null若本地开发节点填充了非零值依赖这些字段的工具与脚本在本地与主网之间就会产生行为差异。EIP-4844 与收据中的 Blob 字段EIP-4844Proto-Danksharding即 Cancun 硬分叉引入的 Blob 交易为区块头与交易收据引入了新的字段。Anvil 的区块头定义位于 crates/anvil/core/src/eth/block.rs其中blob_gas_used与excess_blob_gas均为Option类型blob_gas_used: Optionu64, // 区块内 blob 消耗的 gas excess_blob_gas: Optionu64, // 区块的 excess blob gas用于计算 blob 基础费用在收据层面RPC 规范定义了blobGasUsed与blobGasPrice两个附加字段blobGasUsed该笔交易实际消耗的 blob gas。每个 blob 固定消耗DATA_GAS_PER_BLOB131072单位 gas因此只有携带 blob 的交易EIP-4844 类型 3 交易才有非零值blobGasPrice由区块头的excessBlobGas通过calc_blob_gasprice计算出的 blob 基础费用单位 wei。对非 Blob 交易而言这两个字段没有实际含义规范行为是返回null。变更前的行为非 Blob 交易收据被错误填充在 Anvil 的收据构造逻辑build_mined_transaction_receipt中位于 crates/anvil/src/eth/backend/mem/mod.rs变更前存在如下填充逻辑// Cancun specific let excess_blob_gas block.header.excess_blob_gas(); let blob_gas_used transaction.blob_gas_used(); let blob_gas_price blob_gas_used .map(|_| alloy_eips::eip4844::calc_blob_gasprice(excess_blob_gas.unwrap_or_default()));关键在于transaction.blob_gas_used()的返回值对Blob 交易它返回Some(实际 blob gas)从而blob_gas_price会被计算出来两个字段都正确填充对非 Blob 交易理论上它返回None此时blob_gas_used.map(...)会得到Noneblob_gas_price也是None——这看起来已经是省略了。但问题出在历史实现路径上上述字段随后被写入TransactionReceipt结构let receipt TransactionReceipt { inner: tx_receipt, transaction_hash: info.transaction_hash, transaction_index: Some(info.transaction_index), block_number: Some(block.header.number()), gas_used: info.gas_used, contract_address: info.contract_address, effective_gas_price, block_hash: Some(block_hash), from: info.from, to: info.to, blob_gas_price, blob_gas_used, };在链式调用的某些分支例如 pending block 构造、或底层 EVM 执行结果汇总中blob gas 字段可能以非None的默认值如0进入收据。这一点可以从区块构造逻辑得到印证在 crates/anvil/src/eth/backend/mem/mod.rs 的build_block_info中cumulative_blob_gas_used仅在硬分叉不低于 Cancun 时才被then_some(...)包裹为Somelet is_cancun spec_id SpecId::CANCUN; let cumulative_blob_gas_used is_cancun.then_some(block_result.blob_gas_used);一旦某条路径在未实际发生 blob 消耗的情况下把0作为 blob gas 字段写入非 Blob 交易的收据就会出现blobGasUsed: 0、blobGasPrice: 0这类与主网不一致的响应。本次 patch 的目的就是把这类残留路径统一修正为规范行为非 Blob 交易一律省略null。变更后的行为与测试验证该变更配套了一个专门的集成测试non_blob_receipt_omits_blob_fields位于 crates/anvil/tests/it/eip4844.rs#[tokio::test(flavor multi_thread)] async fn non_blob_receipt_omits_blob_fields() { let node_config NodeConfig::test().with_hardfork(Some(EthereumHardfork::Cancun.into())); let (_api, handle) spawn(node_config).await; let provider http_provider(handle.http_endpoint()); let accounts handle.dev_accounts().collect::Vec_(); let tx TransactionRequest::default().with_from(accounts[0]).with_to(accounts[1]); let receipt provider.send_transaction(tx.into()).await.unwrap().get_receipt().await.unwrap(); assert_eq!(receipt.blob_gas_used, None); assert_eq!(receipt.blob_gas_price, None); }这个测试清晰地刻画了预期行为显式指定 Cancun 硬分叉EthereumHardfork::Cancun排除未启用 Cancun 导致字段天然为 None的干扰确保测试严格覆盖 blob 字段已激活的场景发送一笔最普通的转账交易TransactionRequest::default()仅设置 from/to不携带任何 blob sidecar断言收据的blob_gas_used与blob_gas_price均为None即 RPC 响应中对应 JSON 字段为null。对照同文件中的 Blob 交易测试can_send_eip4844_transactioncrates/anvil/tests/it/eip4844.rs可以直观看出两类交易的差异let sidecar: SidecarBuilderSimpleCoder SidecarBuilder::from_slice(bHello World); let sidecar sidecar.build().unwrap(); // ... 携带 with_blob_sidecar_4844(sidecar) 发送交易 ... assert_eq!(receipt.blob_gas_used, Some(131072)); // DATA_GAS_PER_BLOB assert_eq!(receipt.blob_gas_price, Some(0x1)); // 1 weiBlob 交易的blob_gas_used为131072即DATA_GAS_PER_BLOB一个 blob 的固定 gas 成本blob_gas_price为1 wei由excess_blob_gas计算出的最小 blob 基础费用BLOB_TX_MIN_BLOB_GASPRICE。这一正一反两个测试共同锁定了收据字段填充的正确语义。底层原理blob gas 的执行与累计要理解为什么非 Blob 交易的 blob gas 应为空需要追溯到交易执行层。Anvil 的区块执行器crates/anvil/src/eth/backend/executor.rs维护了区块级累计的blob_gas_usedif self.spec_id SpecId::CANCUN { self.blob_gas_used self.blob_gas_used.saturating_add(blob_gas_used); }其中单个交易的blob_gas_used来源为let blob_gas_used tx.tx().blob_gas_used().unwrap_or_default();这里的关键点是unwrap_or_default()对非 Blob 交易blob_gas_used()返回Noneunwrap_or_default()将其归一化为0用于区块级累计——这对区块头计算是正确且必要的。但同样的数值若被错误地写回单个交易的收据字段就会破坏非 Blob 交易收据省略 blob 字段的规范。本次变更正是要在收据出口处区分区块累计与单笔交易字段两种语境前者允许0参与累计后者必须保持None。区块头的累计值在 crates/anvil/src/eth/backend/mem/mod.rs 中体现let cumulative_blob_gas_used is_cancun.then_some(block_result.blob_gas_used);仅当硬分叉不低于 Cancun 时区块头才携带blob_gas_used这也与 crates/anvil/core/src/eth/block.rs 中头部字段的Option设计一致。实际影响与兼容性收益该 patch 的价值在于与真实以太坊节点的行为对齐场景主网 / Geth 行为变更前 Anvil残留路径变更后 Anvil非 Blob 交易的blobGasUsednull可能为0null非 Blob 交易的blobGasPricenull可能为0nullBlob 交易的blobGasUsed实际消耗如131072实际消耗实际消耗Blob 交易的blobGasPrice由 excess blob gas 计算由 excess blob gas 计算由 excess blob gas 计算受益方包括依赖eth_getTransactionReceipt的工具与索引器按主网语义解析字段时不再被本地0值误导测试合约与脚本在本地 Anvil 与主网之间保持收据 JSON 结构一致便于快照比对其他 RPC 消费者例如基于 Anvil 的 L2 模拟环境Optimism 等见 crates/anvil/src/eth/backend/executor/optimism.rs在转发或消费收据时遵循统一语义。如何复现与验证在本地仓库复现该行为只需两步以 Cancun 硬分叉启动 Anvilanvil --hardfork cancun发送一笔普通转账并查询收据以curl为例# 发送一笔 ETH 转账 curl http://localhost:8545 -X POST -H Content-Type: application/json \ --data {jsonrpc:2.0,method:eth_sendTransaction,params:[{from:0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266,to:0x70997970C51812dc3A010C7d01b50e0d17dc79C8,value:0x1}],id:1} # 用返回的 txHash 查询收据 curl http://localhost:8545 -X POST -H Content-Type: application/json \ --data {jsonrpc:2.0,method:eth_getTransactionReceipt,params:[txHash],id:2}观察响应中的blobGasUsed与blobGasPrice字段二者应为null或直接缺失而不是0x0。若需在源码层面跑集成测试仓库已提供对应用例cargo test -p anvil --test it non_blob_receipt_omits_blob_fields -- --nocapture测试入口位于 crates/anvil/tests/it/eip4844.rs与 Blob 交易的完整用例can_send_eip4844_transaction等同处一个文件便于对照学习。小结anvil: patch级变更Omit blob gas fields from receipts for non-blob transactions看似只是一行发布说明背后却对应着 Anvil 在收据构造、区块执行与硬分叉门控三处的协同修正语义对齐非 Blob 交易收据的blobGasUsed/blobGasPrice输出null与主网一致执行链路区块级 blob gas 累计executor.rs与单笔收据字段填充mem/mod.rs职责分离测试锁定集成测试non_blob_receipt_omits_blob_fields与can_send_eip4844_transaction一正一反防止回归。对于使用 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 小时内出具建站方案 · 河南本地可上门