用于设置账户存储项的操作码 SSTORE 的消耗是:1)将零值改为非零值时,消耗 20000 gas;2)将零值变成零值,或非零值变非零值,消耗 5000 gas;3)将非零值变成零值,消耗 5000 gas;此外,交易执行成功(即未耗尽 gas 交易就执行完了)后会退回 15000 gas。退款金额上限是交易消耗 gas 总额的 50%。这给了人们小小激励去清除存储项。我们注意到,正因为缺乏这样的激励,许多合约的存储空间没有被有效使用,从而导致了存储数据的快速膨胀。这一设计既能提供 “为存储项持续收取租金” 模式的大部分好处,又不会失去合约一旦确立就可以永久存在的保证。延迟退款机制是必要的,因为可以阻止拒绝服务攻击:攻击者可以发送一笔含有少量 gas 的交易,循环清除大量的存储项,直到用光 gas,这样消耗了大量的验证算力,但实际并没有真正清除存储,也不需要付出很多 gas。50% 的上限的是为了确保打包交易的矿工依然能够确定执行交易的计算时间的上限。 (校对注:首先,SSTORE 等状态访问操作码的 gas 消耗量已经随着以太坊的硬分叉而多次更改。截至 2021 年 7 月,最新的数值可见《柏林升级内容概览》;在可预见的未来,这个操作码的数值还会继续变化;其次,这里的 gas refund 机制,事后证明并没有启动缓解状态数据的膨胀问题,反而恶化了该问题,因为人们可以在 gas price 较低时写入大量垃圾数据,在 gas price 较高时清除这些数据来获得 gas,这就是 “GasToken” 的原理。当前已确定,在 “伦敦” 分叉中会改变 gas refund 机制,见《以太坊 “伦敦” 升级预览》。) 合约提供的消息数据是没有成本的。因为在消息调用期间不需要实质复制任何数据,调用数据(call data)可以简单地视为指向父合约 memory 的指针,该指针在子进程执行时不会改变。 Memory 是一个可以无限扩展的数组,然而,每扩展 32 字节的 memory 就会消耗 1 gas 的成本,不足 32 字节以 32 字节计。(校对注:memory 一般译为内存,但在以太坊的语境下,它是 EVM 由于存储数据的三种类型之一,因此都不译,以示其特殊性。) 某些操作码的计算时间极度依赖参数,gas 开销计算是动态变化的。例如,EXP 的的开销是指数级别的(10 gas + 10 gas/字节,即,x^0 = 1 gas、x^1 … x^255 = 2 gas、x^256 … x^65535 = 3 gas,等等)。复制操作码(如:CALLDATACOPY, CODECOPY, EXTCODECOPY)的开销是 1 gas + 1 gas/32 字节(四舍五入;LOG 操作码的规则也类似)。Memory 扩展的开销不包含在这里。如若包含,会变成一个平方攻击向量(50000 次的 CALLDATACOPY,每次消耗 50000 gas,则其计算量应是 50000^2,但如果不使用动态收费规则,就只需付出 ~50000 gas)。 (责任编辑:admin) |