はじめに
初めまして。 『DApps開発入門』という本や色々記事を書いているかるでねです。
以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください!
今回はコンセンサスアルゴリズムについてまとめていきます。 「PoW」、「PoS」、「Tendermint」、「PoA」についてまとめています。
PoW
Proof-of-Work(PoW)は、新しいブロックを作るときに「特定の条件を満たすまでハッシュ計算を繰り返す」仕組みです。 このような条件を満たすことは膨大な計算を必要とするため、ブロックがその条件をクリアしていること自体が「正しく作られた証拠」になります。 これにより、誰か特定の管理者に頼ることなく取引の記録を並べ、矛盾のない履歴を維持できます。
ハッシュ
ここで使われる「ハッシュ」とは、データを一定の長さの値に変換する関数のことです。 BitcoinではSHA-256という暗号学的ハッシュ関数を用いており、入力データを少しでも変えると結果の値が大きく変わるという特徴があります。
以下のサイトで動作を確認できます。
「データ」部分に任意の値を入力すると、「ハッシュ」部分の値が全く異なる値になります。
Hello

Hello
185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969Hello
Helloの後ろにスペースを入れているだけですが、ハッシュ値はHelloとは全く異なる値になっています。

Hello
2ec5a3f0c2fc3e6dcee0f6f3a5735a6c69d2056579a5452095b75802094043a8Hello World

Hello World
a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146ePoWの仕組み
PoWの仕組みについて詳しく説明していきます。
1. ブロックヘッダの組み立て
前ブロックのハッシュ、トランザクションから計算したマークルルート、タイムスタンプ、nBits、nonceを入れてブロックヘッダを作成します。
-
前ブロックのハッシュ(Previous Block Hash) 直前のブロックのヘッダをdoubleSHA-256した値。 この値を含めることで、ブロック同士が鎖のようにつながり、ひとつでも改ざんすると以降すべてが無効になります。
-
マークルルート(Merkle Root) そのブロックに含まれる全トランザクションをMerkle Treeにまとめ、そのルートにあたるハッシュ。 任意のトランザクションがブロック内に含まれているかどうかを効率よく検証できます coinbase(マイナーが報酬を受け取るトランザクションで、ブロック内の最初に格納される)を変えるとマークルルートが変わり、ヘッダ全体も変わります。
-
Timestamp ブロックを作成したおおよその時刻(UNIX時刻形式)。 ノードの時刻に依存するため、正確な時刻を保証するわけではないです。 ネットワークが「未来すぎる時刻」や「過去すぎる時刻」のブロックを拒否するため、だいたいの時間順序を守る役割を持ちます。
-
nBits(難易度の圧縮表現) 難易度を短く表した値で、ここから「target(閾値)」を復元します。 targetが小さいほど条件は厳しく、必要な計算量が増えます。 つまり「どれだけ先頭に0を揃えなければならないか」を決める基準です。
nBitsは「難易度調整アルゴリズム」によって決まります。 Bitcoin の場合、2016ブロックごと(約2週間に一度)にネットワーク全体で計算力に合わせて自動的に更新されます。- 前の2016ブロックがどのくらいの時間で生成されたかを測る
- 目標時間(2016 ブロック × 10分 = 2週間)と比べる
- もし速すぎれば
targetを小さくして難易度を上げる - 遅すぎれば
targetを大きくして難易度を下げる
1回の調整で難易度が4倍以上変わらないよう制限もかけられています 調整後の
targetがcompact形式(32ビット)に変換され、次のブロック以降のnBitsとして使われます。 -
nonce(ナンス) 32bitのカウンタ。 PoW計算のために総当たりで値を変えていく部分。 使い切ったらcoinbase内のextraNonce(coinbase内の任意データを入れられる領域。ここを更新するとマークルルート全体が変わるので、
nonceを使い切った後も新しい探索空間を得られる)を更新してマークルルートを変え、探索空間を広げます。
マークルルートはトランザクション集合の要約なので、coinbaseを変えるとマークルルートも変わり、結果としてヘッダ全体のハッシュも変わります。
2. 目標値(target)を決めます
ブロックヘッダには nBits というフィールドがあり、これは難易度を短く表した圧縮形式です。
マイナーはこの nBits を展開し、実際に使う256ビットの数値である target を計算します。
nBits の構造
nBits は4バイト(32ビット)で構成されています。
- 最上位1バイト
指数部(
exponent) - 下位3バイト
仮数部(
coefficient)
この2つを組み合わせて target を計算します。
target の計算式
以下の式で target を復元します。
- coefficient
nBitsの下位3バイトをそのまま整数にした値 - exponent
nBitsの上位1バイトを整数にした値
計算例
例えば、Bitcoinジェネシスブロックの nBits は 0x1d00ffff です。
- exponent = 0x1d = 29
- coefficient = 0x00ffff = 65535
計算式に当てはめると以下のようになります。
= 65535 × 256^26 = 0x00000000FFFF0000000000000000000000000000000000000000000000000000
これが target です。
PoWにおける判定条件は非常に単純で、ヘッダ全体をSHA-256で二回ハッシュ化した結果(digest)が、この target 以下であるかどうかです。
この「digest ≤ target」という条件は、「ハッシュの先頭にいくつゼロが並んでいるか」を確認することと同じ意味になります
target と完全に一致する必要はなく、それ以下の値であれば十分な理由。
ハッシュはランダムな数として扱われる
ハッシュ関数(SHA-256)の出力は256ビットの整数で、ほぼ一様にランダムに分布します。 つまりPoWは「このランダムな数が十分小さいかどうか」をチェックしているだけです。
条件は「閾値以下」だから
target は「これ以下ならOK」という閾値を意味しています。
もし「digest = target だけが有効」だったら、その確率は に等しく、難易度が跳ね上がり見つけるのが非常に困難になります。
実際には target の範囲内に多くの整数値があるので、以下のようになり、target の値に応じて現実的な確率でブロックが見つかる仕組みになっています。
「target 以下」にすることで難易度を調整可能
targetが大きい → 範囲が広い →digestがその中に収まりやすい → 難易度が低いtargetが小さい → 範囲が狭い →digestが入りにくい → 難易度が高い
もし「target と完全一致」しか認めなければ、難易度の調整ができず、実質的にブロック生成は不可能になります。
target が小さくなるほど、より多くのゼロを揃えなければならず、達成が難しくなります。
例えば先頭に20ビットのゼロが必要であれば、成功確率は 1/2^20 であり、平均して 2^20 回の試行が必要です。
ゼロの数が1ビット増えるたびに、必要な計算量はおおよそ2倍に膨らんでいきます。
ハッシュ値(digest)は256ビットのランダムな整数と考えられます。
PoWではこの整数が target 以下になるまで試行を繰り返します。
例 1:target が大きい場合
仮に target が以下だったとします。
0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF- 先頭 16 ビット(2 バイト)は必ず
0でなければなりません。 - それ以降のビットは自由なので、成功確率は 1 / 2^16 ≈ 1/65,536 です。
- 平均すると約 65,000 回の試行で成功します。
例 2:target が小さい場合
次に target を以下のように小さくします。
0x0000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF- 今度は先頭
28ビット程度が0でなければなりません。 - 成功確率は 1 / 2^28 ≈ 1/268,435,456 です。
- 必要な試行回数は数億回に跳ね上がります。
3. ナンス探索を行います
マイナーはこの条件を満たすブロックを探すため、ブロックヘッダをハッシュ化し続けます。
具体的には、ヘッダ内の nonce という32ビットのカウンタを少しずつ増やしながらdoubleSHA-256を計算し、その結果が target 以下になるかどうかを何度も試みます。
nonce をすべて試しても条件を満たす結果が得られなければ、coinbaseトランザクション内のextraNonceを変更します。
これによりマークルルートが変わり、ブロックヘッダ全体も変化するため、新しい探索空間で再び計算を続けられます。
この探索作業は純粋に確率に依存しているため、いつ条件を満たせるかは予測できません。
ただし target が小さいほど、つまり難易度が高いほど、成功までに必要な試行回数は指数的に増えていきます。
以下でハッシュ化し続ける処理を確認できます。
https://andersbrownworth.com/blockchain/block
デフォルトだと以下のように表示されていると思います。

