以太坊柏林硬分叉完成 Gas费会受到什么影响?

  • A+
所属分类:比特币挖矿
摘要

雍和比特币

雍和比特币 柏林硬分叉已于 4 月 14 日在主网上线,引进了四份 EIP 。其间的两份 (EIP-2929 和 EIP-2930) 对买卖的 gas 本钱有影响。本文将解说部分 gas 本钱在柏林前是怎么核算的,参加了 EIP-2929 后会怎么改动,以及怎么运用 EIP-2930 引进的拜访列表。关键速览

  • 柏林硬分叉改动一些操作码的 gas 本钱。假定在一个 dapp 或一个智能合约里 gas 费的值是硬编码的,它们或许会间断运转。假定这种状况发生了,且智能合约是不行更新的,顾客将需求用 EIP-2930 的拜访列表才干运用那部分的操作码。
  • 拜访列表能够用作削减少数的 gas 本钱,但实践上它们在一些状况下是会添加总 gas 耗费量的。
  • geth 添加了一个叫 eth_createAccessList 的新 RPC 办法,用以简化拜访列表的创立。

柏林硬分叉前的 gas 本钱EVM 履行的每个操作码都有一笔相关的 gas 本钱。它们大多数的本钱是固定的:PUSH1 总是耗费 3 个单位的 gas,MUL 耗费 5 个,等等。其他一些是会改动的:比方 SHA3 的操作码本钱依赖于它的输入巨细。咱们首要评论操作码 SLOADSSTORE,由于它们是最受柏林硬分叉影响的。咱们以后会评论针对地址的操作码,比方一切的 EXT*CALL* ,由于它们的 gas 本钱也改动了。 柏林前SLOAD 的 gas 本钱 在没有 EIP-2929 之前,SLOAD 的 gas 耗费很简单:它总是耗费 800 gas。所以(现在)没有什么可说的。 柏林前SSTORE 的 gas 本钱 在 gas 耗费方面,SSTORE 或许是最杂乱的操作码了,由于它的本钱取决于像存储 slot 的当时值、新值、以及它是否之前被修正正。咱们仅对一些状况进行剖析以取得一个根本了解;假定你想了解更多,请阅览文末的 EIP 链接。

  • 假定存储 slot 的值从 0 变成 1 (或任何非 0 的值),gas 耗费量是 20000。
  • 假定存储 slot 的值从 1 变成 2 (或任何其他非 0 的值),gas 耗费量是 5000。
  • 假定存储 slot 的值从 1 (或任何非 0 的值) 变成 0,gas 耗费量也是 5000,但在买卖的终究你会取得 1 笔 gas 费返还。本文不会评论 gas 费返还,由于它们在柏林硬分叉中不受影响。
  • 假定存储 slot 的值在之前相同的买卖中被修正了,往后一切 SSTORE 的 gas 耗费量都是 800。

这部分的细节并不风趣,重要的是 SSTORE 很贵,而它的耗费取决于几个要素。 EIP-2929 后的 gas 耗费 EIP-2929 对上述一切操作码的 gas 耗费都有影响。但在深化这些改动前,咱们需求先谈谈这份 EIP 引进的一个重要概念:拜访过的地址 (accessed addresses) 与拜访过的存储密钥 (accessed storage keys)。假定一个地址或一个存储密钥在之前的买卖中被「运用」过,那么它们就会被视为「拜访过的」。例如,当你 CALL(调用)一个其他合约,该合约的地址就会被标为「 accessed (拜访过的)」。同样地,当你 SLOAD(加载)或 SSTORE(存储)一些 slot 的时分,买卖的其他部分也会被视为拜访过的。哪个操作码履行它并不重要:假定一个 SLOAD 读取了一个 slot,接下来的 SLOADSSTORE 都会被视为拜访过的。这儿值得注意的是,存储密钥是「内置于」一些地址的。就如这份 EIP 所解说:「在履行买卖时,保持一组 accessed_addresses: Set[Address]accessed_storage_keys: Set[Tuple[Address, Bytes32]] 」也便是说,当咱们说一个存储 slot 被拜访了,咱们实践上说的一对 (address, storageKey) 被拜访了。接下来谈谈新的 gas 耗费。 柏林后的SLOAD 在柏林硬分叉之前,SLOAD 固定耗费 800 gas。现在,它取决于该存储 slot 是否被拜访过。假定它没有被拜访过,gas 耗费是 2100;假定被拜访过了,则是 100。因而,假定该 slot 是在拜访过的存储密钥列表里的,SLOAD 的 gas 耗费会少于 2000。 柏林后的SSTORE 让咱们在 EIP-2929 语境下重温前面的 SSTORE 比如:假定存储 slot 的值从 0 变成 1 (或任何非 0 的值),gas 耗费量是:

  • 假定存储密钥没有被拜访过,22100
  • 假定被拜访过了,20000

