这里需要注意的一点是,存储密钥位于某个地址的“内部”。正如EIP所解释的: “执行事务时,维护一组accessed_addresses: Set[Address] 和 accessed_storage_keys: Set[Tuple[Address, Bytes32]]”也就是说,当我们说一个存储slot被访问时,我们实际上是说一对(address, storageKey)被访问了。 话虽如此,我们还是来谈谈新的gas成本吧。 柏林硬分叉之后的SLOAD在柏林硬分叉之前,SLOAD的固定成本是800 gas,现在,这取决于是否已访问了存储slot。如果未访问,则成本为2100 gas,如果已访问,则成本为100 gas。因此,如果slot在已访问的存储密钥列表中,则一次SLOAD的成本会降低2000 gas。 柏林硬分叉之后的SSTORE让我们在部署EIP-2929的环境下回顾一下之前的SSTORE示例: 如果slot的值从0更改为1(或任何非零值),则成本为:22100(如果未访问存储密钥),20000(如果已访问存储密钥);如果slot的值从1更改为2(或任何其他非零值),则成本为:5000(如果未访问存储密钥),2900(如果已访问存储密钥);如果slot的值从1(或任何非零值)更改为0,则成本与上一项相同,然后加上退款;如果以前在同一交易中修改了该值,则所有后续SSTORE的成本为100;如你所见,如果要修改的slot以前被访问过,那么第一次SSTORE的成本将降低2100 gas。 下面的表总结了目前为止所有改变的值: 请注意,在最后一行中,谈论是否访问了slot是没有意义的,因为如果它以前被写入过,则表明其也被访问过。 EIP-2930 我们在文章开头提到的另一个EIP就是EIP-2930,这个改进提案添加了一种新类型的事务,该事务可以在事务负载中包括访问列表。这意味着你可以在事务开始执行之前预先声明哪些地址和slot应被视为是已访问的。例如,一个未访问slot的SLOAD成本为2100,但是如果该slot包含在事务的访问列表中,则相同的操作码成本就为100。 但是,如果当地址或存储密钥已被访问时,gas成本变更低了,这是否意味着我们可以将所有内容添加到事务的访问列表中并降低gas成本呢?不完全是这样,因为你还需要为添加的每个地址和每个存储密钥支付gas。 让我们看一个例子,假设我们正在向合约A发送一笔交易,访问列表可能如下所示: 如果我们用这个访问列表发送了一笔交易,并且第一个使用0x0 slot的操作码是SLOAD,则它将花费100 gas(而不是2100 gas),这就降低了2000 gas的消耗量。但事务访问列表中包含的每个存储密钥的成本为1900 gas,所以我们只省了100 gas。(如果访问该slot的第一个操作码是SSTORE,那么我们将节省2100 gas,这意味着如果考虑到存储密钥的成本,我们总共将节省200 gas。) (责任编辑:admin) |