コンセンサスアルゴリズム
はじめに
初めまして。
『DApps開発入門』という本や色々記事を書いているかるでねです。
以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください!
今回はコンセンサスアルゴリズムについてまとめていきます。
「PoW」、「PoS」、「Tendermint」、「PoA」についてまとめています。
PoW
Proof-of-Work(PoW)は、新しいブロックを作るときに「特定の条件を満たすまでハッシュ計算を繰り返す」仕組みです。
このような条件を満たすことは膨大な計算を必要とするため、ブロックがその条件をクリアしていること自体が「正しく作られた証拠」になります。
これにより、誰か特定の管理者に頼ることなく取引の記録を並べ、矛盾のない履歴を維持できます。
ハッシュ
ここで使われる「ハッシュ」とは、データを一定の長さの値に変換する関数のことです。
BitcoinではSHA-256という暗号学的ハッシュ関数を用いており、入力データを少しでも変えると結果の値が大きく変わるという特徴があります。
以下のサイトで動作を確認できます。
「データ」部分に任意の値を入力すると、「ハッシュ」部分の値が全く異なる値になります。
Hello
Hello
185f8db32271fe25f561a6fc938b2e264306ec304eda518007d1764826381969
Hello
Hello
の後ろにスペースを入れているだけですが、ハッシュ値はHello
とは全く異なる値になっています。
Hello
2ec5a3f0c2fc3e6dcee0f6f3a5735a6c69d2056579a5452095b75802094043a8
Hello World
Hello World
a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
PoWの仕組み
PoWの仕組みについて詳しく説明していきます。
1. ブロックヘッダの組み立て
前ブロックのハッシュ、トランザクションから計算したマークルルート、タイムスタンプ、nBits、nonceを入れてブロックヘッダを作成します。
-
前ブロックのハッシュ(Previous Block Hash)
直前のブロックのヘッダをdoubleSHA-256した値。
この値を含めることで、ブロック同士が鎖のようにつながり、ひとつでも改ざんすると以降すべてが無効になります。 -
マークルルート(Merkle Root)
そのブロックに含まれる全トランザクションをMerkle Treeにまとめ、そのルートにあたるハッシュ。
任意のトランザクションがブロック内に含まれているかどうかを効率よく検証できます
coinbase(マイナーが報酬を受け取るトランザクションで、ブロック内の最初に格納される)を変えるとマークルルートが変わり、ヘッダ全体も変わります。 -
Timestamp
ブロックを作成したおおよその時刻(UNIX時刻形式)。
ノードの時刻に依存するため、正確な時刻を保証するわけではないです。
ネットワークが「未来すぎる時刻」や「過去すぎる時刻」のブロックを拒否するため、だいたいの時間順序を守る役割を持ちます。 -
nBits(難易度の圧縮表現)
難易度を短く表した値で、ここから「target(閾値)」を復元します。
targetが小さいほど条件は厳しく、必要な計算量が増えます。
つまり「どれだけ先頭に0を揃えなければならないか」を決める基準です。 -
nonce(ナンス)
32bitのカウンタ。
PoW計算のために総当たりで値を変えていく部分。
使い切ったらcoinbase内のextraNonce(coinbase内の任意データを入れられる領域。ここを更新するとマークルルート全体が変わるので、nonce
を使い切った後も新しい探索空間を得られる)を更新してマークルルートを変え、探索空間を広げます。
2. 目標値(target)を決めます
ブロックヘッダには nBits
というフィールドがあり、これは難易度を短く表した圧縮形式です。
マイナーはこの nBits
を展開し、実際に使う256ビットの数値である target を計算します。
PoWにおける判定条件は非常に単純で、ヘッダ全体をSHA-256で二回ハッシュ化した結果(digest)が、この target
以下であるかどうかです。
この「digest ≤ target
」という条件は、「ハッシュの先頭にいくつゼロが並んでいるか」を確認することと同じ意味になります
target
が小さくなるほど、より多くのゼロを揃えなければならず、達成が難しくなります。
例えば先頭に20ビットのゼロが必要であれば、成功確率は 1/2^20 であり、平均して 2^20 回の試行が必要です。
ゼロの数が1ビット増えるたびに、必要な計算量はおおよそ2倍に膨らんでいきます。
3. ナンス探索を行います
マイナーはこの条件を満たすブロックを探すため、ブロックヘッダをハッシュ化し続けます。
具体的には、ヘッダ内の nonce という32ビットのカウンタを少しずつ増やしながらdoubleSHA-256を計算し、その結果が target
以下になるかどうかを何度も試みます。
nonce
をすべて試しても条件を満たす結果が得られなければ、coinbaseトランザクション内のextraNonceを変更します。
これによりマークルルートが変わり、ブロックヘッダ全体も変化するため、新しい探索空間で再び計算を続けられます。
この探索作業は純粋に確率に依存しているため、いつ条件を満たせるかは予測できません。
ただし target
が小さいほど、つまり難易度が高いほど、成功までに必要な試行回数は指数的に増えていきます。
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
- https://bitcoin.org/files/bitcoin-paper/bitcoin_jp.pdf
- https://developer.bitcoin.org/reference/block_chain.html
- https://learnmeabitcoin.com/technical/block/bits
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
のグループ)が選ばれます。
PoSのconsensusは LMD-GHOST
と Casper FFG
で構成されています。
LMD-GHOST
はfork choice ruleとして「どのブロックを先頭とみなすか」を決定し、Casper FFG
はチェックポイントに基づいて justification
と finality
とみなします。
Ethereumのfinalityは、提案された直後のブロックではなく複数のブロックを経たチェックポイントで成立します。
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
が再び成立するように設計された仕組みです。
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の流れ
-
役割の決定(
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
をブロックに含めます。 -
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:ビザンチン耐性)コンセンサスアルゴリズムです。
特徴は以下の3つです。
-
即時ファイナリティ
PoWのような「確率的ファイナリティ」ではなく、バリデータの投票が2/3以上集まれば即座にファイナライズします。 -
マイニング不要
計算競争は行わず、合意形成は投票によって決まります。 -
ABCIによる汎用性
Tendermintはコンセンサス処理を担う仕組みを提供し、アプリケーションはABCI(Application Blockchain Interface)を通じて連携します。
これにより、開発者はコンセンサスの実装を自ら行う必要がなく、ABCIを介してトランザクションの検証や状態管理といったアプリケーション固有の処理を実装できます。
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を満たした)ことを観測し、ロック更新または解除の条件を満たした場合にのみ許可されます。
これにより、競合ブロックで矛盾するファイナリティが同時成立することを防ぎます。
即時ファイナリティ
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が選ばれます。
ここまでで合意は成立していませんが、「誰が提案するか」が決まります。
-
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へ移行します。
-
DeliverTx
Tendermintの時間的目安
1ブロックのファイナライズは通常数秒〜十数秒程度で、ネットワークや設定次第では数十秒になる場合があります。
ネットワークが安定していれば1つのRoundで直ちにファイナライズされますが、提案が届かない・不正である・あるいは2/3以上に達しない場合は次のRoundへ進むため、その分だけ遅延します。
Reference
- https://docs.tendermint.com
- https://github.com/tendermint/tendermint
- https://tendermint.com/static/docs/tendermint.pdf
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)のフロー
1. Validator set
ネットワークは、誰がブロックを生成できるのかを示す署名者リストを保持します。
このリストはオンチェーンの管理コントラクトや設定ファイルで管理され、署名者の追加・削除は投票などの手続きで行われます。
これにより、署名者が正しく身元と責任を持った主体であることが保証され、Sybil攻撃(複数の名ノードを作って支配する攻撃)を防ぎます。
2. Slot assignment
時間は一定間隔のスロットに区切られ、各スロットごとにin-turn(当番)署名者が決まります。
この割り当ては、署名者リストに基づきラウンドロビン(順番に回す方式)や乱数を用いた簡易ルールで決定されます。
これにより、誰が次にブロックを提案するかが予測可能で、無駄な競争が発生しません。
3. Block proposal
そのスロットに割り当てられた署名者は、Mempoolにあるトランザクションを収集して新しいブロック案を組み立てます。
ブロックヘッダーには署名者自身の署名が含まれ、これにより「正規の署名者が生成したブロック」であることが証明されます。
4. Broadcast & verify
提案されたブロックは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)のフロー
1. 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 Whitepaper.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
最後に
今回はコンセンサスアルゴリズムについてまとめてきました。
他でも色々記事を書いているのでぜひよろしければ読んでいってください!
Discussion