EIP-150 及 Gas 的 63/64 规则

EIP-150是针对以太坊区块链的协议升级,主要引入了63/64规则以防止Call Depth Attack。该规则保留了一部分父合约的gas,防止递归调用消耗所有gas。

介绍

EIP-150,即以太坊改进提案150,是对以太坊区块链的协议升级。它于2016年3月18日提出,并于2016年7月20日作为以太坊拜占庭硬分叉的一部分实施。协议中有几个变化,但我们将重点关注它引入的63/64规则。

在深入讨论EIP-150的具体内容之前,了解以太坊中的gas和合约调用的概念是重要的。以太坊

作者

本文由tanim0la(Twitter)与RareSkills技术写作项目共同撰写。

以太坊中的gas概念

Gas是一个单位,用于衡量在以太坊虚拟机(EVM)上执行特定操作或合约所需的计算能力。

EVM上的每个操作或合约都需要一定量的gas才能执行,用户必须以Ether的形式支付这些费用。每当用户发起交易时,他们有义务承担其交易所执行的所有操作的累计费用。

对于基本的以太坊转账,该操作的成本恰好为21,000 gas;然而,更复杂的操作可能需要显著更多的gas,可能达到几百万。

合约调用

在以太坊中,一个合约(称为“调用者”)能够通过特定的操作码如CALLSTATICCALLDELEGATECALL来调用其他合约(称为“被调用者”)。当发生这种情况时,“被调用者”会接收到一定数量的gas,这类似于如果它们通过交易直接被调用时所接收到的gas。

分配的gas量部分由调用者决定,这在操作码参数中有所规定。有关更多信息,请参见 此处提供的CALL规范示例。如果被调用者接收到的gas不足,其操作将被回滚,从而触发“out of gas”异常。

EIP-150的规范

之前,调用者可以将提供给他们的所有gas发送给被调用者。然而,这允许潜在的无休止的合约调用其他合约,因为每次调用的gas成本都很低。

为了防止以太坊节点实现中出现“stack too deep”问题,最大深度被限制为1024,这一限制至今仍然有效。当达到这个深度时,最后一次调用将被回滚。

因此,交易签名者能够保证特定调用将被回滚,通过使交易经历一系列调用直到达到深度1023,然后再调用所需的智能合约。这种攻击被称为“调用深度攻击”。

以下是一个容易遭受此攻击的合约示例:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.5;

// 请勿使用!!!
contract Auction {
    address highestBidder;
    uint256 highestBid;

    function bid() external payable {
        if (msg.value < highestBid) revert();

        if (highestBidder != address(0)) {
            payable(highestBidder).send(highestBid); // 退还之前的出价者
        }
        highestBidder = msg.sender;
        highestBid = msg.value;
    }
}

在实施EIP-150之前,上述合约可能容易受到“调用深度攻击”。这是因为恶意出价者可以对自己发起递归调用,使得栈深度在调用bid()函数之前增加到1023。因此,send(highestBid)调用将静默失败,这意味着之前的出价者不会收到退款,而新的出价者仍然会成为最高出价者。

EIP-150中提出的解决方案是,在调用被调用者合约后,保留调用合约中一部分可用的gas(即调用不能超过父合约gas的63/64)。

保留给父合约的gas公式:

保留的可用gas部分 = 深度N时的可用gas - ((63/64) * 深度N时的可用gas)

让我们测试上述公式!

假设;深度0时的可用gas = 1000

保留的可用gas部分 = 1000 - ((63/64) * 1000) = 15

63/64规则:被调用者可以接收的gas

下面的公式计算任何栈深度下的可用gas。此外,可用gas与栈深度成反比(栈深度越深,可用gas越少)。

深度0时的可用gas  = 初始可用gas * (63/64)^0
深度1时的可用gas  = 初始可用gas * (63/64)^1
深度2时的可用gas  = 初始可用gas * (63/64)^2
深度3时的可用gas  = 初始可用gas * (63/64)^3
.
.
.
深度N时的可用gas  = 初始可用gas * (63/64)^N

以下是一些示例值。

假设;初始可用gas = 3000

深度10时的可用gas  = 3000 * (63/64)^10 = 2562

深度20时的可用gas  = 3000 * (63/64)^20 = 2189

eip 150 ethereum gas at stack call

由于每增加一层深度,gas迅速减少,递归深度将自然受到限制。尽管栈深度的限制1024在当前的以太坊实现中依然存在,但实际上几乎无法达到。

除了前面提到的修改,EIP-150还对CALL*操作码进行了更改,现在提供的gas是一个最大值,而不是严格值。这意味着如果被调用合约的可用gas低于填入操作码中指定的值,调用仍将继续进行,但gas量会减少,而不是失败,这在之前的版本中并非如此。

结论

总而言之,EIP-150的引入是为了防止调用深度攻击。它通过强制执行63/64规则规范来实现,这意味着即使在调用中显式转发所有剩余的gas,仍会为调用合约保留一部分。

了解更多

加入我们的Solidity速成班,以全面了解EVM和以太坊协议。

最初发布于2023年3月23日

  • 原文链接: rareskills.io/post/eip-1...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
RareSkills
RareSkills
https://www.rareskills.io/