例えば、データ部分に「Hello」と入力します。

そうすると、ブロックハッシュが変わるので、正しいハッシュを見つけるためにノンスの値を変更する必要があります。

「掘る」(Miningを行う)をクリックすると、ノンスの値が変更されて先頭4桁が0になるような値を見つけます。
「ハッシュの先頭4桁(16ビット)が0であること」という条件は、数学的には target を小さい値にすることで表現できます。
具体的には以下のような値になり、「先頭16ビットが必ず0で、それ以降はどんな値でもよい」という範囲を意味します。
target = 0x0000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF検証条件は 「digest ≤ target」で、digest がこの target より小さい数になるためには、先頭16ビット(16進4桁)が0 である値を探索します。
4. 条件達成でブロックを伝播します
PoWの条件を満たすブロックヘッダが得られたら、そのブロック(ヘッダ+トランザクション本体)をネットワークに伝播させます。 マイナーは報酬を得るため、自分が発見したブロックをできるだけ早く全体に広めようとします。 並行して他のマイナーもマイニングを行っているため、同じタイミングで複数のブロックが発見されることがあり、その場合はチェーンが一時的にフォークすることになります。
5. 他ノードによる即時検証
ブロックを受け取った他ノードは、そのヘッダに対してdoubleSHA-256を計算し、ハッシュ値(digest)が target 以下であるかを確認します。
このチェックは1回のハッシュ計算で済み、非常に軽量です。
一方で、ブロックを生成するには膨大な試行(nonceの探索)が必要です。 この「生成は計算量的に困難だが検証は容易」という性質こそがPoWの特徴です。 これにより、全体の正当性を低コストで確かめながら、不正に改ざんされたブロックを容易に排除できる仕組みが成立します。
ブロック生成
以下のサイトで実際にブロック生成の流れを確認できます。 デフォルトでは以下のようになっています。

例えば、ブロック2のデータを書き換えたとします。

そうすると、ブロック2のブロック8種が変化し、後続のブロック内の「前ブロックのハッシュ値」が変わってしまい、そのブロックのハッシュ値も変わります。 そうすると、後続の全てのブロックのハッシュ値が変わってしまうため、再度計算し直す必要があります。




そのため、上記のように1つずつブロックをマイニングして、ブロックハッシュを再計算していくことで正しいチェーンとして扱うことができます。
検証の容易さ
PoWの検証は、計算量がほぼ一定で計算処理が軽量で済みます。 以下の手順で、ブロックヘッダだけを使ってPoWが満たされているかを確認します。
- ブロックヘッダを受け取る
ブロックの基本情報(
version/prev-hash/merkle-root/timestamp/nBits/nonce)を含むヘッダを取得します。 本体のトランザクションは使わず、ヘッダだけでPoW検証が可能です。 - ヘッダにdoubleSHA-256を実行
受け取ったヘッダをSHA-256を2回適用して要約値(
digest)を得ます。 入力を1ビットでも変えると結果が大きく変わるため、改ざんの有無がすぐ分かります。 - 得られた値が
target以下か比較 計算したdigestがtarget(nBitsから復元される閾値)以下なら、PoWの検証は成功と判定します。targetが小さいほど条件は厳しく、達成が難しくなります。
このように検証側は「ハッシュ計算1回+整数比較1回」程度のコストで済みます。
一方で生成側(マイナー)はnonce等を変えながら多数回試行する必要があり、ここに計算量の非対称性(生成コストは重いが検証コストは軽い)が生まれます。
結果として、ネットワーク全体は低コストで不正なブロックを速やかに排除できます。
改ざんへの耐性
ブロックチェーンでは、各ブロックが直前のブロックのハッシュを含んでいるため、過去の1つのブロックを改ざんするとその後ろに続くすべてのブロックを作り直さなければなりません。
攻撃者が改ざんを成功させるには、正直なノードと同じ速度で新しいブロックをマイニングしつつ、さらにそれを追い越す必要があります。
しかし正直なノードが計算力の過半数を持っている限り、攻撃者が追いつく可能性は新しいブロックが追加されるたびに急速に下がっていきます。 結果として、ブロックが積み重なるほど過去の記録を改ざんすることは現実的に不可能になります。

