Go
Blockchain
Ethereum
geth

GasLimitの計算方法をソースコードレベルで理解する ~go-ethereum~

More than 1 year has passed since last update.

背景

  • 最近、急速にGasLimitが上昇しているというニュースを見て、分散ネットワーク上でどのようにGasLimitを変化させているのかが気になった。
  • GasLimitによるcontractの実行制限を排除する方法を知りたいと思った。
    • [解説1] GasLimitとは、contract実行に必要なGas(ether)の上限値である。GasLimitの存在によって、高負荷なプログラムの実行を防止し、無限ループ等によるnode停止を防いでいる。
    • [解説2] contractとは、ethereum上で動作するアプリケーションである。

ソースコード

go-ethereum/core/block_validator.go
// CalcGasLimit computes the gas limit of the next block after parent.
// The result may be modified by the caller.
// This is miner strategy, not consensus protocol.
func CalcGasLimit(parent *types.Block) *big.Int {
    // contrib = (parentGasUsed * 3 / 2) / 1024
    contrib := new(big.Int).Mul(parent.GasUsed(), big.NewInt(3))
    contrib = contrib.Div(contrib, big.NewInt(2))
    contrib = contrib.Div(contrib, params.GasLimitBoundDivisor)

    // decay = parentGasLimit / 1024 -1
    decay := new(big.Int).Div(parent.GasLimit(), params.GasLimitBoundDivisor)
    decay.Sub(decay, big.NewInt(1))

    /*
        strategy: gasLimit of block-to-mine is set based on parent's
        gasUsed value.  if parentGasUsed > parentGasLimit * (2/3) then we
        increase it, otherwise lower it (or leave it unchanged if it's right
        at that usage) the amount increased/decreased depends on how far away
        from parentGasLimit * (2/3) parentGasUsed is.
    */
    gl := new(big.Int).Sub(parent.GasLimit(), decay)
    gl = gl.Add(gl, contrib)
    gl.Set(math.BigMax(gl, params.MinGasLimit))

    // however, if we're now below the target (TargetGasLimit) we increase the
    // limit as much as we can (parentGasLimit / 1024 -1)
    if gl.Cmp(params.TargetGasLimit) < 0 {
        gl.Add(parent.GasLimit(), decay)
        gl.Set(math.BigMin(gl, params.TargetGasLimit))
    }
    return gl
}

引用元:https://github.com/ethereum/go-ethereum/tree/master/core

パラメータの説明

  • gl: New GasLimit
  • GasLimitBoundDivisor: GasLimitの増減率
    • defined by genesis block
  • contrib: GasLimit増加方向に寄与
    • (parentGasUsed * 3 / 2) / GasLimitBoundDivisor
  • decay: GasLimit減少方向に寄与
    • parentGasLimit / GasLimitBoundDivisor -1

GasLimitの計算方法

  • New GasLimit = parentGasLimit - decay + contrib -> parentGasUsedparentGasLimit * (2/3)の大小関係によって、New GasLimitが増減される
  • MinGasLimit ≦ New GasLimit ≦ TargetGasLimit
    -> MinGasLimitTargetGasLimitの範囲に調整される

GasLimitによるcontract実行制限を解除する

  • MinGasLimitTargetGasLimit(GenesisGasLimit)を十分大きくすれば良い。
  • MinGasLimit,GenesisGasLimitは、genesis.jsonorparams/protocol_params.goで設定する。

まとめ

  • Block生成毎に、GasLimitが再計算される。
  • 前ブロックのGas使用量前ブロックのGasLimit*(2/3)の大小関係によって、New GasLimitが増減される
  • GasLimitによるContractの実行制限を排除したい場合は、MinGasLimitとGenesisGasLimitを十分大きくすれば良い。
  • GasLimitの計算は、consensus protocolではないため、minerが決定することができる。