用語集 / 開発者向けリファレンス
MSG_CMPCT_BLOCK
- MSG_CMPCT_BLOCKとは?
- MSG_CMPCT_BLOCKは、インベントリ種別4にあたる要求専用のコードです。アナウンスに現れることはなく、先に同意したピアへ送るgetdataメッセージの中でだけ有効です。
BIP-152で規定されています。
コンパクトブロックは事前に取り決めるものであり、告知されるものではありません。ピアはsendcmpctを一度送信して、コンパクトブロックを受け入れることを伝え、その後に限り、もう一方の側は新しいブロックに対してタイプ2ではなくタイプ4で応答できます。BIP152はBitcoin Core 0.13.0とともに2016年8月に登場しました。その節約こそが狙いです。受信側がすでに保有しているトランザクションを指定するのに6バイトで済み、同じものを二度送るのに要する200バイト以上をかけずに済むからです。
仕組み
MSG_CMPCT_BLOCKは、ブロックそのものではなくブロックの説明を要求します。その説明に価値があるのは、2つのノードが似通ったmempoolを保持している場合だけです。
まず取り決めを行います。sendcmpctメッセージはフラグとバージョン番号を運びます。バージョン1はトランザクションをtxidで識別し、バージョン2はwitness txidで識別するもので、分離ウィットネス以降に使われているのはこのバージョンだけです。ノードは、sendcmpctを送っていないピアへのgetdataにタイプ4を決して入れてはなりません。そのピアには、それを理解する義務がないからです。
応答はcmpctblockメッセージで、80バイトのヘッダー、8バイトのnonce、トランザクション1件につき6バイトの短縮識別子、そして完全な形で渡される少数のトランザクションを含みます。これには必ずコインベースも含まれます。受信側がそれをすでに見ていることはあり得ないからです。短縮識別子は、ブロックヘッダーとそのnonceから鍵を導いたSipHashで生成されるため、ブロックごと、リクエストごとに異なります。このランダム化は防御策です。固定の方式では、攻撃者が衝突する2つのトランザクションを事前に計算し、ネットワーク全体の再構築を一度に妨害できてしまいます。
受信側は識別子を自身のmempoolと照合し、不足分をgetblocktxnで要求して、ブロックをローカルで再構築します。その後の検証は通常どおりで、コンセンサスルールには一切触れません。
深さには制限があります。Bitcoin Coreがコンパクトブロックを提供するのは直近5ブロックだけで、それより古いブロックの要求には完全なブロックで応答します。そこまで遅れている受信側には役立つmempoolがなく、結局はブロック内のすべてのトランザクションを要求することになるからです。
確認できる場所
MSG_CMPCT_BLOCKが最も明確に確認できるのはBitcoin Core自身のログで、再構築がどれだけうまくいったかを報告します。
ノードを-debug=cmpctblockを付けて起動すると、新しいブロックごとに、あらかじめ埋められたトランザクションが何件あったか、mempoolで見つかったものが何件あったか、取得が必要だったものが何件あったかを示す行が出力されます。何時間も稼働しているマシンでは、取得件数は通常ゼロで、ブロックは一メガバイト半ではなく数十キロバイトで届きます。3,000件のトランザクションを含むブロックには、ヘッダーとcoinbaseに加えて18,000バイトの短縮識別子が必要です。
その計算は、起動したばかりのノードでは成り立ちません。mempoolが空であればすべての識別子が一致せず、続く要求はブロック全体を求めるものになり、往復が増える分だけ、コンパクトな経路はブロックをそのまま要求するより遅くなります。だからこそこのコードはチェーンの先端に位置するノードのものであり、初期同期の間には決して現れません。
自宅でノードを運用する人にとって、これは、通常の接続がネットワークの進みに追随し続けるか、ブロックが見つかるたびに遅れを取るかを決める機能です。