以太坊小知识(六)——refund gas计算

准备知识

以太坊黄皮书拜占庭版本中编号为65的公式刻画了单个交易执行结束后,总的可返还的gas的计算方法。
以太坊小知识(六)——refund gas计算_第1张图片
refund gas就是要计算等式右边第二个项,即min( , )。
其中Ar的含义如下【在黄皮书6.1节】:
以太坊小知识(六)——refund gas计算_第2张图片
下面的代码是geth(core/state_transition.go)中对编号为65的公式的实现:

func (st *StateTransition) refundGas() {
   // Apply refund counter, capped to half of the used gas.
   refund := st.gasUsed() / 2
   if refund > st.state.GetRefund() {
      refund = st.state.GetRefund()
   }
   st.gas += refund

   // Return ETH for remaining gas, exchanged at the original rate.
   remaining := new(big.Int).Mul(new(big.Int).SetUint64(st.gas), st.gasPrice)
   st.state.AddBalance(st.msg.From(), remaining)

   // Also return remaining gas to the block gas counter so it is
   // available for the next transaction.
   st.gp.AddGas(st.gas)
}

何时触发refund?

在拜占庭版本的黄皮书规范中,只有SELFDESTRUCTSSTORE[x] = 0这两个opcode会触发refund。单个交易执行结束时,累计refund的gas量不能超过当前交易执行上下文的消耗的gasUsed的一半。

示例

假设您发起消息调用,调用一个函数,将初值为0的变量x设值为1

简化过后【例如,不考虑压栈的gas消耗】,消耗的gas成本如下:

  • 交易指定的gasLimit100,000 gas 每个交易(message call)使用的Gas21,000
  • 执行SSTORE消耗20,000 gasx=1,将storage slotzero变为nonzero
  • 总成本为21,000+20,000=41,000 gas,剩下59,000 gas
  • refund counter = 0 gas 【因为没有触发那两个opcode
  • refunded amount =59,000 + min(100,000 - 41,000/2,0)=59,000

现在,发起消息调用,在交易中调用函数将x置为0,简化过后,成本如下:

  • 设交易设置的gasLimit100,000
  • 交易消耗21,000 gas
  • x=0消耗5000 gas
  • 剩余gas= 100,000 - (21,000 + 5,000) = 74,000 refund counter = 15,000 gas
  • 总的返还的gas = 74,000 + min(13,000, 15,000) = 74,000 + 13,000,其中13,000usedGas=(100,000 -74,000)/2

参考资料

  • https://ethereum.stackexchange.com/questions/45999/refunding-gas-fomula-in-ethereum-yellow-paper/46009#46009

  • https://ethereum.stackexchange.com/questions/594/what-are-the-limits-to-gas-refunds

你可能感兴趣的:(Ethereum)