上記のように、特定のブロックを改ざんした場合、改ざんしたブロック以降のブロックのハッシュを全て計算し直す必要があります。 十分な時間があればこの処理を行うことはできますが、その間、他のマイナーはどんどん新しいマイニングをして新しいブロックを生成していきます。 そのため、数ブロックはたまたま普通より早く生成できても、最新のブロックにはいつまで経っても追いつくことは理論上難しいです。
合意形成
ノードは常に、累積PoW(chainwork:これまで積み上がった計算量の合計)が最大のチェーンを正しいとして認識します。 一般に「最長チェーン」と言いますが、厳密には計算の重みが最も大きいチェーンを指します。 各ノードは新しいブロックを受け取るたびに、そのチェーンの累積PoWを自分の手元で再計算し、より大きければ自分が追従するチェーンの先頭(tip)を切り替えます。
ノードはチェーンの切替え時にPoW(digest ≤ target)の妥当性だけでなく、各トランザクションの正当性(署名・二重支払いの有無など)も検証します。
無効なブロックは累積PoWが大きくても採用されません。
全体が揃う仕組み
- 競合(フォーク)の発生 複数のマイナーがほぼ同時にブロックを見つけると、一時的に先頭が分かれます。
- 収束の仕組み どちらか一方に新しいブロックが先に追加されて累積PoWが上回ると、ノードはそちらへ乗り換えます。 これが繰り返され、最終的に1本に収束します。
- 取引の「確からしさ」 あるブロックに後続ブロック(confirmations)が重なるほど、そのブロックを含むチェーンの累積PoWが増え、巻き戻り(reorg)の確率が下がります。 そのため、一定数の確認(例:Bitcoinでは目安として6ブロック)を待ってから、その取引を実質的に確定したものとして扱うのが一般的です。
難易度の調整
Bitcoinでは、ブロックごとに nBits という値が入っています。
これは本来256ビットの大きさを持つ target を短く表したもので、検証時には「ブロックヘッダをSHA-256を2回かけた値(digest)が target 以下か」を見ます。
target が小さいほどより小さなハッシュを要求することになり、見つけにくくなり難易度が上がるという関係です。
難易度(difficulty)は以下のように表され、target が小さくなるほど difficulty は大きくなります。
ただし、マイナーの計算力(ハッシュレート)は常に一定ではありません。
マイナーが増えたりマシンが高速化すると、放っておけばブロックはどんどん早く見つかります。
逆に離脱や故障が増えれば遅くなります。
そこで、平均およそ10分に1ブロックという目標ペースに近づけるため、Bitcoinは2016ブロックごと(約2週間)に target を調整します。
やり方はシンプルで、「直近2016ブロックに実際にかかった時間(actual_timespan)」を測り、目標の14日(target\_timespan)との差に応じて target を比例的に更新します。
計算が速すぎた(actual\_timespan が短い)なら new\_target は小さくなり、次回からはより厳しい条件になります。
遅すぎた場合は new\_target が大きくなり、条件がゆるくなります。
さらに一度の調整で極端に振れないよう、actual\_timespan は 1/4〜4倍の範囲に丸められます(難易度の急変を防ぐため)。
この新しい target を compact 形式に戻したものが次のブロックの nBits になります。
例
ネットワーク全体の計算力がほぼ2倍になれば、同じ2016ブロックをマイニングするのにかかる時間は約半分になります。
式に従って new_target も約半分になり、その結果 difficulty(max\_target / target) はおおむね2倍へ。
逆に計算力が半分になれば new_target は約2倍、difficulty は半分に下がります。
こうして、計算力が増減しても10分前後でのブロック生成が保たれるように調整され続けます。
Reference
PoS
概要
EthereumのPoSは、ETHを stake(担保として預け入れ)した validator(検証者)がブロックを提案し、他のvalidatorが attestation(投票)を行うことでチェーンにblockを追加する仕組みです。
時間は slot(12秒)と epoch(32slot ≒ 約6.4分)で区切られます。
各 slot ごとに RANDAO(検証可能な乱数生成)によって block proposer(その slot でブロックを提案する validator)と committee(その slot の attestation を担当する validator のグループ)が選ばれます。
RANDAO
RANDAOの仕組み
- commit-reveal による乱数生成
各
validatorは、ある時点で秘密値をhash化したもの(commit)を事前に提出します。slotに到達すると、その秘密値(reveal)を公開します。 これを順に XOR(排他的論理和)で組み合わせることで、予測困難な乱数が得られます。 これを「RANDAO」と呼びます。 - 乱数の強化(VDF / mix)
EthereumのBeacon Chainでは、得られた乱数に追加の処理をかけて「予測・操作のしづらさ」を高めています。
例えば「
randao_mix」として保存され、後続のepochの選出に使われます。
選出の流れ
各 epoch のはじめに、その epoch 全体の randao_mix が計算されます。
この乱数をもとに、以下の割り当てが行われます。
block proposer各slotごとに、アクティブなvalidatorのリストから乱数を使って1名が選ばれる。committee同じく乱数を使って、各slotに参加するvalidatorの小グループが決定される。
例:RANDAOによる乱数生成
-
3人の
validatorがいます。- V1
- V2
- V3
-
各
validatorは秘密の値(例:乱数種)を持っています。- V1 →
s1 = 0xA3F... - V2 →
s2 = 0xC9D... - V3 →
s3 = 0x117...
- V1 →
-
各
validatorは事前にhash(s1)・hash(s2)・hash(s3)を提出して「コミット」します。 -
epochに入ると順番にs1・s2・s3を公開(reveal)します。 -
それらを順に XOR で混ぜ合わせます。
textrandao_mix = s1 ⊕ s2 ⊕ s3例:
texts1 = 1010 (2進数) s2 = 1100 s3 = 0111 randao_mix = 1010 ⊕ 1100 = 0110 randao_mix = 0110 ⊕ 0111 = 0001randao_mix = 0001がこのepochの乱数になります。
proposer の選出
アクティブな validator が 1000人いるとします。
- このリストにインデックス(0〜999)を振る。
randao_mixを使って「mod 1000」を計算する。
randao_mix = 0001 (=1)
1 mod 1000 = 1インデックス 1 の validator が、その slot の block proposer に選ばれます。
committee の選出
committee には 128人が必要だとします。
-
randao_mixを元に乱数列を生成し、0〜999の範囲でランダムにvalidatorを選ぶ。 -
例えば以下のような結果になる。
text[5, 217, 398, 777, ...]
この 128人がその slot の committee となり、attestation を担当します。
aggregator の選出
committee の全員が attestation を出すとデータが膨大になるため、さらに committee の中から少数の validator が aggregator として選ばれます。
各 committee メンバーは乱数に基づき「自分が aggregator か」を判定します。
選ばれた aggregator は他メンバーの attestation を集約(aggregate)し、1つの署名付きメッセージとしてネットワークに流します。
これにより 数百人分の attestation が、集約された少数のメッセージとしてブロックに取り込まれるため、効率的にコンセンサスに利用できます。
PoSのconsensusは LMD-GHOST と Casper FFG で構成されています。
LMD-GHOST はfork choice ruleとして「どのブロックを先頭とみなすか」を決定し、Casper FFG はチェックポイントに基づいて justification と finality とみなします。
Ethereumのfinalityは、提案された直後のブロックではなく複数のブロックを経たチェックポイントで成立します。
justification
チェックポイント(各 epoch の最初のブロック)に対し、validator の attestation(投票)を集計し、その重みが active validator のステーク合計の 2/3以上 に達した場合、そのチェックポイントを justified とみなします。
この時点で、そのチェックポイントは「次に finalized とみなせるかを判定する段階へ進むための条件を満たした」状態です。
finality
あるチェックポイントが justified になった後、次のチェックポイントも同様に active validator のステーク合計の 2/3以上 の重みで支持されて justified になると、先に justified だったチェックポイントを finalized とみなします。
finalized とみなされたチェックポイントより前の履歴は、プロトコル上reorg(チェーンの巻き戻し)の対象にしません。
finality に到達するまでの目安は 2 epoch です。
epoch は32 slot(1 slot=12秒)なので、2 epoch は 64 slot=約12分48秒 です。
そのため、finality に到達するまで大体 約12.8分 と理解しておけば実務上は十分です。
PoSの仕組み
PoSでは、stake したETHの重みに応じて合意が決まります。
validator はルールどおりに block proposal(ブロック提案)と attestation(投票)を実行すると reward(報酬)を受け取ります。
違反がある場合は以下のように扱われます。
- 軽度の違反
attestationを出さない・遅れる等 ⇒penalty(報酬の減少や小さな減点)が課されます。 - 重大な違反
同じ
slotで2つのブロックを提案するdouble proposal、互いに矛盾する投票を出すdouble vote、過去の自分の投票を包含する形の矛盾投票であるsurround voteなど ⇒slashing(stakeの削減と強制exit)の対象になります。
finality(後で説明)が長時間「成立しない」状態が続く場合には、inactivity leak が作動します。
これは、参加していない validator の重み(balance)を段階的に小さくし、参加している validator が最終的に2/3を占められるようにすることで、finality が再び成立するように設計された仕組みです。
Inactivity Leak
Ethereum のコンセンサスレイヤーには、チェックポイントを finality させる仕組みがありますが、もし長期間にわたって finality が得られない状態が続いた場合、通常の報酬/罰則ルールだけでは回復できなくなる恐れがあります。
そこで、非常事態対応の仕組みとして inactivity leak が設けられています。
Inactivity leak は、finality が成立しない期間が続くと起動するモードで、オフラインあるいは投票できない validator の stake を段階的に減らすことで、残った参加中の validator がtotal stakeの2/3を占める状態をつくり、最終的に finality を再開できるようにする目的があります。
発動条件
Ethereum の仕様では、4 連続の epoch で finality が得られなかったときに、inactivity leak モードが起動します。
これは「チェックポイント間の支持が十分集まらずfinality にできない」ことを意味します。
動作メカニズム
一旦 inactivity leak モードが始まると、以下のような処理が適用されます。
| 処理 | 内容 |
|---|---|
attestation 報酬 |
attestation に対する報酬は支払われません。 |
非参加 validator へのペナルティ |
非参加(または正しく投票できない)validator に対して、ペナルティを追加で課します。得られるペナルティは時間経過とともに大きくなります。 |
proposer / committee の報酬 |
proposer(ブロック提案者)や committee 参加者への報酬は、inactivity leak 時にも基本的には継続されます。 |
非参加 validator の stake(特にeffective balance)が徐々に減少していき、その影響力が弱まると、残っている validator だけで stake の2/3を超える体制を築けるようになります。
そうしたとき、finality は再び成立できるようになります。
また、inactivity leak 中でもペナルティが続き、モード終了後(finality が再開した後)も一定期間は影響を残すようになっている点も仕様に組み込まれています。
フォーク選択(LMD-GHOST)
各 validator は定期的に attestation を発行します。
これには「自分が見ている head」が含まれます。
Ethereumのノードは、それぞれが受け取った全 attestation のうち、最新のもの(Latest Message Driven)だけを取り出して重み付けします。
この重みは stake に応じて決まります。
- 集計結果として、重みが最も大きい枝の先にあるブロックが「このノードが次に延長すべきチェーン」とされます。
- このブロックを「
head」と呼び、headはあくまで「いま現在の先頭」であり、後続のattestationによって変わる可能性があります。
言い換えると、LMD-GHOST は「常に最新の投票を反映して、どのブロックをチェーンの先頭とみなすかを決める」ルールです。
チェックポイントと finality(Casper FFG)
EthereumのPoSでは、すべてのブロックが同じ重みで確定していくわけではなく、epoch ごとに「チェックポイント」を設け、そこを基準にして finality を与えます。
- チェックポイントの定義
各
epoch(= 32slot≒ 6.4分)の最初のブロックが、そのepochのチェックポイントです。 - justification
あるチェックポイントに対して、
active validatorのeffective balanceの合計の 2/3以上 がattestationで支持すると、そのチェックポイントはjustifiedとみなされます。effective balanceは投票の重みを計算するための基準値で、各validatorごとに最大32 ETHが上限です。 残高がそれ以上あっても投票重みは増えません。 - finalization
justifiedとなったチェックポイントの次のepochのチェックポイントも、同じく 2/3 以上の支持を得てjustifiedになると、最初のチェックポイントがfinalizedとみなされます。 - finality の意味
finalizedになったチェックポイントより前のブロックは、Ethereumのコンセンサスルール上、reorg(ブロックの差し替えや巻き戻し)の対象から外れます。 つまり、これ以降は「確定した履歴」として扱われます。
時間的な目安
- 1
epoch= 32slot= 384秒(6分24秒)
通常、finality に達するまでに 2 epoch(= 約12分48秒) が必要です。
実際には、トランザクションがどのタイミングでブロックに含まれるかによって、チェックポイントに達するまでの待ち時間が加わるため、平均すると 約2.5 epoch(≒ 15分程度) と考えられます。
PoSの流れ

