moon

moon

Build for builders on blockchain
github
twitter

イーサリアム Gas メカニズムの詳細解説 (EIP-1559)

イーサリアムにおける Gas は、スマートコントラクトの実行や取引に必要な測定単位です。これは、ネットワーク内で操作を実行するために必要な計算リソースを表します。Gas は、ネットワークの悪用を防ぎ、取引やスマートコントラクトの実行効率を保証するために使用されます。各操作や取引には Gas 消費があり、ユーザーは Gas 価格を設定してその支払いを行います。Gas のメカニズムは、イーサリアムネットワークの健全な運営を維持するのに役立ち、リソース消費に対する課金を通じてネットワーク負荷を調整します。

イーサリアムネットワークを労働者に例えると、Gas は労働者が提供する労働力です。労働者が仕事を完了した後、労働報酬を支払う必要があります。労働報酬は、単位労働力の価格に提供された総労働力を掛けたものです。単位労働力の価格は GasPrice と呼ばれ、その値はイーサリアムネットワークによって動的に決定されます。したがって、総労働報酬は Gas * GasPrice となります。

GasLimit は、どれだけの労働力に対して支払う意志があるかを理解することができます。もしある作業に 100 の労働力が必要で、あなたが支払う意志があるのが 80 労働力の費用だけであれば、その作業は完了できません。しかし、あなたが 120 労働力の費用を支払う意志がある場合、作業が完了した後に 20 労働力の費用が返金されます。イーサリアムネットワークに例えると、これはその取引に対して最大でどれだけの Gas を支払う意志があるかを示しています。

以下のような取引があります:

transaction

Gas 部分は以下の要素で構成されています:

  • Gas Limit & Usage by Txn: GasLimit と実際に消費された Gas 及びその GasLimit における割合
  • Gas Fees
    • Base: 基本の GasPrice
    • Max: 最大の GasPrice
    • Max Priority: イーサリアムノードのマイナーに支払われる GasPrice
  • Burnt & Txn Savings Fees
    • Burnt: 燃焼された手数料
    • Txn Savings: 取引で節約された費用

Txn Type: 2(EIP-1559): EIP-2718 に基づき、取引タイプが 2 であることを明示し、これは EIP-1559 の取引であることを示します。

BaseFee#

BaseFeeEIP-1559 提案で導入されたメカニズムで、イーサリアムの手数料市場を改善し、ユーザー体験を向上させることを目的としています。BaseFee は各ブロックの基本料金で、自動的に手数料を調整してネットワークの混雑度を反映することを目的としています。

ソースコードにおける BaseFee の計算は以下の通りです:

func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int {
	// 現在のブロックが最初の EIP-1559 ブロックであれば、InitialBaseFee を返す。
	if !config.IsLondon(parent.Number) {
		return new(big.Int).SetUint64(params.InitialBaseFee)
	}

	parentGasTarget := parent.GasLimit / config.ElasticityMultiplier()
	// 親の gasUsed がターゲットと同じであれば、baseFee は変わらない。
	if parent.GasUsed == parentGasTarget {
		return new(big.Int).Set(parent.BaseFee)
	}

	var (
		num   = new(big.Int)
		denom = new(big.Int)
	)

	if parent.GasUsed > parentGasTarget {
		// 親ブロックがターゲットよりも多くのガスを使用した場合、baseFee は増加するべき。
		// max(1, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
		num.SetUint64(parent.GasUsed - parentGasTarget)
		num.Mul(num, parent.BaseFee)
		num.Div(num, denom.SetUint64(parentGasTarget))
		num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
		baseFeeDelta := math.BigMax(num, common.Big1)

		return num.Add(parent.BaseFee, baseFeeDelta)
	} else {
		// そうでなければ、親ブロックがターゲットよりも少ないガスを使用した場合、baseFee は減少するべき。
		// max(0, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
		num.SetUint64(parentGasTarget - parent.GasUsed)
		num.Mul(num, parent.BaseFee)
		num.Div(num, denom.SetUint64(parentGasTarget))
		num.Div(num, denom.SetUint64(config.BaseFeeChangeDenominator()))
		baseFee := num.Sub(parent.BaseFee, num)

		return math.BigMax(baseFee, common.Big0)
	}
}

