EIP-7778 深度解析:无退款的区块 Gas 记账机制如何堵住区块 Gas 上限的绕过漏洞
2026/9/16 1:26:38 网站建设 项目流程

EIP-7778 深度解析:无退款的区块 Gas 记账机制如何堵住区块 Gas 上限的绕过漏洞

【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs

导读

EIP-7778(Block Gas Accounting without Refunds)是 Ethereum 核心层的一项 Gas 记账机制改进提案,目标是彻底消除「区块实际执行的计算工作量」与「区块 Gas 记账」之间的系统性偏差。本提案将交易级(用户付费)与区块级(区块 Gas 上限执行)的两层记账解耦:用户依旧享受存储清零等操作带来的 gas 退款,但区块级记账不再扣除退款。读完本文,你将完整理解 gas 退款的由来与演变、区块 Gas 上限被绕过的攻击面、EIP-7778 的精确记账公式及其与 EIP-7623 calldata 下限的配合方式,以及它在后续网络升级(如 Glamsterdam)与多维 Gas 记账提案(EIP-8037)中的定位。

背景:gas 退款机制与它的副作用

退款机制的初衷

Ethereum 的 gas 退款机制最早用于激励「状态卫生」(state hygiene):鼓励开发者清理不再需要的存储槽与合约。其核心是SSTORE操作:当把存储槽从非零值写回零时,会触发退款。该机制经由 EIP-2200 的净 Gas 计量规则定型,再经 EIP-3529(Reduction in refunds)大幅收窄:

  • 移除SELFDESTRUCT退款;
  • SSTORE_CLEARS_SCHEDULE从 15,000 gas 降至SSTORE_RESET_GAS + ACCESS_LIST_STORAGE_KEY_COST,即当前约 4,800 gas(见 eip-3529.md);
  • 将单笔交易退款上限从gas_used // 2收紧为gas_used // MAX_REFUND_QUOTIENT,其中MAX_REFUND_QUOTIENT = 5,即退款最多为已消耗 gas 的 1/5。

EIP-3529 在其动机部分已经明确指出:退款会放大区块大小方差——一笔区块中实际消耗的 gas 理论上限接近账面 Gas 上限的两倍(退款为后续交易腾出了 gas 空间),尽管退款被限制在单笔交易已用 gas 的 50%(后被收紧至 20%)。这正是 EIP-7778 要根治的根源性问题。

两层记账的偏差从何而来

在 EIP-7778 之前,gas 退款同时作用于两个层面:

  1. 交易层(用户付费)SSTORE清零产生退款,减少用户实际支付的 gas;
  2. 区块层(区块 Gas 上限执行):同一笔退款也从「区块已用 gas」中扣除,导致区块实际执行的计算量超过账面 Gas 上限。

由此产生一个结构性漏洞:矿工/验证者可以在一个区块内打包比 Gas 上限允许的更多的计算工作。举例如下:

区块20878522的净使用量为 28.5 MGas,但其中包含 4.01 MGas 的退款,毛使用量达到 32.51 MGas——超出区块 Gas 上限 2.51 MGas。

以 30M 的区块 Gas 上限计算,这意味着该区块实际执行的计算量超限约 8.4%,而账面上却显示「未超限」。

EIP-7778 规范:用户层与区块层记账解耦

EIP-7778 的核心规范非常聚焦,只改动区块级记账,不动用户级记账:

1. 用户 Gas 记账(保持不变)

用户仍可获得符合条件操作(如将存储槽置零)的 gas 退款,交易 gas 计算式为:

gas_spent = max(tx_gas_used - gas_refund, calldata_floor_gas_cost)

其中calldata_floor_gas_cost来自 EIP-7623 引入的 calldata 下限成本(见下文)。

2. 区块 Gas 记账(修改)

在计算区块 Gas 上限执行时,不再减去退款

block.gas_used += max(tx_gas_used, calldata_floor_gas_cost)