sequenceDiagram
participant VP as Validator (Proposer)
participant VC as Validator (Committee)
participant AG as Aggregator (Validator)
participant BN as Beacon Node (Consensus)
participant EX as Execution Client (EVM)
participant GS as Gossip network
Note over BN: RANDAOに基づいて<br/>ProposerとCommitteeを選定
VP->>EX: トランザクションを収集
VP->>BN: 新しいブロックを生成
VP->>GS: ブロックをブロードキャスト
VC->>BN: 受け取ったブロックを検証
VC->>GS: attestationを送信(head, source, target)
AG->>VC: attestationを収集
AG->>BN: 集約attestationを生成
AG->>GS: 集約attestationをgossip
BN->>BN: フォーク選択(LMD-GHOST)<br/>headブロックを決定
BN->>BN: チェックポイント処理(Casper FFG)<br/>justification / finalization
BN->>VP: rewardまたはpenaltyを適用
BN->>VC: rewardまたはpenaltyを適用
BN->>AG: rewardまたはpenaltyを適用Gossip network
Ethereum では Gossip プロトコルと呼ばれる通信方式を使って、PoSのコンセンサスに必要な情報を全ノードに伝播させています。 ノードは少数の隣接ピアとだけ直接通信し、受け取った情報をさらに他のピアへ転送していくため、最終的にネットワーク全体へと広がります。 口コミのように伝わる仕組みなので「Gossip」と呼ばれています。
この通信方式を通じて、proposer が作成したブロックや、committee が提出する attestation、aggregator がまとめた aggregated attestation など、合意形成に必要なデータが共有されます。
各メッセージは受け取るたびに検証されて不正なものは破棄されるため、改ざんや欠落を防ぎながら全体に行き渡るのが特徴です。
結果として、EthereumのPoSにおいて Gossipは「ブロックや投票情報を全ノードに効率的に行き渡らせる仕組み」であり、フォーク選択や finality 判定といった上位のコンセンサスプロセスを支える基盤になっています。
-
役割の決定(
assignment) 各epochの開始時に、RANDAOを入力とするshufflingによって、各slotのblock proposerとcommittee(内部でaggregatorも)が決まります。 1slotは 12 秒、32slotで 1epoch(約6分24秒)です。 -
block proposal決まったblock proposerがトランザクションを集めて新しいブロックを生成し、broadcastします。block proposalはそのslotのrandao_revealをブロックに含めます。randao_revealは、validatorが毎回のblock proposalに含める乱数の公開値です。 各validatorは事前に秘密値のハッシュを提出しておき、proposalの時にその秘密値を公開します。 公開された値(reveal)はRANDAOに混ぜ合わされ、次のslotやepochで使う乱数(randao_mix)が更新されます。 -
attestation提出 そのslotのcommitteeが受け取ったブロックに対するattestationを作成・送信します。attestationには以下が含まれます。- 現在の先頭ブロック(
head) - 直近の
justifiedチェックポイント(source) - 現在のターゲットとなるチェックポイント(
target)aggregatorが複数のattestationを集約してネットワークに送信し、これらは次のslot以降のブロックに取り込まれます(最短 1slot遅延)。
- 現在の先頭ブロック(
-
フォーク選択(
LMD-GHOST) 各ノードは最新のattestationを重み(effective balance)付きで集計し、重みが最大のチェーンの先端にあるブロックをその時点のheadとして採用します。headはあくまで「今延長すべき先頭」で、後続のattestationにより変化します。 -
チェックポイント処理(
Casper FFG) 各epochの境界でチェックポイントへのattestationを集計し、active validatorのeffective balanceの 2/3 以上 の支持があれば、そのチェックポイントをjustifiedとみなします。 次のepochのチェックポイントでも同条件が満たされると、先にjustifiedだったチェックポイントをfinalizedとみなします。finalizedより前の履歴はEthereum上のreorgの対象にしません。finalityに到達する目安は 2epoch(= 64slot≒ 約 12 分 48 秒) です。 -
インセンティブ計算
validatorが正しくblock proposalを行い、attestationを期限どおりに提出した場合はrewardが支払われます。attestationを提出しない/遅れるなどの不参加があればpenaltyになります。 さらに、同一slotで2つのブロックを提案するdouble proposal、矛盾する投票を出すdouble vote、過去の自分の投票を包含する矛盾投票であるsurround voteなどの重大な違反はslashing(stakeの削減と強制exit)の対象です。 加えて、finalityが長時間成立しない異常状態ではinactivity leakが発動し、非参加側のeffective balanceを段階的に減少させて参加中のvalidatorが 2/3 を満たせるようにし、finalityを再び成立させます。
Reference
- https://ethereum.org/ja/developers/docs/consensus-mechanisms/pos
- https://ethereum.org/ja/staking
- https://ethereum.org/ja/developers/docs/consensus-mechanisms/pos/block-proposal
- https://ethereum.org/ja/developers/docs/consensus-mechanisms/pos/gasper
- https://ethereum.org/ja/developers/docs/consensus-mechanisms/pos/pos-vs-pow
- https://github.com/ethereum/consensus-specs
Tendermint
概要
Tendermintは、ブロックチェーンにおけるBFT(Byzantine Fault Tolerance:ビザンチン耐性)コンセンサスアルゴリズムです。
BFT
ビザンチン将軍問題は、分散した参加者がメッセージだけで合意する状況を抽象化した説明です。 複数の将軍(参加者)が行動を一致させる必要がある一方で、連絡手段は伝令(ネットワークメッセージ)のみで、遅延・欠落・改ざんが起こり得ます。 さらに一部の将軍は裏切り者(任意の不正挙動を行うノード)として、相手ごとに矛盾した指示を送ったり沈黙したりできます。 この条件下で「正直な将軍が必ず同じ行動にまとまれるか」が問題です。 重要なのは、どちらの行動が正しいかではなく、正直な参加者が矛盾なく同じ決定に到達できるかどうか、という点です。
理論的には、ノード総数を 、不正ノード数を とすると、合意の安全性(Safety:正直な参加者同士が矛盾する決定を採用しない)と活性(Liveness:通信が続く限り最終的に決定に到達する)を同時に満たすための代表的な境界は以下です。
つまり、不正が全体の3分の1未満であれば、正直な参加者は最終的に同じ決定に達することができます。 多くのBFT系コンセンサスでは2/3以上の同意を閾値として用い、この閾値を満たした時点で決定を最終確定(finality)とみなします。
特徴は以下の3つです。
- 即時ファイナリティ PoWのような「確率的ファイナリティ」ではなく、バリデータの投票が2/3以上集まれば即座にファイナライズします。
- マイニング不要 計算競争は行わず、合意形成は投票によって決まります。
- ABCIによる汎用性 Tendermintはコンセンサス処理を担う仕組みを提供し、アプリケーションはABCI(Application Blockchain Interface)を通じて連携します。 これにより、開発者はコンセンサスの実装を自ら行う必要がなく、ABCIを介してトランザクションの検証や状態管理といったアプリケーション固有の処理を実装できます。
ABCI(Application Blockchain Interface)
概要
ABCI(ApplicationBlockchainInterface)は、Tendermintが提供する「コンセンサス層」と「アプリケーション層」を接続するための汎用インターフェースです。
TendermintCoreは、ブロック提案と投票による合意形成のみを担当します。 一方、ブロック内トランザクションに対する検証規則の適用(署名・nonce・手数料・サイズ等の検査)や、手数料計算・権限制御・トランザクション処理に伴うステート遷移はアプリケーション側で実装します。 ABCIは、このコンセンサス層—アプリケーション層のインターフェースを規定します。 これにより、コンセンサスの仕組みを変更せずに、アプリケーション側のルールやステート遷移ロジックを差し替え・拡張できます。
仕組み
Tendermint Coreとアプリケーションはプロセスとして分離され、ソケット通信(通常はgRPC)を通じてABCIメッセージをやり取りします。 Coreがブロックやトランザクションを処理する時には、その内容をABCI経由でアプリケーションに渡し、アプリケーションは検証・実行結果を返します。 これにより、コンセンサスとステート遷移の責務が明確に分離されます。
ABCIには大きく分けて以下のようなメソッド群があります。
- CheckTx Mempool受け入れ前の検証を行います。 署名の有効性、サイズやガス上限、手数料、シーケンス番号(nonce)、二重送付(double-spend)禁止ルールなどを確認します。
- DeliverTx ブロックに含まれるトランザクションを実際に実行してアプリケーションのステートを更新します。
- Commit ブロック処理の最後に呼ばれ、アプリケーションの新しいステートルートを返します。
- BeginBlock / EndBlock ブロックの開始時・終了時に呼ばれ、ブロック単位で必要な処理(スラッシングや報酬計算など)を行います。
役割
ABCIの役割は「コンセンサスを行う層」と「アプリケーションロジックを実装する層」を切り離すことにあります。 これにより、開発者は任意のプログラミング言語でアプリケーションを実装でき、Tendermint Coreと組み合わせてブロックチェーンを構築できます。 Cosmos SDKが典型例で、ABCIを通じてTendermintと連携しながらステーキングやガバナンスといったモジュールを実装しています。
Tendermintの仕組み
バリデータ
Tendermintでは、投票権(votingpower)を持つノードをバリデータと呼びます。 投票権はステーク量などの基準で割り当てられ、不正ノードが全体の1/3未満であれば、Safety(安全性)=正直な参加者同士で矛盾するファイナリティが同時に成立しないこと、Liveness(活性)=通信が継続する限りいずれブロックがファイナリティに到達することの両方を満たします。 各バリデータは署名付きメッセージで投票し、その重みは投票権に比例します。
Height/Round
ブロック番号をHeightと呼び、各Heightで1つのブロックをファイナライズします。
ファイナライズに至らない可能性を考慮し、同じHeightの中でRoundを順に進めます。
各Roundには提案者(Proposer)が1名割り当てられ(通常は投票権に基づく重み付きローテーション)、提案が間に合わない・不正である・2/3以上の同意に届かない場合はタイムアウトにより次のRoundへ移行します。
提案を受け取れないときや不正を検出したとき、バリデータは「ブロックなし」を意味するnilに投票できます。
投票フェーズ
各Heightでは、同じHeight内で次の手順を順に実行してブロックをファイナライズします。
- Propose 提案者(Proposer)がMempoolからトランザクションを収集し、ブロック案を提示します。
- Prevote
各バリデータは提案されたブロックを検証し、正しく処理可能と判断すれば該当ブロックに投票して不正または条件を満たさないと判断すれば
nilに投票します。 - Precommit 特定ブロックに2/3以上のPrevoteが集まったことを観測したバリデータは、そのブロックにPrecommitを投じます。 条件が満たされなければ次のRoundへ進みます。
- Commit 同一ブロックに2/3以上のPrecommitが集まった瞬間、そのブロックをファイナライズして各ノードはチェーンへ追加します。
Tendermintにはロック(lock)規則があります。 ロック規則とは、あるラウンドで特定ブロックにPrecommitしたバリデータが、後続ラウンドでも同じブロックの支持を継続する義務を課す仕組みです。 別ブロックへの切り替えは、その別ブロックに対するPrevoteが2/3以上集まった(polkaを満たした)ことを観測し、ロック更新または解除の条件を満たした場合にのみ許可されます。 これにより、競合ブロックで矛盾するファイナリティが同時成立することを防ぎます。
Polka
Polkaは、あるラウンドにおいて1つのブロックがバリデータのPrevoteで2/3以上の支持を集めた状態を指します。
Prevoteは「このブロックを候補として次の段階に進めることに同意する」という一次投票です。 Prevoteが複数のブロックに分散すると、どのブロックも優勢とは言えません。 これに対し、1つのブロックに対して2/3以上のPrevoteが集まった場合、そのブロックは次の段階へ進むに十分な支持を得たとみなされ、この状態をPolkaと呼びます。
即時ファイナリティ
Tendermintは、同一Round内で2/3以上のPrecommitが観測された時点で、そのブロックにファイナリティを与えます。 ファイナライズ後はプロトコル上の巻き戻しが起きないため、reorgを前提に待機する必要はありません。 ネットワーク遅延などで1回のRoundで2/3以上が揃わない場合は次のRoundへ進み、条件が整い次第、同じHeightで即時ファイナライズします。
Tendermintの流れ

- Proposer selection(weighted round-robin) 各Heightの各Roundで1名のProposerを割り当てます。 割り当ては投票権(voting power)に基づく重み付きローテーションで行われます。 Proposerが提案を間に合わせない、不正な提案をする、あるいは以後の投票で条件に達しない場合、Roundのタイムアウトにより次のRoundへ移行し、新しいProposerが選ばれます。 ここまでで合意は成立していませんが、「誰が提案するか」が決まります。
重み付きローテーション
Tendermintでは、各Height/各RoundのProposer(提案者) を、バリデータのvoting power(投票権) に比例する頻度で選びます。 頻度だけでなく、短期的な偏り(同じノードに連続で偏ること)も抑える必要があります。 そこで用いるのが重み付きローテーション(Weighted Round-Robin) で、Tendermintでは内部的にProposer Priorityという値を各バリデータに持たせて実現します。
各バリデータ i に、固定の voting_power[i] と可変の priority[i] を持たせます。
各Height/各Roundで次の処理を行います。
- 累積
すべてのバリデータについて
priority[i] += voting_power[i]を加算します。 投票権が大きいほど優先度が速く増えます。 - 選出
priority[i]が最大のバリデータを Proposer に選びます。 最大値が同じ場合は、全ノードが同じ結果に到達できるよう、事前に定めた一意の順序(例:バリデータのアドレスを昇順で比較)で一人を選びます。 - 調整
選ばれたバリデータ
kに対してpriority[k] -= total_voting_power(全バリデータのvoting_power合計)を行います。 これで選ばれた直後は優先度が大きく下がり、次回以降は他のバリデータが選ばれやすくなるようにバランスをとります。
この3手順を各Roundごとに繰り返すと、長期的には「選出回数 ≈ voting power の比率」になり、短期的には極端な偏りが出にくくなります。
例
バリデータA/B/Cの voting_power を A=50, B=30, C=20、初期 priority=0 とします。
total=100 です。
- 1回目の累積後
priority = [50, 30, 20]→ 最大はA → Aを選出 → Aのpriority -= 100→[-50, 30, 20] - 2回目の累積後
[0, 60, 40]→ 最大はB → B選出 →[0, -40, 40] - 3回目の累積後
[50, -10, 60]→ 最大はC → C選出 →[50, -10, -40] - 4回目の累積後
[100, 20, -20]→ 最大はA → A選出 →[0, 20, -20]
このように、A:B:C ≈ 5:3:2 の比で巡回し、連続選出が抑制されます。
バリデータ集合の変化への対応
バリデータの追加・削除・投票権変更は、EndBlock でアプリケーションが提案し、次のブロックHeight(H の次である H+1)で反映されます。
つまり、Height = H のブロック処理中に提案された変更は、Height = H+1 以降の Proposer 選出や voting power に適用されます。
- Block proposal(from Mempool)
選ばれたProposerは、Mempoolからトランザクションを収集してブロック案を生成し、ネットワークへブロードキャストします。
ヘッダには前ブロックハッシュ、時刻、Proposer署名などを含みます。
ブロック案は候補にすぎないため、この後の投票で支持が示されなければ先へ進みません。
提案が届かない、あるいは明らかな不整合を含む場合、バリデータは次段階で
nilを選択できます。 - Prevote
各バリデータは受信したブロック案を検証し、正しく処理可能と判断すればそのブロックにPrevoteを投じ、そうでなければ
nilに投票します。 ここで特定のブロックに2/3以上のPrevoteが集まった状態を polka と呼びます。 polka は、あるラウンドで特定のブロックに対するPrevote が 2/3 以上に到達した状態を指します。 この状態はPrecommitを行うための前提条件であり、さらにロック更新・解除の判断基準として用いられます。 Prevoteが2/3以上に達しない場合は、タイムアウト後に次のラウンドへ進みます。 - Precommit(lock / polka)
バリデータは、自身が観測したPrevoteの集計に基づき、polkaを得たブロックにPrecommitを投じます。
ロック規則は、あるラウンドで特定ブロックにPrecommitした時点でそのブロックに「ロック」され、同じ
Heightの後続ラウンドでは原則としてそのブロックにPrevote/Precommitを出し続けることを求める規則です。 別ブロックへ切り替えるのは、より新しいRoundでその別ブロックが2/3以上のPrevote(= 新しいpolka)を得たことを観測し、ロック更新・解除の条件を満たした場合に限られます。 これにより、競合候補があってもSafetyを保ちながら進行できます。 - Commit(finality) 同一ブロックに2/3以上のPrecommitが集まった時点で、そのブロックにファイナリティが与えられ、各ノードはブロックをチェーンに追加します。 ファイナライズ後はプロトコル上の巻き戻し(reorg)を行いません。 ネットワーク遅延などで条件に達しない場合は次のRoundへ進み、同じHeightのまま条件が整い次第ファイナライズします。
- ABCI processing(DeliverTx → EndBlock → Commit)
ファイナライズ後、コンセンサス層はABCIを通じてアプリケーションにブロックを渡します。
- DeliverTx 各トランザクションを実行し、署名・nonce・手数料規則・権限制御などの検査を行いながらステートを更新します。
- EndBlock 二重投票などのEvidence処理、スラッシング、報酬・罰則の計算など、ブロック末尾の処理を行います。
- Commit 新しいステートルートを返し、次のHeightへ移行します。
sequenceDiagram
autonumber
participant P as Proposer
participant V1 as Validator A
participant V2 as Validator B
participant V3 as Validator C
participant N as Gossip Network
participant A as Application (ABCI)
Note over V1,V3: Height = H, Round = r
%% Proposer selection
V1->>V1: Proposer selection(重み付きローテーション)
V2->>V2: 同期して同一のProposerを計算
V3->>V3: 同上
V1-->>P: Proposer = P(最大が同一のときは、事前定義の一意の並びで一者に決定)
%% Proposal
P->>P: Mempool から Tx を収集
P->>N: Block proposal(ヘッダ・Tx・署名)をブロードキャスト
%% Prevote
N->>V1: Proposal を受信
N->>V2: Proposal を受信
N->>V3: Proposal を受信
V1->>V1: 検証(ヘッダ/署名/整合性)
V2->>V2: 検証
V3->>V3: 検証
V1->>N: Prevote(ブロック or nil)
V2->>N: Prevote(ブロック or nil)
V3->>N: Prevote(ブロック or nil)
V1->>V1: Prevote を集計し 2/3 判定
V2->>V2: Prevote を集計し 2/3 判定
V3->>V3: Prevote を集計し 2/3 判定
Note over V1,V3: 同一ブロックへの Prevote が 2/3 以上 → polka 成立
%% Precommit + Lock
alt polka が成立
V1->>N: Precommit(対象ブロック)
V2->>N: Precommit(対象ブロック)
V3->>N: Precommit(対象ブロック)
V1->>V1: ロック規則:対象ブロックにロック
V2->>V2: ロック規則:対象ブロックにロック
V3->>V3: ロック規則:対象ブロックにロック
else polka 未達(タイムアウト)
V1->>V1: Round r+1 へ移行
V2->>V2: Round r+1 へ移行
V3->>V3: Round r+1 へ移行
end
%% Commit (finality)
V1->>V1: Precommit を集計し 2/3 判定
V2->>V2: Precommit を集計し 2/3 判定
V3->>V3: Precommit を集計し 2/3 判定
Note over V1,V3: 同一ブロックへの Precommit が 2/3 以上
V1->>V1: ブロックにファイナリティ
V2->>V2: ブロックにファイナリティ
V3->>V3: ブロックにファイナリティ
%% ABCI execution
V1->>A: DeliverTx(Tx 実行・ステート更新)
V2->>A: DeliverTx
V3->>A: DeliverTx
V1->>A: EndBlock(Evidence/報酬・罰則など)
V2->>A: EndBlock
V3->>A: EndBlock
V1->>A: Commit(新しいステートルート)
V2->>A: Commit
V3->>A: Commit
Note over V1,V3: Height H が完了 → 次のブロック Height(H+1)へTendermintの時間的目安
1ブロックのファイナライズは通常数秒〜十数秒程度で、ネットワークや設定次第では数十秒になる場合があります。 ネットワークが安定していれば1つのRoundで直ちにファイナライズされますが、提案が届かない・不正である・あるいは2/3以上に達しない場合は次のRoundへ進むため、その分だけ遅延します。
Reference
PoA
概要
PoA(Proof-of-Authority/権威証明)は、あらかじめ承認された署名者(=バリデータ。ブロックに署名して正当性を示す役割のノード)だけがブロックを作れる、許可型(参加者や権限を管理するタイプ)のコンセンサスです。 匿名多数の参加を前提とするPoW/PoSと違い、身元や組織的責任を伴う少数ノードに権限を集中させることで、短いブロック時間と高スループットを実現します。 PoAでは「誰が署名者になるか、またその交代をどう行うか」という信頼の前提が仕組みのコアです。 実際の運用では、この部分をスマートコントラクトを用いたガバナンスの仕組みとして設計し、透明性を確保しながら管理することが重要です。
PoAの仕組み
署名者集合(Validator/Sealer)
ネットワークは「署名者リスト」を管理して、どのノードがブロックを生成できるかを定めます。 多くの実装では、このリストをオンチェーンのコントラクトで保持し、投票によって署名者の追加や削除を決定します。 こうした仕組みにより、匿名のノードが大量に参加して支配しようとするSybil攻撃を防ぎ、署名者の信頼性を保ちます。
ブロック生成方式(2種類)
PoAには主に以下の2種類があります。
- スロット型PoA(Clique/Aura)
時間を一定間隔のスロットに区切り、各スロットでは順番で選ばれた署名者(
in-turn:そのスロットの担当署名者)がブロックを作成して署名します。in-turnがブロックを出せない場合は、別の署名者(out-of-turn:代替の署名者)が代わりに生成します。 Ethereum系クライアントで広く利用され、セットアップも容易です。 - BFT型PoA(IBFT2/QBFT) BFT(ビザンチン障害耐性)アルゴリズムを用い、ブロック提案→投票→承認の3段階を経て、署名者の3分の2以上の同意を得たブロックはその時点でファイナリティに達し、巻き戻ることはありません。 HyperledgerBesuでは、この方式(IBFT2/QBFT)が推奨されています。
Finalityと安全性
- スロット型 フォークが発生するとチェーン選択規則によって分岐が解消されますが、短い巻き戻り(reorg)は発生する可能性があります。 そのため、ある程度のブロックが積み重なった時点で「事実上のファイナリティ」とみなします。
- BFT型
コミット時点でブロックが即時確定します。
署名者が
n人いる場合、そのうち3f+1人の構成で最大f人が不正や故障を起こしても、2/3以上の署名が集まれば、そのブロックはファイナリティに達して合意の安全性が保たれます。
ガバナンスと運用
署名者の交代・追加・停止、投票ルールやタイムアウト設定といった運用ポリシーは、オンチェーンのコントラクトや設定で明確に定義されます。 これにより履歴が残り、透明性を確保できます。 不正行為を行った署名者は投票によって除名できます。
適用領域
PoAは、参加者を特定できる組織間ネットワークに向いています。 高スループット・低遅延を実現しやすく運用コストも低いことから、コンソーシアムチェーンや開発・テスト環境でよく利用されています。 パブリック用途でも事例はありますが、信頼をどこに置くか、中央集権度をどこまで許容するかといった設計判断が必要です。
PoAの流れ
スロット型(Clique/Aura)のフロー

sequenceDiagram
autonumber
participant V as Validator (in-turn)
participant O as Validator (out-of-turn)
participant N as Network (Gossip)
participant P as Peers
%% 1. Validator set
Note over V,O: 署名者リストはオンチェーンで管理される
%% 2. Slot assignment
V->>V: スロット割り当て(in-turn決定)
%% 3. Block proposal
V->>V: Mempoolからトランザクション収集
V->>V: ブロックを組み立てて署名
%% 4. Broadcast & verify
V->>N: ブロックをGossipで伝達
N->>P: ピアへブロックを拡散
P->>P: 署名者の正当性を確認<br/>トランザクションやヘッダーを検証
P-->>N: 不正なブロックは拒否
%% 5. Fallback sealing
alt in-turnが提案しなかった場合
O->>O: out-of-turnがブロック生成
O->>N: 代替ブロックを伝達
end
%% 6. Fork choice
alt 同じブロックHeightで複数ブロック
P->>P: フォーク選択ルールを適用
Note over P: 1. in-turnブロックを優先<br/>2. 累積難易度を比較
end
%% 7. Confirmations
P->>P: 一定の承認深さまで待機
Note over P: 十分な深さで実質的にファイナリティに達する1. Validator set
ネットワークは、誰がブロックを生成できるのかを示す署名者リストを保持します。 このリストはオンチェーンの管理コントラクトや設定ファイルで管理され、署名者の追加・削除は投票などの手続きで行われます。 これにより、署名者が正しく身元と責任を持った主体であることが保証され、Sybil攻撃(複数の名ノードを作って支配する攻撃)を防ぎます。
2. Slot assignment
時間は一定間隔のスロットに区切られ、各スロットごとにin-turn(当番)署名者が決まります。 この割り当ては、署名者リストに基づきラウンドロビン(順番に回す方式)や乱数を用いた簡易ルールで決定されます。 これにより、誰が次にブロックを提案するかが予測可能で、無駄な競争が発生しません。
3. Block proposal
そのスロットに割り当てられた署名者は、Mempoolにあるトランザクションを収集して新しいブロック案を組み立てます。 ブロックヘッダーには署名者自身の署名が含まれ、これにより「正規の署名者が生成したブロック」であることが証明されます。
4. Broadcast & verify
提案されたブロックはGossipプロトコルによってネットワーク全体に送信されます。 各ノードは、受け取ったブロックに対して以下を検証します。
- ブロックを作成したのが署名者リストに含まれるノードか
- ブロックの内容(トランザクションやヘッダー)がルールに従っているか
この検証により、不正なブロックはネットワークに広がる前に排除されます。
Gossipプロトコルは、P2Pネットワークにおけ*情報拡散の仕組みの1つです。 各ノードは自分が受け取ったメッセージを、ランダムに選んだ少数のノードへと伝えます。 受け取ったノードはさらに別のノードへ伝える、という動作を繰り返すことで、最終的にネットワーク全体に情報が行き渡ります。
この方法は、人から人へ噂(gossip)が広がっていく様子に似ているため、Gossipと呼ばれています。
5. Fallback sealing
スロットに割り当てられた署名者がその時間内にブロックを提案しなかった場合、out-of-turn(補欠)署名者が代わりにブロックを生成します。 この仕組みにより、一部の署名者がオフラインになってもブロック生成が途切れず、ネットワークは継続して稼働できます。
6. Fork choice
同じブロックHeightで複数のブロックが生成されるとフォークが発生します。 スロット型PoAでは「フォーク選択ルール(fork choice rule)」を適用し、どのブロックを正規のチェーンとして採用するかを決定します。
in-turn(割り当て署名者)が作成したブロックを優先する- 難易度の累積値を比較して、より累積難易度が大きいチェーンを選ぶ
7. Confirmations
スロット型PoAは即時のファイナリティ(finality)を持たず、チェーンが短く巻き戻る(reorg)可能性があります。
そのため、実際の利用では「十分なブロック数が積み重なったら、そのブロックは事実上ファイナリティに達した」と見なす運用をします。
これが Confirmations(承認深さによる実質的なファイナリティ)です。
BFT型(IBFT2/QBFT)のフロー

sequenceDiagram
autonumber
participant V as Validators
participant P as Proposer
participant N as Network (Gossip)
%% 1. Validator set
Note over V,P: 署名者リストはオンチェーンで管理される
%% 2. Proposer selection
V->>P: ラウンドごとに提案者を選出
%% 3. Block proposal
P->>P: Mempoolからトランザクション収集
P->>P: ブロックを組み立てて署名
P->>N: ブロックを伝達
N->>V: 提案ブロックを配信
%% 4. Prepare phase
V->>N: Prepareメッセージを送信
N->>V: 他の署名者にPrepareを転送
%% 5. Commit phase
V->>N: Commitメッセージを送信
N->>V: 他の署名者にCommitを転送
%% 6. Finality
alt Commitが2/3以上揃う
V->>V: ブロックはファイナリティに達する
else 不足
V->>P: タイムアウト → 次ラウンドの提案者へ
end1. Validator set
スロット型と同様に、署名者リストをオンチェーンのコントラクトや設定で管理します。 署名者の追加・削除は投票などで決められ、リストに含まれるノードのみが合意に参加できます。
2. Proposer selection
ラウンドごとにブロック提案者(Proposer)を決定します。 提案者は署名者リストに基づき、順番や乱数などのルールで選ばれます。
3. Block proposal
選ばれたProposerがMempoolからトランザクションを収集し、新しいブロックを作成します。 作成したブロックは署名され、他の署名者に伝達されます。
4. Prepare phase
ブロックを受け取った署名者は、提案が有効であると判断した場合にPrepareメッセージを送信します。 この段階で、署名者たちは「このブロックを次の候補として受け入れる」意思を表明します。
5. Commit phase
一定数のPrepareメッセージを受け取ると、署名者はそのブロックに対してCommitメッセージを送ります。
n 人の署名者のうち 3f+1 人構成で最大 f 人が故障または不正でも、2/3以上のCommit署名が集まれば合意は成立します。
6. Finality
2/3以上のCommit署名が揃った時点で、そのブロックはファイナリティに達し、巻き戻ることはありません。 この即時ファイナリティが、BFT型PoAの大きな特徴です。
Reference
- https://kando.tech/sites/default/files/2021-10/POA%20Whitepaper.pdf
- https://ethereum.org/developers/docs/consensus-mechanisms/poa
- https://openethereum.github.io/Permissioning
- https://openethereum.github.io/Proof-of-Authority-Chains
- https://besu.hyperledger.org/private-networks/how-to/configure/consensus
- https://besu.hyperledger.org/private-networks/concepts/poa
最後に
今回はコンセンサスアルゴリズムについてまとめてきました。
他でも色々記事を書いているのでぜひよろしければ読んでいってください!

