深入理解以太坊 Gas 机制:从概念起源和 21 个 EIP 开始

Gas 费问题是目前以太坊 1.0 链面临最严重的问题之一,尽管以太坊的算力很多,但任务能力因为区块链的结构问题(每个全节点计算同样的数据,因此任务都在抢单个节点的计算资源),以太坊在处理大量任务的时候会拥堵,拥堵后,Gas 费会很高。

DeFi 应用爆发式增长,让这种现象愈演愈烈。这里要提到的是,以太坊除了打包区块链交易外,智能合约等也是发布到链上的,所以智能合约在链上执行的时候要消耗资源,因此用户在 DeFi 里做的几乎每一步,都需要支付 Gas 费,这也是 Gas 模型的一个问题所在。

近日以太坊社区对 EIP-1559 的讨论也是更加激烈,因为有很多的矿池并不同意部署这个提案,这个提案调整了 Gas 费的构成,虽然无法解决 Gas 高的问题,但可以提升对 Gas 费的预期,完善体验。

还有一个近期的相关消息,3 月 16 日,以太坊的一位开发者 Philippe Castonguay 提出了另一个提案 EIP-3382,提议将区块 Gas 限制固定为每区块 12,500,000 Gas。并且更新块验证规则,如果 Gas 限制不等于 12,500,000,则区块无效。这是为了对区块 Gas 限制达成共识,并且不受矿工制约。

在原来的规则中,区块 Gas 限制是以太坊中唯一不由节点一致性决定的数据部分,是由矿工选择的参数。他认为这是一个关键参数,需要节点一致性,以避免少数参与者对网络其余部分施加任何突然的有害变化。

像 EIP1559、EIP-3382 这样对 Gas 费进行调整的提议很多,因为 Gas 费在以太坊运行过程中占据了重要地位,所以,Gas 费有很多历史故事,如果把所有关于 Gas 费的消息全部浏览完毕,可以发现,解决 Gas 费并非易事。

今天,白计划团队会为读者在文中提及大约全部以太坊的 Gas 费关联资料,包含设计变化、EIP 修订等。愿您有所用。

如果想要理解 Gas 费,从 TXStreet 的动态图像可以很形象去理解。

币世界-深入理解以太坊 Gas 机制:从概念起源和 21 个 EIP 开始

TXStreet 将以太坊区块打包过程形象化为交通运输

如果把区块打包抽象成一个汽车载人运输过程,会遇到道路宽度有限、汽车容量有限因素,所以进入汽车的过程就会有竞争,可以理解为以价高者的,而平均的费用也会因拥堵被「哄抬」。

汽车行驶的道路,是基础资源,需要支付「过路费」来 Cover,而打包需要的 Gas 费是「Gas 费」,羊毛出在羊身上,Gas 费用来最终支付「过路费」。所以 Gas 费(Gas 费)就是最终支付以太坊的资源使用的费用。

早期关于 Gas 的第一个 key

Gas 的概念是来自计算机领域,在以太坊里看到,最早来源于以太坊黄皮书,黄皮书的作者是 Polkadot 创始人 Gavin,说起来很吓人,以太坊黄皮书指出,理论上,交易中包含的 Gas 可以是任意值,因为理论上要涵盖更多交易,最高可达 2 ^ 256 (可涵盖与已知宇宙中的原子数几乎一样多的交易)。

虽然设计无限,但处理能力是有限的,在 Geth 1.6 版本中,Gas 计算切换为使用 64 位值,这样 Gas 限制为 64 位的单个块可以容纳的交易量是人体中红细胞数量的 44 倍。不过这是理论,现实远远大相径庭。

在这个版本确认前,还有一个较为有趣的细节,在 Vitalik 设计的以太坊 Gas 模型里,是把 Gas 费支付过程默认在合约里,也就是一个合约执行过程中,合约中的余额会减少,如果余额因为执行消耗不足了,合约会暂停。

币世界-深入理解以太坊 Gas 机制:从概念起源和 21 个 EIP 开始

早期以太坊合约里执行设置的内置扣费

而后来 Gavin 开始参与以太坊,进入后就修改了 Gas 的付费机制,从这种合约执行支付变成了转账人支付,也就是合约执行人支付。Vitalik 描述为,从「合同付款」方式转变为「发送者付款」方式,以代替每个单独的交易步骤立即拿走一点 ETH。

币世界-深入理解以太坊 Gas 机制:从概念起源和 21 个 EIP 开始

以太坊早期 Vitalik 和 Gavin 在迷你黑客松上,中间的大神是 Jeffrey

这是比较容易理解的「Gas 费支付」。如果解剖更细节的部分,我们要看黄皮书里 Gas 的关联部分。

Gas 是以太坊中所有计算量的计价单位,想要在以太坊上进行越多计算,则要支付越多 Gas。