注意该公式同时纳入了 EIP-7623 的 calldata 下限,并且有一个重要保留项:那些反映实际计算量减少的存储折扣仍然保留在区块级记账中,例如:

  • 热存储访问(warm storage access,见 EIP-2929 的访问清单机制);
  • 将值恢复为原始值(reverting to original values)时获得的折扣。

这类折扣之所以可以保留,是因为它们对应的「计算工作量确实减少了」——例如槽位写回原值时,客户端无需真正修改 Merkle 树。这与「清零退款」的本质不同:清零操作本身仍需要客户端执行真实的写入工作。

与 EIP-7623 calldata 下限的配合

EIP-7623(Increase calldata cost)通过引入 calldata 下限成本来限制最大区块尺寸,其关键参数为:

参数
STANDARD_TOKEN_COST4
TOTAL_COST_FLOOR_PER_TOKEN10

其中tokens_in_calldata = zero_bytes_in_calldata + nonzero_bytes_in_calldata * 4,交易 gasUsed 计算式变为(见 eip-7623.md):

tx.gasUsed = ( 21000 + max( STANDARD_TOKEN_COST * tokens_in_calldata + execution_gas_used + isContractCreation * (32000 + INITCODE_WORD_COST * words(calldata)), TOTAL_COST_FLOOR_PER_TOKEN * tokens_in_calldata ) )

EIP-7778 在区块记账公式中直接沿用了这个calldata_floor_gas_cost下限,从而保证:无论退款如何变动,区块级记账都不可能低于 calldata 下限所代表的最小数据成本。两个提案在「以记账反映真实资源消耗」这一目标上形成了互补——EIP-7623 约束的是数据字节,EIP-7778 约束的是执行计算量。

设计动机:让 Gas 上限与计算工作重新对齐

区块 Gas 上限的本来含义

区块 Gas 上限的设计目的是约束每区块的计算负载(computational load per block)。而退款机制的引入初衷是激励状态清理,并非允许突破计算上限。问题在于二者被耦合在了同一个记账通道里,导致账面 gas 无法真实反映客户端需要执行的工作量。

三层危害

EIP-7778 的 Motivation 明确列出该漏洞可能导致的后果:

  1. 网络不稳定:实际计算量超限会产生「超大区块」,增大传播与处理延迟;
  2. 拒绝服务(DoS)向量:攻击者可构造包含大量可退款操作的交易,让区块承载超出预期的计算压力;
  3. 计算负载超出设计上限:区块实际消耗的资源与协议设定的 Gas 上限脱节,损害资源定价的公平性。

从源码级事实看,EIP-3529 已经验证了这种攻击的现实性:退款上限收紧至 1/5 后,退款机制仍可使区块所需的存储写操作数量最多增加 25%——即存储写型 DoS 攻击的空间依然存在,EIP-7778 正是要在区块记账层面把这个口子彻底堵上。

保留用户激励的设计哲学

EIP-7778 的关键设计决策是只改记账,不改经济学:用户依然拿到退款,因而「清理状态更便宜」的激励被完整保留;只有区块级约束的计算口径发生变化。这种「两层记账」模式使协议约束与用户激励各归其位:

  • 用户层:退款照常,激励有效;
  • 区块层:以毛 gas(不扣退款)为口径,约束真实计算负载。

向后兼容性与硬分叉要求

EIP-7778 属于Standards Track / Core类别,且明确声明:

  • 不向后兼容,需要硬分叉——因为它改变了区块有效性判定所依赖的 gas 记账口径;
  • 对单笔交易的用户与开发者体验无任何影响——用户付费、gas 估算、RPC 行为均不变;
  • 区块生产者(矿工/验证者/构建者)需要调整交易选择算法——由于每笔交易对区块 Gas 的占用不再是「净 gas」,而是「毛 gas」,打包时必须以新口径重新计算区块填充度。

这一点对 PBS(Proposer-Builder Separation)环境下的构建者尤为重要:构建区块时必须确保max(tx_gas_used, calldata_floor_gas_cost)的累计值不超过区块 Gas 上限。

测试用例:如何验证新记账逻辑

EIP-7778 给出了三个方向的测试要求,可直接作为共识客户端(如 Geth、Reth、Erigon 等)的测试用例设计依据:

