【完全保存版】EIP-1559(トランザクションの価格設定メカニズム)について学ぼう!
当記事は、EIP-1559を翻訳・編集したものです。
0 シンプルな概要
ブロックごとに固定されたネットワーク手数料を含むトランザクションの価格設定メカニズムで、一時的な混雑に対処するためにブロックサイズを動的に拡大/縮小します。
1 概要
0x02||rlp([chain_id,nonce,max_priority_fee_per_gas,max_fee_per_gas,gas_limit,destination,amount,data,access_list,signature_y_parity,signature_r,signature_s])のフォーマットを持つ新しいEIP-2718トランザクションタイプを紹介します。
プロトコルのガスあたりの基本料金は、親ブロックで使用されたガスと、親ブロックのガス目標(ブロックのガス上限を弾性乗数で割ったもの)の関数である式に従って、ブロックごとに上下します。
このアルゴリズムにより、ブロックがガス目標を上回るとガスあたりの基本料金は増加し、ブロックがガス目標を下回ると減少します。
ガスあたりの基本料金はバーンされます。
トランザクションは、マイナーが自分のトランザクションを含むようにインセンティブを与えるために、ガス当たりの最大手数料を指定します(別名:優先手数料)。
トランザクションはまた、優先手数料とガスあたりのブロックのネットワーク手数料(別名:基本料金)の両方をカバーする、合計で支払っても構わないガスあたりの最大手数料(別名:最大手数料)を指定します。
この2つの手数料の合計額がトランザクションのガスあたりの最大手数料を超えない限り、トランザクションは常にそれが含まれるブロックのガスあたりの基本料金を支払い、トランザクションに設定されたガスあたりの優先手数料を支払います。
2 動機
イーサリアムは歴史的に単純なオークションの仕組みを使って取引手数料の値付けを行っており、ユーザーは入札(「ガス価格」)を添えてトランザクションを送信し、マイナーは最も高い入札額のトランザクションを選択し、組み込まれたトランザクションは指定した入札額を支払っていました。
これはいくつかの大きな非効率の原因となります。
1 取引手数料のボラティリティと取引の社会的コストとのミスマッチ
成熟したパブリック・ブロックチェーン上で、ブロックが満杯になるほどの利用がある取引を含めるための入札は、極めてボラティリティが高くなる傾向があります。
例えば、1ガスあたりのコストが1ナノETHのときと、10ナノETHのときとで、ブロックに1つの追加トランザクションを受け入れるネットワークのコストが10倍になるというのは不合理です。
どちらの場合も、ガスの量は800万ガスから802万ガスへの違いに過ぎません。
2 利用者にとって不必要な遅延
ブロックごとのガス上限が厳しく、取引量の自然な変動もあるため、取引が組み込まれるまで数ブロック待たされることがよくありますが、これは社会的に非生産的です。
ブロックごとの需要差に対応するために、あるブロックを大きくしたり、次のブロックを小さくしたりできる「スラック」メカニズムがないため、誰も大きな利益を得られません。
3 第一価格オークションの非効率性
現在のアプローチでは、トランザクションの送信者が最大手数料を入札したトランザクションを公開し、マイナーが最も高い手数料を支払うトランザクションを選択し、全員が入札額を支払います。
これはメカニズム設計の文献では非常に非効率的であることがよく知られているため、複雑な手数料推定アルゴリズムが必要となります。
しかし、このようなアルゴリズムでさえも、結局はあまりうまく機能しないことが多く、手数料の過払いが頻発することになります。
4 ブロック報酬のないブロックチェーンの不安定性
長い目で見ると、現在発行が行われていないブロックチェーン(BitcoinやZcashなど)は、マイナーへの報酬を完全にトランザクション手数料に依存させる方向に移行しようとしています。
しかし、これには既知の問題があり、大幅な不安定性をもたらす可能性があります。
これは、トランザクション手数料を奪う「シスターブロック」のマイニングを奨励します。
さらに、はるかに強力な自己中心的なマイニング攻撃(Selfish mining)のベクトルを生み出してしまいます。
現時点では、これに対する良い緩和策は存在していません。
5 このEIPでの解決策
このEIPの提案は、ネットワークの混雑度に基づいてプロトコルが上下に調整する基本料金から始めるというものです。
ネットワークがブロックごとの目標ガス使用量を超えると、基本料金はわずかに増加し、容量が目標を下回ると、基本料金はわずかに減少します。
これらの基本料金の変更には制約があるため、ブロックごとの基本料金の最大差は予測可能です。
これにより、ウォレットは信頼性の高い方法でユーザーのガス料金を自動設定することができます。
ネットワークが活発な時期であっても、ほとんどのユーザーはガス料金を手動で調整する必要はないと予想されます。
ほとんどのユーザーにとって、基本料金はウォレットによって推定され、オーファンリスク(例えば1ナノエス)を引き受けるマイナーを補償する少額の優先手数料が自動的に設定されます。
また、ユーザーは手動で取引最大手数料を設定し、総コストを制限することもできます。
この手数料システムの重要な側面は、マイナーが優先手数料のみを取得できることです。
基本料金は常にバーンされます。(つまりプロトコルによって破棄されます)。
これにより、ETHのみがイーサリアム上のトランザクションの支払いに使用されることが保証され、イーサリアムプラットフォーム内でのETHの経済的価値が確固たるものとなります。
また、マイナー抽出可能価値(MEV)に関連するリスクが軽減されます。
さらに、このバーンはイーサリアムのインフレに対抗する一方で、ブロック報酬と優先手数料をマイナーに与えます。
最後に、ブロックのマイナーが基本料金を受け取らないようにすることは、ユーザーからより多くの手数料を引き出すために手数料を操作するマイナーのインセンティブを排除するため重要です。
3 仕様
ブロックの有効性は以下のリファレンス実装で定義されています。
GASPRICE (0x3a) オペコードは、以下の参照実装で定義されているように effective_gas_price を返さなければなりません (MUST)
ちなみに、effective_gas_priceはpriority_fee_per_gasとbase_fee_per_gasの合計です。
こんな感じですね。
こちらは、実際に使われたガスの合計です。
FORK_BLOCK_NUMBER(フォーク時のブロックナンバー) の時点で、新しい EIP-2718 トランザクションが TransactionType 2 で導入されます。
具体的には、21000 + 16 * 非ゼロ calldata バイト + 4 * ゼロ calldata バイト + 1900 * アクセスリストストレージキーカウント + 2400 * アクセスリストアドレスカウントです。
このトランザクションのEIP-2718 TransactionPayloadはrlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list, signature_y_parity, signature_r, signature_s])です。
このトランザクションのsignature_y_parity, signature_r, signature_s要素は、keccak256(0x02 || rlp([chain_id, nonce, max_priority_fee_per_gas, max_fee_per_gas, gas_limit, destination, amount, data, access_list])上のsecp256k1署名を表します。)
このトランザクションの EIP-2718 ReceiptPayload は rlp([status, cumulative_transaction_gas_used, logs_bloom, logs]) です。
3’ コードを読もう
以下、コードを読んでいきます。
一見難しそうですが、一つ一つは決して難しくないですので、お時間があるときに、ぜひ読んでみてください。
また、この章は翻訳者による解説事項になります。
1 レガシータイプとEIP-2930のペイロードについて
ここでは、トランザクションの中で、レガシー(従来の)タイプのクラスとEIP-2930のペイロードのクラスを定義しています。
なお、EIP-2930は『アクセスリスト』についての提案で、ペイロードとは具体的なトランザクションの本体のデータです。
また、データクラス(Data Class)は、Python 3.7から追加された新しいクラスタイプで、主に値を保持するためのクラスを簡単に作成するためのものです。
データクラスは@dataclassデコレータを用いて定義されます。
2 Transaction2930Envelopについて
そして、Transaction2930Envelopというクラスで、どのような構成になるのかを定義しています。
3 EIP1559のペイロード、エンべロップ(封筒)について
続いての、Transaction1559Payloadも同様です。
つまり、このようになりました。
4 Transaction2718について
次は、こちらです。
このようになりました。
5 Transactionについて
同様にして、Transactionはこのようになります。
6 親ブロックのガス上限とガス目標について
まずは、親のブロックのガス上限とガス目標を求めます。
ガス目標とは理想的なガスの使用量であり、ガス上限はその2倍に設定されています。
そのため、ガス上限を2で割り、ガス目標を求めています。
7 親ブロックの基本料金、ガス使用量、トランザクションの取得
次に、親のブロックから、基本料金、ガス使用量を求め、トランザクションを取得します。
8 ガス使用量の確認
こちらでガス使用量が上限値以下であることを確認しています。
9 ガス上限の変化の値の確認
次に、ガス上限が親のガス上限から適度に変化していることを確認しています。
具体的には、1,024分の1未満の変化に抑えられていることを確認しています。
10 ガス上限の下限値の確認
次に、ガス上限が5,000以上であることを確認しています。
11 分岐と、期待される基本料金の作成
次に、親のブロックのガス使用量に応じて、分岐をおこなっています。
ちなみに、途中で切れてしまっていますが、親ブロックの使用ガス量がガス目標より大きい場合は、最大で12.5%増加します。
逆に少ない場合は、最大で12.5%減少します。
12 ブロックの累積ガス使用量について
まず、こちらはブロック内の全てのトランザクションで使用されるガスの合計が入ることになります。
まずは初期化として0を入れます。
13 トランザクションの正規化について
次にブロック何に入っている全てのトランザクションで回していきます。
まず、正規化がされていないトランザクションについて、「validate_and_recover_signer_address」でトランザクションの署名を検証して、アドレスを求めます。
13ー1 署名者ウォレットアドレスの導出について
デジタル署名から署名者の公開鍵を導き出し、それからEthereumアドレスを計算するというプロセスを指します。
具体的には以下の手順で行われます。
デジタル署名とトランザクションデータを用いて、送信者の公開鍵を計算(回復)します。このステップは暗号学的な手法を用います。
そして、公開鍵から送信者のEthereumアドレスを計算します。これは公開鍵をKeccak-256ハッシュ関数に通し、その出力の最後の20バイトを取ることで得られます。
以上の操作により、「トランザクションの送信者(署名者)のアドレスの回復」が行われます。
この操作は、トランザクションが本当にその署名者から発行されたものであると確認するための重要なステップです。
13ー2 トランザクションの正規化について
次に、正規化されていないトランザクションと署名者のアドレスを用いて、正規化を行います。
正規化とは、トランザクションのデータ構造を一定の形式に整えることで、後続の処理や検証を容易にするためのものです。
14 署名者情報の取得について
上で取得した署名者のアドレスを用いて、署名者の情報を取得しています。
15 送付Ether量の確認について
次に、署名者のバランスから、署名者が送ろうとしているEtherの量を引きます。
その上で引いた後の残高が0以上であることを確認しています。
16 残高が想定最大のガス代以上であることの確認
次に、残高が、ガスの最大量×最大ガス価格よりも大きいことを確認します。
これにより、ガス代が高くなってもトランザクションを実行できることが確認できます。
17 最大手数料の基本料金以上であることの確認
次に、トランザクションの最大手数料がブロックの基本料金以上であることを確認します。
ブロックの基本料金は上下するため、それ以上の手数料を支払えるかを確認します。
18 最大ガス価格、最大優先手数料のオーバーフローの確認
次は最大ガス価格、最大優先価格が2の256乗未満であることを確認しています。
イーサリアムでは256ビットが一般的に使用される長さです。
そのため、これを超えてオーバーフローしないようにするための確認です。
19 最大ガス価格 ≧ 最大優先手数料の確認
次に、最大ガス価格が最大優先手数料以上であることを確認しています。
20 優先手数料の取得について
次に、優先手数料を求めています。
最大優先手数料か(最大手数料ー基本料金)のうち、小さい方になります。
21 エフェクティブガス価格の取得について
次に、エフェクティブガス価格を求めます。
これは実際に払うガス価格です。
優先手数料と基本料金の合計で求めます。
22 エフェクティブガス価格を利用した残高確認について
エフェクティブガス価格が求まったので、ガス上限と組み合わせて、必要最大のガス価格を差し引きます。
その結果が0以上であることを確認します。
23 トランザクションの実行と使われたガス代の取得について
署名者が十分なガス代を持っていることが確認できたので、「execute_transaction」でトランザクションの実行を行います。
結果として、使用されたガス代を取得します。
24 返却分のガスの取得と累積のトランザクションガス使用量の設定について
続いて、ガス上限から使用されたガスを引いて、返却分のガスを求めます。
また、累積のトランザクションガス使用量に使用されたガス量を入れます。
25 未使用分のガス代の返却について
トランザクションの署名者に未使用分のガス代を返却します。
26 マイナーへの優先手数料分の支払いについて
そして、ブロックの作成者に、使用した分のガス量 × 優先手数料を払います。
27 ブロック内のガス代合計の確認について
全てのトランザクションを実行した後、ブロックで使用されたガス代とトランザクションで使用されたガス代の合計が等しいことを確認します。
28 トランザクションの正規化関数について
こちらは「normalize_transaction」関数についてです。
トランザクションのクラスの種類に応じて、正規化した上で戻しています。
該当するものがない場合は、エラーを発生させています。
29 親ブロック、そのブロックハッシュの取得関数について
こちらで、ブロックを渡した時に、その親ブロック、ブロックハッシュを求める抽象メソッドを示しています。
30 ブロック何のトランザクション取得関数について
「transactions」では、ブロックを渡した時に、ブロック内の一連のトランザクションを取得します。
31 正規化トランザクションの実行関数について
こちらの「execute_transaction」で正規化されたトランザクションの実行を行い、そのガス使用量を返します。
32 トランザクションの検証・アドレス回復関数について
こちらの「validate_and_recover_signer_address」ではトランザクションの検証を行い、署名者のアドレスを返しています。
33 アカウント情報取得関数について
最後に、「account」関数では、引数として渡したアドレスのアカウントの情報を取得します。
今回のケースでは、その取得した情報の残高を主に使用していました。
4 後方互換性
レガシーなEthereumのトランザクションは、新しい価格システムから直接恩恵を受けることはありませんが、引き続きブロックに含まれ続けます。
これは、レガシートランザクションから新しいトランザクションへのアップグレードにより、レガシートランザクションの gas_price が base_fee_per_gas と priority_fee_per_gas のどちらかに完全に消費されるためです。
1 ブロックハッシュの変更
ブロックハッシュを計算するために keccak256 に渡されるデータ構造が変わります。
ブロックの内容を確認したり、ブロックが有効であることを検証したりするすべてのアプリケーションは、新しいデータ構造(追加の項目が1つ)をサポートするように調整する必要があります。
ブロックヘッダのバイトを取得してハッシュ化するだけなら、引き続き正しいハッシュを得られますが、その構成要素からブロックヘッダを作成する場合は、最後に新しい項目を追加する必要があります。
2 GASPRICE
この変更前まで、GASPRICEはトランザクションに対して署名者がガスあたりで支払うETHとマイナーが受け取るETHの両方を表していました。
この変更後、GASPRICEは署名者がガスあたりで支払うETHの量を表すだけになり、トランザクションに対してマイナーが受け取った額はもはやEVMで直接アクセスできなくなります。
5 セキュリティ上の考慮事項
1 最大ブロックサイズ/複雑さの増加
このEIPは最大ブロックサイズを増加させますが、マイナーがブロックを十分速く処理できない場合、空のブロックをマイニングすることを強制される可能性があります
しかしながら、時間と共に平均ブロックサイズはこのEIPがない場合と同じくらいになると予測されているため、ブロックサイズの急激な増加は短期間だけの問題であるとされています。
しかし、一部のクライアントはこの短期的なサイズの増加をうまく処理できず、エラーを引き起こす可能性があると警告しています(たとえば、メモリ不足など)。
そのため、各クライアントの実装者は、自分たちのクライアントが最大サイズのブロックも適切に処理できるようにする必要があると提言しています。
2 トランザクションの順序付け
ほとんどの人が優先手数料で競争せず、基本料金を使って取引を含めるようになると、トランザクションの順序付けは個々のクライアントの内部実装の詳細、たとえばトランザクションをメモリ内にどのように格納するかなどに依存するようになります。
攻撃者が大量のトランザクションを保留プールに投げ込むスパム攻撃からネットワークを保護するために、同じ優先手数料を持つトランザクションは受信した時間でソートすることを推奨します。
マイナーは、純粋に自己中心的なマイニングの観点から、より高いガスプレミアムを持つトランザクションを、より低いガスプレミアムを持つものよりも優先すべきです。
3 マイナーが空のブロックをマイニングする
基本料金が非常に低くなるまでマイナーが空のブロックを採掘し、その後半分程度のブロックを採掘して優先手数料でトランザクションをソートし直す可能性があります。
この攻撃は可能ですが、マイニングが分散化されている限り、これは特に安定した均衡ではありません。
この戦略から逸脱する任意のマイナー(正規のマイナー)は、攻撃が続いている間(基本料金が0になった後でさえも)、攻撃に参加しているマイナーよりも利益を得ることになります。
カルテルから匿名で逸脱できる任意のマイナーがいて、特定のマイナーが逸脱したことを証明する方法がないため、この攻撃を実行する唯一の実行可能な方法は、ハッシュパワーの50%以上をコントロールすることです。
攻撃者がハッシュパワーのちょうど50%を持っていた場合、彼らは優先手数料からEtherを得ることはなく、逸脱者は優先手数料からEtherを2倍得ることになります。
攻撃者が利益を得るためには、ハッシュパワーの50%以上を持つ必要がありますが、これはダブルスペンド攻撃を行うか、単に他のマイナーを無視する方がはるかに利益を得る戦略になります。
マイナーがこの攻撃を試みる場合、私たちは単に弾性乗数(現在は2倍)を増加させることができます。
これにより、攻撃が理論的に逸脱者に対して利益を上げることができる前に、さらに多くのハッシングパワーが必要になります。
4 ETHバーンにより供給量が固定できない
基本料金をバーンすることにより、固定されたEther供給量を保証することができなくなります。
これにより、長期的にETHの供給量が一定でないため、経済的な不安定さが生じる可能性があります。
これは有効な懸念ですが、どれだけ影響を与えるかを定量化することは難しいです。
基本料金でより多くがバーンされるとETHはデフレとなり、マイニング報酬でより多くが生成されるとETHはインフレとなります。
私たちはユーザーのブロックスペースに対する需要を制御できないため、現時点ではETHがインフレかデフレになるかを確定することはできません。
したがって、この変更により、コア開発者はEtherの長期的な数量を一部制御できなくなります。
6 著作権
CC0により、著作権および関連する権利が放棄されています。