ブロック
最終編集者: @HiroyukiNaito(opens in a new tab), 2024年5月26日
ブロックとは、チェーンの1つ前のハッシュとトランザクションのバッチのことです。 ハッシュはブロックデータから暗号的に生成されるため、チェーンのブロックはお互いに繋がっています。 前のブロックのハッシュを用いるため、どれかのブロックが改ざんされるとデータの整合性が取れなくなるため、ブロックチェーンを実行しているすべての人が改ざんに気づくことになります。
前提知識
この記事は初心者向けに記載していますが、 より理解を深めるために、まずアカウント、トランザクションそしてイーサリアムの導入を読むことをお勧めします。
ブロックを使用する背景
ブロックはすべてのイーサリアムネットワークへの参加者が同期された状態を維持し、トランザクションの正確な履歴に同意できるように、複数のトランザクションをブロックにバッチとして格納します。 これは、何十件(もしくは数百) ものトランザクションが一度にコミット、合意、同期されることを意味します。
イーサリアムEVM(opens in a new tab)からの図解
コミットの間隔をあけ、すべてのネットワーク参加者がコンセンサスに至るまでの十分な時間を確保しています。たとえトランザクション要求が毎秒数十回発生したとしても、ブロックはイーサリアム上で12秒に1回生成され、コミットされます。
ブロックの仕組み
トランザクション履歴を保持するため、ブロックは厳密に順序付けられ、作成されたすべての新規ブロックに親ブロックへの参照(ハッシュ)が含まれます。 同様に、ブロック内のトランザクションも厳密に順序付けられています。 まれな例外を除き、 常時ネットワーク上のすべての参加者は、正確な数のブロックとその履歴に合意しており、現在のトランザクションリクエストを次のブロックにバッチ処理しています。
ランダムに選ばれたバリデータがブロックをまとめると、そのブロックは残りの他のネットワークに伝播されます。すべてのノードはこのブロックをブロックチェーンの最後尾に追加します。そして、新しいバリデータが選ばれ、次のブロックを生成します。 このブロック生成とコミットメント/コンセンサスプロセスは、現在イーサリアム「プルーフ・オブ・ステーク (PoS) 」プロトコルによって定義されています。
プルーフ・オブ・ステーク(PoS)プロトコル
プルーフ・オブ・ステークとは、以下のことを意味します。
- 検証を行うノードは、不正行為をしない担保として、デポジットコントラクトに32 ETHのステーキングが必要。 明らかに不誠実な行為を行うと、担保のステーキングの一部またはすべてが失うことになるため、ネットワークの保護を目的としている。
- すべてのスロット(12秒間隔)において、ランダムに1つのバリデータがブロックの提案者として選出される。 選ばれたバリデータが、トランザクションを1つにまとめ、実行し新たな「状態」を決定し、 この情報をブロックに格納し、他のバリデータに渡す。
- 新しいブロックに関する情報を受け取った他のバリデータは、トランザクションを再実行し、グローバル状態への変更提案について同意することを確認する。 ブロックが有効であった場合、それを自分のデータベースに追加する。
- バリデータが同一スロットで2つの競合するブロックの情報を受け取った場合は、フォーク・チョイス・アルゴリズムを使用して、最も多額のETHステーキングにより支持されている方を選択する。
ブロックが保持するパラメータ
ブロックにはたくさんの情報が含まれており、 大まかには、以下のようなフィールドがあります。
フィールド | 説明 |
---|---|
スロット (slot) | ブロックが所属するスロット |
proposer_index | ブロックを提案するバリデータのID |
parent_root | 先行ブロックのハッシュ値 |
state_root | 状態オブジェクトのルートハッシュ |
規格の概要 | 以下に定義されているように、複数のフィールドを含むオブジェクト |
ブロックのbody
には独自のフィールドがいくつかあります。
フィールド | 説明 |
---|---|
randao_reveal | 次のブロック提案者の選択に使用される値 |
eth1_data | デポジットコントラクトの情報 |
グラフィティ | ブロックのタグ付けに使われる任意のデータ |
proposer_slashings | スラッシュされるバリデータのリスト |
attester_slashings | スラッシュされる証明者のリスト |
アテステーション | 現在のブロックに賛成しているアテステーションのリスト |
入金 | デポジットコントラクトに対する新しい入金のリスト |
voluntary_exits | ネットワークに存在するバリデータのリスト |
sync_aggregate | ライトクライアントへの提供に使用されるバリデータのサブセット |
execution_payload | 実行クライアントから渡されるトランザクション |
attestations
フィールドには、ブロック内のすべてのアテステーションのリストが含まれます。 アテステーションは、複数のデータを含むそれぞれの独自のデータ型があり、 それぞれのアテステーションには以下が含まれています。
フィールド | 説明 |
---|---|
aggregation_bits | このアテステーションに参加しているバリデータのリスト |
データ | 複数のサブフィールドを持つコンテナ |
署名 | 証明する全バリデータによる署名の集約 |
attestation
のdata
フィールドには、以下が含まれます。
フィールド | 説明 |
---|---|
スロット (slot) | アテステーションに関連するスロット |
インデックス | 証明するバリデータのインデックス |
beacon_block_root | このオブジェクトを含むビーコンブロックのルートハッシュ |
情報源 | 最後に正当化されたチェックポイント |
target | 最新のエポック境界ブロック |
execution_payload
のトランザクションを実行すると、グローバル状態が更新されます。 すべてのクライアントは「新しい状態」が「新しいブロック」のstate_root
フィールドの状態と一致することを確認するために、execution_payload
のトランザクションを再実行します。 このようにして、クライアントは「新しいブロック」が有効であり、ブロックチェーンに追加しても安全であることを判断します。 execution payload
自体は、いくつかのフィールドを持つオブジェクトです。 実行データに関する重要な要約情報を含むexecution_payload_header
もあります。 これらのデータ構造は、以下のように構成されています。
execution_payload_header
には、以下のフィールドが含まれます。
フィールド | 説明 |
---|---|
parent_hash | 親ブロックのハッシュ |
fee_recipient | トランザクションフィーの支払先アカウントアドレス |
state_root | このブロックに変更を適用した後のグローバルステートに対するルートハッシュ |
receipts_root | トランザクションレシートツリーのハッシュ |
logs_bloom | イベントログを含むデータ構造 |
prev_randao | ランダムなバリデータ選出で使われた値 |
block_number | 現在のブロック番号 |
gas_limit | このブロックで許可されているガスの最大値 |
gas_used | このブロックで実際に使われたガスの量 |
タイムスタンプ | ブロックタイム |
extra_data | 生バイトで表される任意の追加データ |
base_fee_per_gas | ベースフィーの値 |
block_hash | 実行ブロックのハッシュ |
transactions_root | ペイロードに含まれるトランザクションのルートハッシュ |
withdrawal_root | ペイロードに含まれる引き出しのルートハッシュ |
execution_payload
自体には、以下のものが含まれます(注:トランザクションのルートハッシュの代わりに実際のトランザクションリストと引き出し情報を含んでいることを除けば、ヘッダーと同じ)。
フィールド | 説明 |
---|---|
parent_hash | 親ブロックのハッシュ |
fee_recipient | トランザクションフィーの支払先アカウントアドレス |
state_root | このブロックに変更を適用した後のグローバルステートに対するルートハッシュ |
receipts_root | トランザクションレシートツリーのハッシュ |
logs_bloom | イベントログを含むデータ構造 |
prev_randao | ランダムなバリデータ選出で使われた値 |
block_number | 現在のブロック番号 |
gas_limit | このブロックで許可されているガスの最大値 |
gas_used | このブロックで実際に使われたガスの量 |
タイムスタンプ | ブロックタイム |
extra_data | 生バイトで表される任意の追加データ |
base_fee_per_gas | ベースフィーの値 |
block_hash | 実行ブロックのハッシュ |
処理 | 実行されるトランザクションのリスト |
引き出し | 引き出しオブジェクトのリスト |
withdrawals
リストには、次のように構造化されたwithdrawals
オブジェクトが含まれています。
フィールド | 説明 |
---|---|
address | 引き出されたアカウントアドレス |
金額 | 引き出し金額 |
インデックス | 引き出しのインデックス値 |
validatorIndex | バリデータのインデックス値 |
ブロックタイム
ブロックタイムとは、ブロックの生成間隔のことです。 イーサリアムでは、12秒単位で時間を分割し、その単位を「スロット」と呼びます。 各スロットでは、1人のバリデータが選ばれ、ブロックを提案します。 すべてのバリデータがオンラインで完全に稼働している場合、すべてのスロットにブロックが1つ生成され、ブロックタイムは12秒となります。 しかし、バリデータがブロックを提案するタイミングでオフラインになっていることがあり、その場合、スロットが空になることがあります。
この実装は、ブロックタイムが不規則であり、プロトコルがターゲットとして定めるマイニングの難易度によって調整されるプルーフ・オブ・ワークを基としたシステムとは異なります。 イーサリアムの平均ブロックタイム(opens in a new tab)は、12秒という新しいブロックタイムで安定しており、これは、プルーフ・オブ・ワークからプルーフ・オブ・ステークへの移行が明確に示される最も良い例です。
ブロックサイズ
最後に重要なのは、ブロックのサイズには制限があるということです。 各ブロックの目標サイズは1,500万ガスですが、ネットワークの需要に合わせて、ブロックの上限である3,000万ガス(目標ブロックサイズの2倍)まで増減します。 ブロックのガスリミットは、前のブロックのガスリミットから1/1024の割合で上下に調整することができます。 したがって、バリデータはコンセンサスによってブロックのガスリミットを変更することができます。 ブロックの全トランザクションで消費されたガスの総量は、ブロックのガスリミットを超えてはいけません。 ブロックが勝手に大きくなりすぎるのを防ぐという点で、この制限は重要です。 ブロックサイズが大きすぎると、スペースと速度の要件により、パフォーマンスの低いフルノードはネットワークに追いつけなくなり、 次のスロットに間に合うように処理するために必要な計算能力も高くなります。 これが中央集権的な力につながってしまうことから、ブロックサイズに上限を設けています。
参考文献
役に立ったコミュニティリソースがあれば、 ぜひこのページに追加してください。