这种采取使用者付费的模式,能够避免资源滥用。可以理解为一旦开发者为每种运算支付费用,就会尽可能将代码写得简洁高效,另外,Gas 的存在还能阻止攻击者通过无效运算(因此执行很多操作都需要花费 Gas),对以太坊网路进行泛洪(Flooding)攻击,下文中统计的一个 EIP 就是提高了对账户访问的 Gas 值来减少攻击可能性的。

除了知道哪里需要付 Gas,我们还需要了解 GasPrice 和 GasLimit。

GasPrice 为交易发送方对每单位 Gas 愿意支付的价格(以 Wei 计量),交易发送方可以自定义愿意支付的每单位 Gas 价格。假设一笔交易需要耗费 10 Gas,发送者愿意支付 3 Wei/Gas ,交易的成本总价就是 30 Wei,在我们使用的钱包里都会有调整 Gas 费的高级选项。

GasLimit 为交易发送方最多能接受的用于执行交易的 Gas 量。假如没有 GasLimit,可能会导致发送方的账户余额被误消耗殆尽,GasLimit 是安全机制,防止把账户中所有 ETH 消耗掉。

另外,GasLimit 也可以被定义为预付 Gas。当节点在验证交易时,先将 GasPrice 乘 GasLimit 算出交易的固定成本。如果交易发送方的账户余额小于交易固定成本,则该交易视为无效。交易执行完之后,剩余的 Gas 会退回至发送方账户,这也是为什么我们在使用 MetMask 执行合约的时候,预估 Gas 很贵,但执行完毕价格并没有那么高。

币世界-深入理解以太坊 Gas 机制:从概念起源和 21 个 EIP 开始

一个区块里包含的内容

这是一个区块里的固有内容,在交易部分,有 237 笔转账和 39 笔合约内部交易,如果具体查看交易就可以看到更详细的 Gas 费花销。也可以看到燃料限制为 12493113,文章开头提到的 EIP-3382 中,将每个块的 Gas 限制限制在 12500000,就是这个部分。这样,每个块里拿到的奖励总和会比较可控。

关于 ETH1.0 链,有一个每个操作码的 Gas 费计算,我们截取了其中价格较高的部分,供读者参考。操作码最终会决定了链的执行和资源的使用。例如,一个基本的思路是,假如创建合约。成本计算如下:

固有成本 = Gtransaction + Gtxdatazero * Nzeros + Gtxdatanonzero * Nnonzeros + Gtxcreate

其中:

  • Gtransaction = 21,000 Wei

  • Gtxcreate = 32,000 Wei

  • Gtxdatazero = 4 Wei

  • Gtxdatanonzero = 68 Wei (在伊斯坦布尔升级时会改为 16 wei)

大家可以对以下的操作码对号入座。

币世界-深入理解以太坊 Gas 机制:从概念起源和 21 个 EIP 开始

以太坊 1.0 链的操作码对应的 gas 值消耗

据以上的介绍,我们可以得到的基本理解是,Gas 费是因为使用以太坊的链上资源产生的,计算越多,Gas 越高,在智能合约合约操作里,每个单独的步骤都需要支付 Gas。另外,补充一点,如果发送者把 Gas 设置的很高,矿工会优先执行交易,因为矿工可以选择优先打包某些交易。

21 个与 Gas 费息息相关的 EIP

接下来我们就可以详细看一下关于 Gas 的 EIP 提案。提案大约根据时间先后排列。

EIP-5: 调整 RETURN 和 CALL 的 Gas 用量

此 EIP 使得调用 RETURN 字符串和其他动态大小的数组的函数成为可能。当前,当从以太坊虚拟机内部调用另一个合约 / 功能时,必须预先指定输出的大小。还必须为未写入的内存支付费用,这使得返回动态大小的数据既昂贵又不灵活,以至于实际上无法使用。此 EIP 中提出的解决方案是仅对 CALL 返回时实际写入的内存支付。

EIP-150:大量 IO 操作的 Gas 成本变化

  • 将 EXTCODESIZE 的 Gas 费用从 20 增加到 700。

  • 将 EXTCODECOPY 的基础 Gas 成本从 20 增加到 700。

  • 将 BALANCE 的 Gas 费用从 20 增加到 400。

  • 将 SLOAD 的 Gas 成本从 50 增加到 200。

  • 将 CALL,DELEGATECALL,CALLCODE 的 Gas 费用从 40 增加到 700。

  • 将 SELFDESTRUCT 的 Gas 成本从 5000 增加到 5000。
    如果 SELFDESTRUCT 命中一个新创建的帐户,则会触发 25000 的额外 Gas 费用(类似于 CALL)。

  • 将建议的 Gas 限制目标提高到 550 万。

EIP-158:状态清除