1. SSTORE 操作记账

  • 将存储槽置零:用户获得退款,但区块级记账使用全额成本
  • 验证包含大量存储清零操作的区块仍然遵守 Gas 上限。

2. 区块 Gas 上限边界用例

  • 构造包含不同比例可退款操作的区块;
  • 确保区块无法通过退款机制突破 Gas 上限

3. 交易 Gas 与区块 Gas 的一致性

  • 验证用户侧的交易成本保持不变;
  • 确认区块级记账正确排除了退款。

安全考量

EIP-7778 带来的安全收益可以归纳为三点:

  1. 消除 DoS 向量:封堵利用退款超额占用区块计算资源的攻击路径;
  2. 区块处理时间更可预测:对计算工作施加更严格的上限,降低区块处理时间的方差;
  3. 防止矿工/验证者集体超载:任何一组交易集合,其整体计算工作量都不可能再「借道」退款而超过协议预期。

在生态中的定位:与后续 EIP 的联动

EIP-7778 并非孤立提案,它在当前仓库的 EIP 生态中与多个提案存在明确的依赖与协同关系:

Glamsterdam 网络升级(EIP-7773)

EIP-7773(Hardfork Meta - Glamsterdam)已将 EIP-7778 列为Scheduled for Inclusion的 EIP 之一,与 EIP-8037(State Creation Gas Cost Increase)、EIP-7976(Increase Calldata Floor Cost)等一同进入该升级规划。

区块延迟减半(EIP-7782)

EIP-7782(Reduce Block Latency)在其requires字段中明确依赖7623, 7778——说明在缩短区块时间的同时,协议需要 EIP-7778 保证每个区块的实际计算负载可控。

多维 Gas 计量(EIP-8037)的集成方式

EIP-8037 引入执行 gas 与状态 gas 两个维度的独立计量,并专门设有「Integration with EIP-7778」一节(见 eip-8037.md),给出了与 EIP-7778 组合时的区块级记账公式:

tx_state_gas = tx_output.evm_state_gas_used tx_execution_gas = max(tx_gas_used_before_refund - tx_state_gas, calldata_floor_gas_cost) block_output.block_execution_gas_used += tx_execution_gas block_output.block_state_gas_used += tx_state_gas

其中max项正是保留了 EIP-7778 的block.gas_used += max(tx_gas_used, calldata_floor_gas_cost)规则,并将其应用于执行 gas 维度。EIP-8037 还特别澄清了一个容易混淆的点:状态 gas 的「refill」(如某帧 revert 后撤销的状态创建费用)不属于 EIP-7778 所指的退款——refill 撤销的是从未持久化创建的状态,其计量资源从未被真正消耗,因此始终净额计入evm_state_gas_used,不受 EIP-7778 影响。

移除退款上限的方向(EIP-3298)

EIP-3298 在其分析中指出:由于 EIP-7778 已将退款排除在区块级记账之外,退款上限(20% 上限)用于「限制退款对区块大小影响」的历史使命已经完成,从而为未来移除该上限、简化协议铺平了道路。这从侧面印证了 EIP-7778 承担的正是「让退款回归纯用户激励机制」的协议职责。

总结

EIP-7778 以最小的改动面(仅修改区块级记账公式)解决了 Ethereum 自引入退款机制以来长期存在的「账面 Gas 与实际计算负载脱节」问题。它通过两层记账解耦,同时达成了三个目标:用户激励不损、区块计算负载受控、超限漏洞封堵。结合 EIP-7623 的 calldata 下限,EIP-7778 构成了「字节成本 + 计算成本」双重约束的一部分;而它与 EIP-8037 的集成公式,则展示了如何在未来的多维 Gas 计量框架中延续其记账原则。对于共识层开发者、区块构建者以及研究 gas 定价的读者而言,EIP-7778 是理解 Ethereum 下一代 Gas 模型的关键一环。

【免费下载链接】EIPsThe Ethereum Improvement Proposal repository项目地址: https://gitcode.com/GitHub_Trending/ei/EIPs

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询