假定存储 slot 的值从 1 变成 2 (或任何其他非 0 的值),gas 耗费量是:

  • 假定存储密钥没有被拜访过,5000
  • 假定被拜访过了,2900

假定存储 slot 的值从 1 (或任何非 0 的值) 变成 0,gas 耗费与上一种状况相同,再加上返还。假定存储 slot 的值在之前相同的买卖中被修正了,往后一切 SSTORE 的 gas 耗费量都是 100。如你所见,假定 SSTORE 正在修正的 slot 是之前被拜访过的,第一个 SSTORE 耗费少于 2100 gas。 总结 下表对上述的值进行了比较:以太坊柏林硬分叉完结 Gas费会遭到什么影响?请注意,在终究一行没有必要议论 slot 是否现已被拜访过,由于假定它之前就被写入,那它就被拜访过了。 EIP-2930: 可选拜访列表买卖 咱们一开端提及的其他 EIP 便是 EIP-2930。这份 EIP 添加了一种新的买卖类,它能够在买卖里参加一个拜访列表。这意味着你能够在买卖履行开端前,事前声明哪些地址和 slot 应被视为拜访过的。例如,一个未被拜访过的 slot 的一个 SLOAD 需求耗费 2100 gas,但假定该 slot 被参加到买卖拜访列表里,同一个操作码只需耗费 100 gas。但假定现已被拜访过的地址或存储密钥会耗费更少 gas,这是否意味着咱们能够把一切东西都添加到买卖拜访列表来下降 gas 耗费了?棒!不必给 gas 费了!可是,不尽然是这样,由于你每次添加地址和存储密钥的时分仍是需求付出 gas 费的。咱们来看一个比如。假定咱们正在向合约 A 发送一笔买卖,拜访列表或许如下:accessList:[{address:"lt;addressofAgt;",storageKeys:["0x0000000000000000000000000000000000000000000000000000000000000000"]}]

假定咱们发送一笔附有这个拜访列表的买卖,运用 slot0x0 的第一个操作码是 SLOAD,它耗费的是 100 而不是 2100 gas。这削减了 2000 gas。但每次把存储密钥添加到买卖的拜访列表中都需求耗费 1900 gas。因而咱们只 了 100 gas。(假定拜访该 slot 的第一个操作码是 SSTORE 而不是 SLOAD,咱们能够 2100 gas,也便是说假定咱们考虑的是存储密钥的耗费的话,咱们一共节 200 gas。)这是否代表只需咱们运用买卖拜访列表就能节 gas?不是的,由于咱们还需求付出添加地址到拜访列表 (即咱们的比如中的 “” ) 的 gas。拜访过的地址到现在为止,咱们只评论了操作码 SLOADSSTORE,但柏林晋级后不是只要这些操作码有改动。例如,操作码 CALL 之前的固定耗费量是 700。但 EIP-2929 后,假定地址不在拜访列表里,它的耗费质变成了 2600,假定在,则是 100。还有,像拜访过的存储密钥,不管之前拜访的是什么操作码 (例如,假定 EXTCODESIZE 是第一次被调用,那么该操作码将耗费 2600 gas,而往后任何运用同一个地址的 EXTCODESIZECALL 仍是 STATICCALL 都只耗费 100 gas)。这是怎么影响有拜访列表的买卖的呢?例如,假定咱们给合约 A 发送一笔买卖,而该合约调用另一个合约 B,那么咱们能够参加这样一个列表:

accessList: [{ address: “”, storageKeys: [] }]

