原文作者:@Web3 Mario 引言:Vitalik 在 2024 年 5 月 13 日发布了 EIP-7706 提案,提出了对现有 Gas 模型的补充方案,将 calldata 的 gas 计算单独剥离出来,并定制了类似 Blob gas 的 base fee 定价机制,进一步降低 L2 的运行成本。与之相关的提案还需要追溯到 2022 年 2 月提出的 EIP-4844 ,相隔时间甚久,因此查阅相关资料,希望对最新的 Ethereum Gas 机制做一个综述,方便大家快速了解。 在最初的设计中,Ethereum 采用了一个简单的拍卖机制对交易费用进行定价,这需要用户主动为自己的交易出价,也就是设置 gas price,通常情况下,由于用户付出的交易费将归属于矿工,所以矿工将根据经济最优的原则,按照出价高低来决定交易打包顺序,注意这是在忽略 MEV 的情况下。在当时核心开发者看来这个机制面临着以下四个方面的问题: 交易费用水平的波动性与交易的共识成本之间的不匹配:对于处在活跃状态的区块链中,交易的打包需求充足,这意味着区块可以被轻易填满,但这往往也意味着整体费用的波动性极大。例如当平均 Gas Price 为 10 Gwei 时,网络因在一个区块中再接受一笔交易而产生的边际成本是平均 Gas Price 为 1 Gwei 时的 10 倍,这是不可接受的。 对用户来说不必要的延迟:由于每个区块有 gas limit 的硬性限制,加上历史交易量的自然波动,交易通常会等待几个区块才能被打包,但这对整体网络来说是低效的;即不存在允许一个区块更大而下一个区块更小的“松弛”机制来满足逐个区块的需求差异。 定价效率低下:由于采用简单的拍卖机制导致了公允价格发现的效率较低,这意味着对于用户来说,给出一个合理的定价将是困难的,这也就意味着有非常多情况下,用户付高了手续费。 无区块奖励的区块链将不稳定:当取消挖矿带来的区块奖励并采取单纯的手续费模型时,可能会导致很多不稳定,例如激励挖掘窃取交易费用的“姐妹块”,开启更强大的自私挖掘攻击向量等。 直到 EIP-1559 的提出与执行,Gas 模型有个第一次迭代,EIP-1559 时 Vitalik 等核心开发者在 2019 年 4 月 13 日提出的,并在 2021 年 8 月 5 日的 London 升级中被采用,该机制摒弃了拍卖机制,转而采用了一种 Base fee 和 Priority fee 的双定价模型,其中 Base fee 将根据父区块中已产生的 gas 消耗情况与一个浮动且递归的 gas target 之间的关系通过一个既定的数学模型定量计算,直观的效果为若上一个区块中 gas 使用情况超过了预定的 gas target 时,则上调 base fee,若不及 gas target,则下调 base fee,这样做既可以比较好的反应供需关系,又可以使得对于合理 gas 的预测变得更加精准,不至于出现由于误操作导致的天价 Gas Price,因为 base fee 的计算是直接由系统决定的而非用户自由指定。具体的代码如下: 其中可知当 parent_gas_used 大于 parent_gas_target 时,那么当前区块的 base fee 将相比于上一个区块的 base fee 加上一个偏移值,至于偏移值则是取 parent_base_fee 乘以上一个区块 gas 总用度相对 gas target 的偏移量并对 gas target 与一个常量取余与 1 的最大值。反之逻辑类似。 另外 Base fee 将不再作为奖励分配给矿工,而是直接销毁,从而时 ETH 的经济模型处于通缩的状态,有利于价值的稳定。而另一方面 Priority fee 则相当于用户给矿工的打赏,可以自由定价,这一定程度上可以让矿工的排序算法得到一定程度的复用。 随着时间推进到 2021 年,那时 Rollup 的发展逐渐进入佳境,我们知道无论 OP Rollup 还是 ZK Rollup 都意味着需要将 L2 的数据做压缩处理后的某些证明数据通过 calldata 上传至链上实现数据可用性(Data Available)或者直接交由链上做验证。这就让这些 Rollup 解决方案在维护 L2 的最终性时面临着很大的 Gas 成本,而这些成本最终都将转嫁到用户的身上,因此那时大部分的 L2 协议使用成本并没有想象那么低。 与此同时 Ethereum 也面临着区块空间竞争的窘境,我们知道每个区块存在一个 Gas Limit,这意味着当前区块中的所有交易的 Gas 消耗加总不可以超过该值,按当前的 Gas Limit 为 30000000 来计算,理论上存在 30, 000, 000 / 16 = 1, 875, 000 字节的限制,其中 16 指的是 EVM 处理每个 calldata 字节需要消耗 16 单位的 Gas,也就意味着单个区块最多可以承载的数据规模约为 1.79 MB。而 L2 排序器所产生的 Rollup 相关数据通常数据规模较大,这就使其与其他主链用户的交易确认产生竞争,导致单个区块可以打包的交易量变小,进而影响主链的 TPS。 为了解决这个窘境,核心开发者们于 2022 年 2 月 5 日提出了 EIP-4844 提案,并在 2024 年二季度初的 Dencun 升级后得到了实施。该提案提出了一种新的交易类型,名为 Blob Transaction,相比于传统类型的 Transaction,Blob Transaction 的核心思想是补充了一个新的数据类型,即 Blob data。区别于 calldata 类型,blob data 不可以被 EVM 直接,而只能访问其 hash,也被称为 VersionedHash。此外还有两个相伴而来的设计,其一相较于普通交易,blob transaction 的 GC 周期更短,从而保证区块数据不至于过于臃肿,其二 blob data 的具有原生的 Gas 机制,总体上呈现的效果于 EIP-1559 类似,但在数学模型上选择自然指数函数,使其在应对交易规模波动时稳定性上表现更好,因为自然指数函数的斜率亦为自然指数函数,这意味着无论此时网络交易规模处在什么状态,当交易规模快速飙升时,blob gas 的 base fee 反应的更充分,从而有效遏制交易活跃度,同时该函数还有一个重要的特性,当横坐标为 0 使,函数值为 1 。 base_fee_per_blob_gas = MIN_BASE_FEE_PER_BLOB_GAS * e**(excess_blob_gas / BLOB_BASE_FEE_UPDATE_FRACTION) 其中 MIN_BASE_FEE_PER_BLOB_GAS 和 BLOB_BASE_FEE_UPDATE_FRACTION 为两个常量,而 excess_blob_gas 则由父区块中总的 blob gas 消耗于一个 TARGET_BLOB_GAS_PER_BLOCK 常量之间的差值来决定,当总的 blob gas 消耗超过目标值,即差值为正时,e**(excess_blob_gas / BLOB_BASE_FEE_UPDATE_FRACTION) 大于 1 ,则 base_fee_per_blob_gas 变大,反之则变小。 这样对于一些只希望利用 Ethereum 的共识能力为某些规模较大的数据做存证以保证可用性的场景就可低成本的执行,同时不会挤占区块的交易打包能力。以 Rollup 排序器为例,可以通过 blob transaction 将 L2 的关键信息封装到 blob data 中,并在 EVM 中通过精巧的设计,利用 versionedHash 实现链上验证的逻辑。 需要补充的是当前 TARGET_BLOB_GAS_PER_BLOCK 和 MAX_BLOB_GAS_PER_BLOCK 的设置为主网带来了一个限制,即每个区块的平均处理 3 个 blob ( 0.375 MB) 的目标和最多 6 个 blob ( 0.75 MB) 的限制。这些初始限制旨在最大限度地减少该 EIP 对网络造成的压力,并且随着网络在较大区块下展现出可靠性,预计会在未来的升级中增加。 在明确了当前 Ethereum 的 Gas 模型后,我们来看下 EIP-7706 提案的目标与实施细节。该提案由 Vitalik 在 2024 年 5 月 13 日提出。与 Blob data 类似,该提案对另一个具有特殊性的数据字段对应的 Gas 模型进行了剥离,这个数据字段即为 calldata。并且优化了相应的代码实现逻辑。 从原理上 calldata 的 base fee 计算逻辑与 EIP-4844 中 base fee for blob data 相同,均采用了指数函数并根据父区块中的实际 gas 消耗值与目标值的偏差值来计算对当前 base fee 的缩放比例。 值得注意的是一个新的参数设计,LIMIT_TARGET_RATIOS=[ 2, 2, 4 ],其中 LIMIT_TARGET_RATIOS[ 0 ]表示了执行操作类 Gas 的目标比率,LIMIT_TARGET_RATIOS[ 1 ]表示 Blob data 类 Gas 的目标比率,LIMIT_TARGET_RATIOS[ 2 ]表示 calldata 类 Gas 的目标比率,这个向量用于计算父区块中三类 gas 对应的的 gas target 值,计算逻辑如下,即分别使用 LIMIT_TARGET_RATIOS 对 gas limit 做整除操作: 其中 gas_limits 的设定逻辑如下: gas_limits[ 0 ]必须遵循现有的调整公式 gas_limits[ 1 ]必须等于 MAX_BLOB_GAS_PER_BLOCK gas_limits[ 2 ]必须等于 gas_limits[ 0 ] // CALLDATA_GAS_LIMIT_RATIO 我们知道当前 gas_limits[ 0 ]为 30000000 ,CALLDATA_GAS_LIMIT_RATIO 被预设为 4 ,这就意味着当前 calldata gas target 约为 30000000 // 4 // 4 = 1875000 ,又因为按当前的 calldata gas 计算逻辑,每个非零 Bytes 消耗 16 Gas,零 Bytes 消耗 4 Gas,假设某段 calldata 中非零与零 Bytes 的分布各占 50% ,则平均处理 1 Bytes 的 calldata 需要消耗 10 Gas。因此当前的 calldata gas target 应对应 187500 bytes 的 calldata 数据,约为当前平均用量的 2 倍, 这样做的好处在于大大减少了 calldata 达到 gas limit 的情况发生的概率,通过经济模型使 calldata 的用量保持在一个较为始终的状态,同时也杜绝了对 calldata 的滥用。之所以做这样的设计还是为 L2 的发展扫平障碍,搭配 blob data,使得排序器成本进一步降低。当前已支持的 Ethereum Gas 模型——EIP-1559 和 EIP-4844
对于执行环境 Gas 消耗模型的再细化——EIP-7706