SSTORE 都消耗 800 gas细节在这里并不重要,重要的是,SSTORE 是昂贵的,具体消耗多少 gas 则依赖于多个因素。 EIP-2929 之后的 Gas 消耗量EIP-2929 改变了所有这些数值。但在展开之前,我们要先谈谈该 EIP 引入的一个重要概念:被访问过的地址和被访问过的存储项的键(storage key)。 当一个地址或者一个存储项的键,在一笔事务中被 “使用过” 之后,在该笔交易余下的执行过程中,这个地址(或者这个键)都会被当成 “已被访问过的”。举个例子,如果你在一笔事务中 CALL (调用)另一个合约,那么该合约的地址就会被标记为 “访问过的”。类似地,如果你 SLOAD 或者 SSTORE 过一些存储项槽 ,在该笔事务余下的执行过程里,这些槽也会被当成已经访问过的。到底用的哪个操作码是没有关系的,即使你只 SLOAD 过某个槽,接下来使用 SSTORE 时该槽也会被当成已访问过的。 注意:存储项的键是 “内在于” 某些地址中的,一如该 EIP 所解释的: 也就是说,当我们说某个存储槽已被访问过了,我们的实际意思是:(address, storageKey) 已被访问过了。 搞清楚了这个概念,我们来谈谈新的 Gas 消耗量计算模式。 「柏林」以后的 SLOAD 升级前,SLOAD 的 Gas 消耗量是固定的 800。但升级后,Gas 消耗量要看这个存储槽是否已经被访问过。还没访问过的,消耗量就是 2100 gas;访问过的,就是 100 gas。所以,如果某个存储项槽已经在 “已访问过的存储项键 ` 的集合里了,就可以省掉 2000 gas。 「柏林」以后的 SSTORE 我们逐个逐个对比下,在 EIP-2929 实施后,上面的几个例子会发生什么样的变化: 如果存储项的值从 0 改为 1 (或者任意非零的值),Gas 消耗量是 20000 如果存储项的值从 1 改为 2 (或者任意非零的值),Gas 消耗量是 5000 如果该存储项键还未访问过,消耗 5000 gas 若已访问过,消耗 2900 gas
如果存储项的值从 1 (或任意非零的值) 改为 0,消耗量保持不变,gas 返还机制也不变 在一笔事务中,如果存储项已不是第一次修改,则后续每一次 SSTORE 都消耗 100 gas
由此可见,如果某个槽此前已访问过,则对它的第一次 SSTORE 操作会节约 2100 gas (相比于从未访问过)。 汇总一下上面的文字实在啰嗦,我们就直接做一张表,把上面提到的值都汇总一下:
(责任编辑:admin) |