咱们将需求付出 2400 gas 以把这个拜访列表参加到买卖里,但之后运用 B 地址的第一个操作码只耗费 100 gas,而不是 2600。因而,咱们经过这样做节 了 100 gas。假定 B 以某种办法运用它的存储,且咱们知道运用的是哪个密钥,那么咱们也能够把它们参加到拜访列表里,这样能够为每个密钥节 100~200 gas (取决于你的第一个操作码是 SLOAD 仍是 SSTORE )。可是为什么咱们要议论另一个合约?咱们正在调用的合约呢?为什么不对这个合约进行这些操作?

accessList: [ {address: “lt;address of Agt;”, storageKeys: []}, {address: “lt;address of Bgt;”, storageKeys: []},]

咱们能够这样做,但这样不划算,由于 EIP-2929 明确规定正在被调用的合约 (即 tx.to) 地址会默许参加到 accessed_addresses 列表里。因而咱们无须付出剩余的 2400 gas。让咱们再对之前的比如进行剖析:

accessList: [{ address: “lt;address of Agt;”, storageKeys: [ “0x0000000000000000000000000000000000000000000000000000000000000000” ]}]

除非咱们要参加多几个存储密钥,不然这其实很糟蹋。假定咱们预设 SLOAD 总是首要运用存储密钥,那么咱们最少需求 24 个存储密钥能保本。你能够幻想一下,做剖析与手动创立一个拜访列表并不那么风趣。走运的是,其实有更好的办法。eth_createAccessList RPC 办法Geth (从 1.10.2 版别开端 ) 参加了一个新的 eth_createAccessListRPC 办法,你能够用它来生成拜访列表。它的运用与 eth_estimateGas 类似,但它回来的不是 gas 估值,而是像下面这样的成果:

{ “accessList”: [ { “address”: “0xb0ee076d7779a6ce152283f009f4c32b5f88756c”, “storageKeys”: [ “0x0000000000000000000000000000000000000000000000000000000000000000”, “0x0000000000000000000000000000000000000000000000000000000000000001” ] } ], “gasUsed”: “0x8496”}

也便是它给你该买卖会用到的地址与存储密钥的列表,加上拜访列表被参加状况下所耗费的 gas。(像 eth_estimateGas,这是一个估值,当买卖实践上被挖的时分,这个列表或许会改动。)但,这并不代表 gas 耗费量会低于在没有拜访列表状况下发送同一笔买卖所耗费的!我想咱们会跟着时间推移发现运用它的正确办法,但我猜的伪代码如下:

let gasEstimation = estimateGas(tx)let { accessList, gasUsed } = createAccessList(tx)if (gasUsed gt; gasEstimation) { delete accessList[tx.to]}tx.accessList = accessList;ransaction(tx)给合约松绑

值得一提的是,拜访列表的首要意图不在于运用 gas。如 EIP 所解说:「减轻由 EIP-2929 引进的合约开裂危险,由于买卖能够提早指定买卖计划拜访的账户和存储 slot 并提早付出;终究在实践履行中,操作码 SLOADEXT* 只耗费 100 gas:这个低 gas 耗费不只能够避免由该 EIP 引起的开裂,还能够「松开」任何因 EIP-1884 而受限的合约。」这意味着假定一个合约对履行某业务的本钱做了假定,gas 本钱的添加就或许使它中止运作。例如,一个合约调用另一个合约,像这样 someOtherContract.someFunction{gas: 34500}(),由于它假定 someFunction 会精确耗费 34500 gas,这样它会出问题。但假定你添加了一个合理的拜访列表,那么合约会再次运作。自己做查验假定你像自己去测验,仿制这个代码库,里边由多个能够用 Hardhat 和 geth 履行的实例。在 README 检查阐明。原文标题:《柏林硬分叉对 Gas 影响几许?》撰文:Franco Victorio翻译:ETH 中文站

  • 我的微信
  • 这是我的微信扫一扫
  • weinxin
  • 我的微信公众号
  • 我的微信公众号扫一扫
  • weinxin
头像

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

目前评论:0   其中:访客  0   博主  0

    • 头像 币圈子 9

      区块链应用领域: