技能简析柏林晋级后 OpenEthereum 客户端犯错始末

技能简析柏林晋级后 OpenEthereum 客户端犯错始末

以太坊柏林晋级改变了 Gas 耗费量的计量办法,OpenEthereum 客户端对犯错买卖耗费的 Gas 核算与网络中其他客户端产生了不合。…比特币,技能,Gas,OpenEthereum,EIP-2929,项?发展 比特币 技能 Gas OpenEthereum EIP-2929 项?发展以太坊爱好者 图标 Logo以太坊爱好者区块链作者,团队,专栏,大众号,头条·

以太坊柏林晋级改变了 Gas 耗费量的计量办法,OpenEthereum 客户端对犯错买卖耗费的 Gas 核算与网络中其他客户端产生了不合。

原文标头:《科普 | OpenEthereum 客户端 「柏林」 晋级后犯错始末》
撰文:Alex Stokes
翻译:阿剑

你或许现已听说了,@OpenEthereum 客户端的一个过错导致了一些支撑以太坊网络的重要服务宕机。

咱们来揣摩一下那笔形成事端的买卖。

首要,我想感谢一切快速反应到 事端 并处理了问题的工程师。

别的,我没有自己盯梢一切的细节,下文中的重要现实都由用户 eb 在 Eth R&D; discord 服务器里提出。

先从那笔触发了过错的 买卖 开端。

这是一笔合约调用买卖,从 KuCoin 买卖所宣布,向许多地址分发 ETH。对该笔买卖的 call data 的 ABI 编码过错,终究导致了链割裂。你能够在 Etherscan 上看看这笔买卖的 「Input Data」。

1/ 在合约中调用 sendEths 时,需求供给两个参数:一个是关于方针地址的不定长数组(dynamically sized array);一个是关于转账数额(以 wei 为单位)的不定长数组;两者相调配才知道要搬运多少钱给哪个地址。

2/ 咱们能够解析 call data 来看看究竟哪里出了错:榜首行(在 Etherscan 上标记为 「[0]」)表明地址列表从字节 64 (行 「[2]」)开端。第二行表明搬运数额的列表从字节 416 (行 「[13]」)开端。

3/ 因而,大体上,咱们是希望成对成对地、从上往下、向某个地址发送必定数量的 ETH —— 看起来很直接嘛。

4/ 可是,当咱们开端遍历这个列表,咱们先跳转到 call data 的正确字节,而 Solidity ABI 声明晰数据的榜首个字是整个不定长数组的长度。

5/ 这便是终究 bug 的本源:由于 call dada 中的值是 「0x10」(留意,这可是 16 进制!),可是 call data 只给出了 10 个 地址-数值对。对这个 call data 的正确 ABI 编码(填内行 [2] 和行 [13] 的)应该是 「0xA」 —— 不是 「0x10」!

6/ 你或许现已猜到了那时分会产生什么事,咱们能够经过履行情况盯梢器(execution trace)来 看看。

7/ 合约成功地遍历了前 10 个地址。原本合约应该在此刻中止履行,但依据 call data 的声明,还有许多个地址!那就继续履行吧。

可是,依据 call data 的结构,「第 11 个地址」 是用于编码列表长度的 0x10,所以合约就测验发送 0 ETH 到地址 0x10

8/ 此外,好像,当合约测验读取并不存在的 call data 时,会回来 0 ETH —— 你能够幻想成合约在这里跑出了一个过错,但它却继续发送 0 ETH 到它从 call data 中读取的别的 6 个 「地址」。

此刻,你或许会留意到,0x10 有或许是咱们所谓的 「特别地址」 之一,它彻底在 EVM 预编译合约的范围内(所谓 「预编译合约」,便是一类特别合约,在 EVM 之外有最优的完成,可是编译起来与大多数合约相同)。

而咱们也并不希望预编译合约 0x10 能够回来 ETH 。如此,它就成了一个 ETH 黑洞。可是,这也并不必定形成任何问题。究竟是什么导致了整个客户端溃散?

原因在于,0x10 实践上是一个由 EIP-2537 断语的预编译合约,是为 BLS 配对密码学程序而设的,但这个 EIP 还未布置到主网上。所以尽管你能够跟这个地址互动,但主网上的这个地址里没有任何合约,不会有任何进一步的动作。

此外,咱们还需求一个现实来解说这次割裂,你或许也猜到了,便是 「柏林」 硬分叉(也正是这次硬分叉使这个问题浮出水面):它改变了 EVM 中 Gas 耗费量的计量办法。

在 EIP-2929 施行后,假如你在一笔买卖中对同一个存储槽屡次履行状况存储操作,榜首次履行会耗费更多 Gas,后续履行的耗费会更少。这种重定价理论上能更精确地反映当时的客户端拜访存储项的本钱 ……

并且,要知道,在一切客户端的履行中,这些数据一般都换存在更廉价的硬件层中。

现在咱们总算找到了 OpenEthereum 在区块 #12244294 处产生的 Bug:该客户端包含了一切已完成的预编译,作为 EIP-2929 拜访清单的一部分。(译者注:此处应为 「EIP-2930」)

由于 EIP-2537 在大部分客户端中都现已完成安排妥当了(并且一度有人提议要把它包含在 「柏林」 晋级里边!),OpenEthereum 对一切拜访了 0x10 的买卖都给了 gas 扣头。

但网络的绝大部分活泼客户端都不是这样完成 EIP-2929 的,它们只会给拜访了已激活预编译合约的买卖供给 gas 扣头 —— 而 EIP-2537 归于还未激活的预编译合约!所以,OpenEthereum 客户端对该买卖耗费了多少 Gas 的核算与网络中其他客户端产生了不合。

所幸,@mhswende 很快找出了该 bug,而 @sorpaas 出力修正了该 bug。

还有许多东西可说,我也预期会有比我更能观察到全貌人来编撰更好的时分陈述。

我能说的仅仅,这个 bug 显示了硬分叉的内涵危险,以及继续致力于建造更有弹性的基础设施的重要性。

依赖于 OpenEthereum 客户端的单客户端体系在今日停机了一段时间,由于客户端无法在问题区块呈现后与网络坚持同步。Etherscan 自身也因而停机。

幸亏的是,这个 bug 没有严重到导致严重的链分叉,但这样的或许性并不是不存在。咱们能够使用多客户端完成来提高抗性 —— 多客户端自身便是咱们以太坊生态的一大利益 —— 并推进您的基础设施供给商也这样做。

咱们现已看到,2021 年的遍及速度现已史无前例地快,并且远景十分光亮。咱们要从这个事端中吸取教训,一同打造更好的以太坊。

来历链接:twitter.com

免责声明:作为区块链信息渠道,本站所发布文章仅代表作者个人观点,与链闻 ChainNews 态度无关。文章内的信息、定见等均仅供参考,并非作为或被视为实践出资主张。

[标签:作者]

Published by