イーサリアムにおける Gas
は、スマートコントラクトの実行や取引に必要な測定単位です。これは、ネットワーク内で操作を実行するために必要な計算リソースを表します。Gas
は、ネットワークの悪用を防ぎ、取引やスマートコントラクトの実行効率を保証するために使用されます。各操作や取引には Gas
消費があり、ユーザーは Gas
価格を設定してその支払いを行います。Gas
のメカニズムは、イーサリアムネットワークの健全な運営を維持するのに役立ち、リソース消費に対する課金を通じてネットワーク負荷を調整します。
イーサリアムネットワークを労働者に例えると、Gas
は労働者が提供する労働力です。労働者が仕事を完了した後、労働報酬を支払う必要があります。労働報酬は、単位労働力の価格に提供された総労働力を掛けたものです。単位労働力の価格は GasPrice
と呼ばれ、その値はイーサリアムネットワークによって動的に決定されます。したがって、総労働報酬は Gas * GasPrice
となります。
GasLimit
は、どれだけの労働力に対して支払う意志があるかを理解することができます。もしある作業に 100 の労働力が必要で、あなたが支払う意志があるのが 80 労働力の費用だけであれば、その作業は完了できません。しかし、あなたが 120 労働力の費用を支払う意志がある場合、作業が完了した後に 20 労働力の費用が返金されます。イーサリアムネットワークに例えると、これはその取引に対して最大でどれだけの Gas
を支払う意志があるかを示しています。
以下のような取引があります:
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#
BaseFee
は EIP-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
の半分として計算します。- 親ブロックの
GasUsed
がparentGasTarget
と等しい場合:BaseFee
は変わらない。 - 親ブロックの
GasUsed
がparentGasTarget
より大きい場合:BaseFee
は増加し、計算は以下の式に従います。
- 親ブロックの
parentBaseFee + max(1, parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
- 親ブロックの
GasUsed
がparentGasTarget
より小さい場合:BaseFee
は減少し、計算は以下の式に従います。
max(0, parentBaseFee - parentBaseFee * gasUsedDelta / parentGasTarget / baseFeeChangeDenominator)
ここで:
GasUsed
: 実際に使用されたGas
parentBaseFee
は親ブロックのBaseFee
に等しいgasUsedDelta
はparent.GasUsed - parentGasTarget
であり、親ブロックのGas
実際使用量と目標総量との間の差額ですparentGasTarget
は親ブロックのGasLimit
の半分で、通常は 15000000 ですBaseFeeChangeDenominator
は定数で、値は 8 です
etherscan
の ブロックリストページ には以下の 2 つのブロックがあります。
18247918 ブロックでは、以下のことがわかります。
BaseFee
は 6.79 Gwei に等しいgasUsedDelta / parentGasTarget
は -24% に等しく、BaseFee
を減少させる必要があることを示しています。
式に従って 18247919 ブロックの BaseFee
は以下のように計算されます。
図示と一致します。
MaxPriorityFee#
MaxPriorityFee
は優先手数料です。これは、各単位の Gas
に対する追加の加算であり、この部分の費用はマイナーに支払われます。値が大きいほど、取引はより早くパッケージ化されます。GasTracker を通じて、現在の最新の Gas
情報を確認できます。
最終的な GasPrice
は BaseFee
と MaxPriorityFee
の合計です。
取引に関して:
取引手数料は図中の Transaction Fee
フィールド値と一致します。
MaxFee#
MaxFee
は最大の GasPrice
を意味します。
送信された取引が必ずしも次のブロック内にパッケージ化されるわけではなく、BaseFee
は動的に変化します。取引で設定された MaxPriorityFee
が低すぎると、取引がパッケージ化されない可能性があります。次のブロックのパッケージ化を待つ必要があります。しかし、次のブロックの BaseFee
が以前のものより高い場合、取引が破棄されることになります。高い MaxFee
を設定することで、将来の数ブロック内で BaseFee
が低すぎるために取引が破棄されないことを保証できます。
労働力の例を引き続き使用します。現在、各単位の労働力の価格(BaseFee
)は変動しており、市場によって決定されます。あなたが仕事を発表した後、各単位の労働力に追加報酬(MaxPriorityFee
)を支払う意志がある場合、あなたが支払う意志がある報酬が市場価格よりも低い場合、誰もあなたのために働くことを望まないため、あなたが発表した仕事は取り下げられます。したがって、あなたは最大の各単位の労働力価格(MaxFee
)を提示し、現在の BaseFee
と MaxPriorityFee
の合計が MaxFee
よりも小さい限り、労働者を募集し続けることができます。各単位の労働力価格は依然として BaseFee + MaxPriorityFee
に基づいて計算されます。
通常、MaxFee
の計算は以下の式に従います。
連続して 6 つのブロックが満たされた Gas
の場合でも、メモリプール内で待機し続けることができます。
Burnt#
燃焼された手数料は、この部分の費用をブラックホールアドレスに転送することを意味します。転送される数量は BaseFee
によって決定されます。
上記の取引を例に計算します。
図中の Burnt
フィールド値と一致します。
Txn Savings#
取引で節約された費用は、最大の受け入れ可能な取引費用から実際に消費された取引費用を引いたものです。
上記の取引を例に計算します。
図中の 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