访问过的地址 到目前为止,我们只讨论了操作码SLOAD和SSTORE,但柏林升级后不是只有这些操作码有变化。例如,操作码CALL之前的固定消耗量是700。但EIP-2929后,如果地址不在访问列表里,它的消耗量变成了2600,如果在,则是100。还有,像访问过的存储密钥,无论之前访问的是什么操作码(例如,如果EXTCODESIZE是第一次被调用,那么该操作码将消耗2600 gas,而往后任何使用同一个地址的EXTCODESIZE、CALL还是STATICCALL都只消耗100 gas)。 这是如何影响有访问列表的交易的呢?例如,假如我们给合约A发送一笔交易,而该合约调用另一个合约B,我们将需要支付2400 gas以把这个访问列表加入到交易里,但之后使用B地址的第一个操作码只消耗100 gas,而不是2600。因此,我们通过这样做节省了100 gas。如果B以某种方式使用它的存储,且我们知道使用的是哪个密钥,那么我们也可以把它们加入到访问列表里,这样可以为每个密钥节省100~200 gas(取决于你的第一个操作码是SLOAD还是SSTORE)。 但是为什么我们要谈论另一个合约?我们正在调用的合约呢?为什么不对这个合约进行这些操作? 我们可以这样做,但这样不划算,因为EIP-2929明确规定正在被调用的合约(即tx.to)地址会默认加入到accessed_addresses列表里。因此我们无须支付多余的2400 gas。 除非我们要加入多几个存储密钥,否则这其实很浪费。如果我们预设SLOAD总是首先使用存储密钥,那么我们起码需要24个存储密钥能保本。 你可以想象一下,做分析与手动创建一个访问列表并不那么有趣。幸运的是,其实有更好的方法。 eth_createAccessList RPC方法 Geth(从1.10.2版本开始)加入了一个新的eth_createAccessList RPC方法,你可以用它来生成访问列表。它的使用与eth_estimateGas相似,但它返回的不是gas估值。 也就是它给你该交易会用到的地址与存储密钥的列表,加上访问列表被加入情况下所消耗的gas。(像eth_estimateGas,这是一个估值,当交易实际上被挖的时候,这个列表可能会改变。)但,这并不代表gas消耗量会低于在没有访问列表情况下发送同一笔交易所消耗的! 我想我们会随着时间推移发现使用它的正确方法。 给合约松绑 值得一提的是,访问列表的主要目的不在于使用gas。如EIP所解释: 减轻由EIP-2929引入的合约断裂风险,因为交易可以提前指定交易计划访问的账户和存储slot并提前支付;最终在实际执行中,操作码SLOAD和EXT*只消耗100 gas:这个低gas消耗不仅可以防止由该EIP引起的断裂,还可以“松开”任何因EIP-1884而受限的合约。 这意味着如果一个合约对执行某事务的成本做了假设,gas成本的增加就可能使它停止运作。例如,一个合约调用另一个合约,像这样someOtherContract.someFunction{gas:34500}(),因为它假设someFunction会准确消耗34500 gas,这样它会出问题。但如果你添加了一个合理的访问列表,那么合约会再次运作。 (责任编辑:admin) |