在任何情况下,call 余额等都为 0 的账户都不再消耗 25000 个帐户创建 Gas 的成本

EIP-1108:降低 alt_bn128 预编译 Gas 成本

椭圆曲线计算预编译当前价格过高。对预编译进行重新定价将大大有助于以太坊上的许多隐私解决方案和扩展解决方案。对于基于以太坊的基于 zk-SNARK 的协议,EIP-1108 不仅会大大降低验证 zk-SNARK 的 Gas 成本,而且还可以帮助将多个 zk-SNARK 证明批量组合在一起。这也是一种可用于将单片 zk-SNARK 电路拆分为一批具有较小单个电路尺寸的 zk-SNARK 的技术,这使得 zk-SNARK 都更易于构造和部署。

目前,这些交易的成本约为 6,000,000Gas。此 EIP 可以将其减少到 1,000,000Gas,这使该协议更加实用。

EIP-1283:SSTORE 操作码的 Gas 调整

该 EIP 提议对 SSTORE 操作码进行计量更改,以实现合同存储的新用法,并在与大多数实现工作方式不匹配的地方减少过多的 Gas 成本。这可以作为 EIP-1087 的替代方案,在 EIP-1087 中,它尝试对更改缓存使用不同优化策略的实施更友好。

EIP-2028:减少交易数据用气成本

建议将 Calldata (GTXDATANONZERO)的 Gas 成本从当前的 68 字节降低到 16 字节,并通过数学建模和经验估算来支持。

EIP-2200:净 Gas 计量的结构化定义

此 EIP 为 SSTORE 操作码提供了净 Gas 计量更改的结构化定义,可用于合同存储的新用法,并在与大多数实现工作方式不匹配的地方降低了过多的 Gas 成本。这可以当作 EIP-1283 和 EIP-1706 的组合。

EIP-2565:ModExpGas 成本

为了准确反映 ModExp 预编译的实际操作成本,此 EIP 指定了一种用于计算 Gas 成本的算法。该算法估算了乘法复杂度成本,并将其乘以执行幂运算所需的迭代次数的近似值。

EIP-1559:ETH 1.0 链的收费市场变化

以太坊使用简单的拍卖机制以历史价格定价交易费用,用户以出价(「 Gasprices」)发送交易,矿工选择出价最高的交易,包含在内的交易按照指定的出价支付。这导致效率低下。

此 EIP 中的建议是从基本费用金额开始,该费用由协议根据网络的拥挤程度上下调整。当网络超出每块 Gas 的目标使用量时,基本费用会略有增加,而当容量低于目标数量时,基本费用会略有下降。

由于这些基本费用的变化受到限制,因此不同块之间基本费用的最大差异是可以预测的。然后,这允许钱包以高度可靠的方式为用户自动设置 Gas 费。预计即使在网络活跃期间,大多数用户也不必手动调整 Gas 费。对于大多数用户来说,基本费用将由他们的钱包来估算。

EIP-2929:状态访问操作码的 Gas 成本增加

增加的 Gas 成本 SLOAD (0x54)至 2100,以及 *CALL 操作码家族(0xf1,f2,f4,fA)、BALANCE 0x31 以及 EXT*操作码家族(0x3b,0x3c,0x3f)、以及 2600 免 CD (ⅰ)预编译。此外,还可以改革 SSTORE 计量方式,确保对 SELFDESTRUCT 这些操作码中固有的「实际存储负载」进行正确定价。

通常,操作码 Gas 成本的主要功能是估计处理该操作码所需的时间,目标是使 Gas 限制对应于处理块所需时间的限制。然而,存储访问操作码(SLOAD,以及CALL,BALANCE 和 EXT操作码)在历史上被低估。在 2016 年上海 DoS 攻击中,修复了最严重的客户端错误后,攻击者使用的一直奏效的策略之一就是简单地发送可访问或调用大量帐户的交易。

提议的 EIP 将这些操作码的成本增加了大约 3 倍,从而将最坏情况下的处理时间减少到大约 7-27 秒。数据库布局的改进涉及重新设计客户端以直接读取存储而不是跳到 Merkle 树上,这将进一步降低这种情况,尽管这些技术可能需要很长时间才能完全推出,并且即使采用这种技术,访问存储的 IO 开销也会保持实质性。

EIP-1077: 合约调用的 Gas 中继

采用 DApp 的主要障碍是需要多个 token 来执行链式操作。允许用户签名消息以显示执行意图,但允许第三方中继器执行消息可以避免此问题,尽管以太坊交易始终需要 ETH,但智能合约可以采用 EIP-191 签名并转发付款激励具有 ETH 的不受信任方执行交易。可以标准化它们的通用格式,以及用户允许以代币支付交易的方式,为应用程序开发人员提供了很大的灵活性,并且可以成为应用程序用户与区块链交互的主要方式。

EIP-1087:用于 SSTORE 操作的 Gas 计量

该 EIP 提议对 EVMSSTORE 操作的 Gas 收费方式进行更改,以减少不必要的 Gas 成本,并为合同存储提供新的用例。

EIP-1285:在 CALL 操作码中增加 GcallstipendGas

Gcallstipend 将 CALL 操作码中的费用参数从 2,300 增至 3,500Gas 单位。

EIP-1380:降低了内部调用的 Gas 成本

降低内部调用的 Gas 成本将极大地受益于诸如 Solidity 和 Vyper 之类的智能合约语言,这样他们便能够用 CALL 代替 JUMP 内部操作调用使用操作码。

EIP-1613: Gas 站网络

通过允许合同接受「代收货款」并为 Gas 付费,使非 ETH 用户可以访问智能合约(例如 dapp)。

与 dapp 通讯目前需要向 ETH 支付 Gas 费,这限制了 dapp 的采用仅限于以太坊用户。因此,合同所有者可能希望为 Gas 支付费用以增加用户获取量,或者让其用户以法定货币支付 Gas 费用。或者,第三方可能希望补贴某些合同的 Gas 成本。如 EIP-1077 中所述的解决方案可以允许来自不包含 ETH 的地址的交易。

EIP-1930:具有严格 Gas 语义的 CALL。如果没有足够的 Gas,请还原

添加智能合约功能,以使用特定数量的 Gas 执行 CALL。如果无法做到这一点,则应返回执行。

EIP-2045:EVM 操作码的颗粒 Gas 成本

计算 EVM 操作码(ADD,SUB,MUL,等等)通常相对于高估到用于存储操作码的 I / O ( SLOAD,SSTORE 等)。当前,最小的 Gas 成本为 1 (即一种 Gas 单位),并且大多数计算操作码的成本接近 1 (例如 3、5 或 8),因此可能降低成本的范围受到限制。一种新的最小 Gas 单位,称为「颗粒」,是一种 Gas 的一部分,将扩大 Gas 成本的范围,因此可以降低到当前的最低水平以下。

EIP-2046:降低了对预编译进行静态调用的 Gas 成本

将调用预编译的基本 Gas 成本 STATICCALL 从 700 降低到 40。这将允许更有效地使用预编译以及总成本低于 700 的预编译。

EIP-2542:新的操作码 TXGASLIMIT 和 CALLGASLIMIT

允许智能合约访问有关当前交易和执行框架的 Gas 限制的信息。随着中继,元交易,Gas 费和帐户抽象等概念的普及,对于某些合同而言,能够绝对精确地跟踪 Gas 支出变得至关重要。

EIP-3322:帐户 Gas 存储操作码

通过将 Gas 从需求量较小的区块移动到需求量较大的区块,从而带来了 Gas 供应弹性和价格稳定性。不幸的是,这奖励了不必要的状态增长。通过引入高级的 Gas 存储机制,Gas 市场将需要较少的存储和计算。

EIP-2780:减少内部交易 Gas

降低内在交易的成本 21,000 到 7,000Gas。

当前 21,000 交易的 Gas 内在成本使发送 ETH 的成本非常高,而小批量(数十美元)的成本通常高得令人望而却步。虽然其他 EIP (例如 EIP-1559)也考虑了 Gas 价格和首次价格拍卖的变化,但如果以安全的方式进行,大幅降低发送 ETH 的成本并实现更大数量的此类交易将是积极的。

第二个 key:Rollup 与 Gas

早期的 Gas 故事是关于以太坊 Gas 费模式的制定,而目前来看,除了对 Gas 费降低外,最好的扩容和降低 Gas 费方式还有压缩交易数据。

这便与 Rollup 关系很大。

一个简单的以太坊交易(发送 ETH)需要约 110 个字节。但是,Rollup 中的 ETH 传输仅占用 12 个字节,所以,Rollup 可能会使基础链的可伸缩性提高约 10 倍,在特定的计算里,采用 Rollup,可伸缩性甚至可以提高超过 100 倍。

这是绝对可观的成绩,这也是为什么 Eth2.0 成为了以 Rollup 为中心的开发路线。

Gas 费调整是个长久的概念和过程,是无数以太坊工程师对细节修复的结果,如果只查看单个 GasEIP 的调整,不足以感受到 Gas 费的重要和调整 Gas 费的难度。不过,可以肯定的是,以太坊 Gas 问题最终的解决方案,一定是 Eth2.0,请保持一颗期待的心吧。

深入理解以太坊 Gas 机制:从概念起源和 21 个 EIP 开始

扫一扫手机访问

深入理解以太坊 Gas 机制:从概念起源和 21 个 EIP 开始

发表评论