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是一个单位,用于衡量在以太坊虚拟机(EVM)上执行特定操作或合约所需的计算能力。
EVM上的每个操作或合约都需要一定量的gas才能执行,用户必须以Ether的形式支付这些费用。每当用户发起交易时,他们有义务承担其交易所执行的所有操作的累计费用。
对于基本的以太坊转账,该操作的成本恰好为21,000 gas;然而,更复杂的操作可能需要显著更多的gas,可能达到几百万。
在以太坊中,一个合约(称为“调用者”)能够通过特定的操作码如CALL
、STATICCALL
和DELEGATECALL
来调用其他合约(称为“被调用者”)。当发生这种情况时,“被调用者”会接收到一定数量的gas,这类似于如果它们通过交易直接被调用时所接收到的gas。
分配的gas量部分由调用者决定,这在操作码参数中有所规定。有关更多信息,请参见 此处提供的CALL规范示例。如果被调用者接收到的gas不足,其操作将被回滚,从而触发“out of gas”异常。
之前,调用者可以将提供给他们的所有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
下面的公式计算任何栈深度下的可用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
由于每增加一层深度,gas迅速减少,递归深度将自然受到限制。尽管栈深度的限制1024在当前的以太坊实现中依然存在,但实际上几乎无法达到。
除了前面提到的修改,EIP-150还对CALL*操作码进行了更改,现在提供的gas是一个最大值,而不是严格值。这意味着如果被调用合约的可用gas低于填入操作码中指定的值,调用仍将继续进行,但gas量会减少,而不是失败,这在之前的版本中并非如此。
总而言之,EIP-150的引入是为了防止调用深度攻击。它通过强制执行63/64规则规范来实现,这意味着即使在调用中显式转发所有剩余的gas,仍会为调用合约保留一部分。
加入我们的Solidity速成班,以全面了解EVM和以太坊协议。
最初发布于2023年3月23日
- 原文链接: rareskills.io/post/eip-1...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!