BaseFee の計算プロセスは以下の通りです:

  • 現在のブロックが最初の EIP-1559 ブロックであれば、InitialBaseFee を返し、その値は 1 Gwei です。

  • parentGasTarget を親ブロックの GasLimit の半分として計算します。

    • 親ブロックの GasUsedparentGasTarget と等しい場合: BaseFee は変わらない。
    • 親ブロックの GasUsedparentGasTarget より大きい場合: BaseFee は増加し、計算は以下の式に従います。
parentBaseFee + max(1, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
  • 親ブロックの GasUsedparentGasTarget より小さい場合: BaseFee は減少し、計算は以下の式に従います。
max(0, parentBaseFee - parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)

ここで:

  • GasUsed: 実際に使用された Gas
  • parentBaseFee は親ブロックの BaseFee に等しい
  • gasUsedDeltaparent.GasUsed - parentGasTarget であり、親ブロックの Gas 実際使用量と目標総量との間の差額です
  • parentGasTarget は親ブロックの GasLimit の半分で、通常は 15000000 です
  • BaseFeeChangeDenominator は定数で、値は 8 です

etherscanブロックリストページ には以下の 2 つのブロックがあります。

blocks

18247918 ブロックでは、以下のことがわかります。

  • BaseFee は 6.79 Gwei に等しい
  • gasUsedDelta / parentGasTarget は -24% に等しく、BaseFee を減少させる必要があることを示しています。

式に従って 18247919 ブロックの BaseFee は以下のように計算されます。

BaseFee=max(0,6.796.790.24/8)=6.5863\mathrm{BaseFee = max(0, 6.79 - 6.79 * 0.24 / 8) = 6.5863}

図示と一致します。

MaxPriorityFee#

MaxPriorityFee は優先手数料です。これは、各単位の Gas に対する追加の加算であり、この部分の費用はマイナーに支払われます。値が大きいほど、取引はより早くパッケージ化されます。GasTracker を通じて、現在の最新の Gas 情報を確認できます。

最終的な GasPriceBaseFeeMaxPriorityFee の合計です。

取引に関して:

transaction

Transaction Fee=GasUsedGasPrice=GasUsed(BaseFee+MaxPriorityFee)=115855(7.407585749+0.05)=863998.597Gwei\begin{aligned} \tt{Transaction\ Fee} & = \tt{GasUsed * GasPrice} \\ &= \tt{GasUsed * (BaseFee + MaxPriorityFee)} \\ &= 115855 * (7.407585749 + 0.05) \\ & = 863998.597\tt{Gwei} \end{aligned}

取引手数料は図中の Transaction Fee フィールド値と一致します。

MaxFee#

MaxFee は最大の GasPrice を意味します。

送信された取引が必ずしも次のブロック内にパッケージ化されるわけではなく、BaseFee は動的に変化します。取引で設定された MaxPriorityFee が低すぎると、取引がパッケージ化されない可能性があります。次のブロックのパッケージ化を待つ必要があります。しかし、次のブロックの BaseFee が以前のものより高い場合、取引が破棄されることになります。高い MaxFee を設定することで、将来の数ブロック内で BaseFee が低すぎるために取引が破棄されないことを保証できます。

労働力の例を引き続き使用します。現在、各単位の労働力の価格(BaseFee)は変動しており、市場によって決定されます。あなたが仕事を発表した後、各単位の労働力に追加報酬(MaxPriorityFee)を支払う意志がある場合、あなたが支払う意志がある報酬が市場価格よりも低い場合、誰もあなたのために働くことを望まないため、あなたが発表した仕事は取り下げられます。したがって、あなたは最大の各単位の労働力価格(MaxFee)を提示し、現在の BaseFeeMaxPriorityFee の合計が MaxFee よりも小さい限り、労働者を募集し続けることができます。各単位の労働力価格は依然として BaseFee + MaxPriorityFee に基づいて計算されます。

通常、MaxFee の計算は以下の式に従います。

MaxFee=(2BaseFee)+MaxPriorityFee\tt{Max Fee = (2 * BaseFee) + MaxPriorityFee}

連続して 6 つのブロックが満たされた Gas の場合でも、メモリプール内で待機し続けることができます。

Burnt#

燃焼された手数料は、この部分の費用をブラックホールアドレスに転送することを意味します。転送される数量は BaseFee によって決定されます。

Burnt=BaseFeeGasUsed\mathtt{Burnt = BaseFee * GasUsed}

上記の取引を例に計算します。

Burnt=BaseFeeGasUsed=7.407585749115855=858205.846950395 Gwei\begin{aligned} \tt{Burnt} & = \tt{BaseFee * GasUsed} \\ & = 7.407585749 * 115855 \\ &= 858205.846950395 \ \tt{Gwei} \end{aligned}

図中の Burnt フィールド値と一致します。

Txn Savings#

取引で節約された費用は、最大の受け入れ可能な取引費用から実際に消費された取引費用を引いたものです。

TxSavingsFees=MaxFeeGasUsed(BaseFee+MaxPriorityFee)GasUsed\tt{Tx Savings Fees = MaxFee * GasUsed - (BaseFee + MaxPriorityFee) * GasUsed}

上記の取引を例に計算します。

TxSavingsFees=MaxFeeGasUsed(BaseFee+MaxPriorityFee)GasUsed=7.657591636115855863998.597=23171.68198878Gwei\begin{aligned} \tt{Tx Savings Fees} & = \tt{MaxFee * GasUsed - (BaseFee + MaxPriorityFee) * GasUsed} \\ & = 7.657591636 * 115855 - 863998.597 \\ & = 23171.68198878 \tt{Gwei} \\ \end{aligned}

図中の Txn Savings フィールド値と一致します。

JSON-RPC#

EIP1559 取引を開始する際、取引に Gas に関連するパラメータを手動で入力する必要があることがよくあります。これらのパラメータは、ノードに対して事前に http リクエストを送信することで取得でき、以下の JSON-RPC メソッドが含まれています。

  • eth_estimateGas
  • eth_maxPriorityFeePerGas
  • eth_getBlockByNumber

eth_estimateGas#

取引をこのインターフェースに送信すると、予測される Gas を取得でき、取引の GasLimit を設定するのに一般的に使用されます。

// Request Payload
{
  "jsonrpc": "2.0",
  "method": "eth_estimateGas",
  "params": [
    {
      "from": "0xD28C383dd3a1C0154129F67067175884e933cf4e",
      "to": "0x7071D6EF9FaF45aA48c22bae7d4a295aD68DC038",
      "value": "0x186a0"
    }
  ],
  "id": 1
}
// Response
{
  "id":1,
  "jsonrpc": "2.0",
  "result": "0x5208" // 21000
}

eth_maxPriorityFeePerGas#

このインターフェースは、現在の最新の MaxPriorityFee を取得するために使用されます。

// Request Payload
{
  "jsonrpc": "2.0",
  "method": "eth_maxPriorityFeePerGas",
  "params": [],
  "id": 1
}
// Response
{
  "jsonrpc": "2.0",
  "result": "0x9b8495", // MaxPriorityFee
  "id": 1
}

eth_getBlockByNumber#

このインターフェースは、ブロック情報を取得するために使用され、その中には BaseFee などの情報が含まれています。

// Request Payload
{
  "jsonrpc": "2.0",
  "method": "eth_getBlockByNumber",
  "params": [
    "latest",
    false
  ],
  "id": 1
}
// Response
{
  "jsonrpc": "2.0",
  "result": {
    "baseFeePerGas": "0x1bc47470a", // baseFee
    "difficulty": "0x0",
    "extraData": "0x546974616e2028746974616e6275696c6465722e78797a29",
    "gasLimit": "0x1c9c380",
    "gasUsed": "0xced6fd",
    "hash": "0xbb9b314d0b8208e655a0afc17384f56f44659a63e3ba4e244609105da497a7d9",
    ...
  },
  "id": 1
}

最新のブロック情報を取得した後、フィールド baseFeePerGas の値が BaseFee です。上記で取得した MaxPriorityFee と組み合わせることで、MaxFee を設定することができます。

Max Fee = (2 * BaseFee) + MaxPriorityFee
読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。