152013年3月11〜12日
ビットコインが二つの有効な歴史を持った夜
ビットコインコアの新旧バージョンは、一つのブロックについて意見が一致しなかった。開発者やマイナーは、数時間のうちにどのブランチをサポートするかを決定しなければならなかった — そして、そのために捨てられた労力を払った。
2013年3月11日の夕方、ビットコインのノードは同じ過去から二つの異なる履歴を伸ばし始めた。新しいBitcoin 0.8はブロック225 430を受け入れ、その先にブロックをつないだ。一方、バージョン0.7を使う一部の古いノードは拒否した。処理に必要なデータベースロックの数が、Berkeley DBの実際の上限を超えたためだ。双方とも自分のソフトウェアに従い、自分のチェーンを有効と判断していた。当初は新しい側にマイニングプールの計算能力の大半が集まっていた。待つだけでは解決よりも分裂の深まりが懸念された。開発者、取引所、プール運営者がIRCに集まった。中央の司令塔がないなか、十分な数の参加者が再び同じ履歴をたどれる道を探さなければならなかった。
一つのブロック、 二つの判決
ブロック225 430は、ネットワークを分割することを目的として作成されたものではなかった。ただし、それまでのブロックよりも多くのトランザクション入力を含んでいたため、データベースに異常な負荷がかかり、バージョンの違いを明らかにした。Bitcoin 0.8はLevelDBを使用しており、ブロックを処理した。一方、Berkeley DBを使用していたバージョン0.7は、ロックの数に達してエラーとなった。
結果は危険なほどに目立たなかった。両方のノードグループは、プログラムが実行できる範囲で規則を遵守していた。新しいブランチは、意図されたコンセンサスルールに従って偽物ではなく、古いノードは攻撃されなかった。ネットワークは、ドキュメント化されていない一つのデータベース技術の実用的な制限のため、分裂した。
0.8バージョンのマイナーは新しいブロックの上に構築していた。古いバージョンのマイナーはその前のブロックから続けていた。両方のブランチがさらにブロックを獲得すると、一方のブランチで確認された取引がもう一方のブランチでは存在しない可能性が出てきた。通常の確認回数に頼ることはできなくなり、経済的多数派がどちらの歴史を受け入れるかが明らかになるまで、ユーザーは安全に取引できない状態になった。
新しい枝は最初に約六十パーセントの性能を持っていた。通常の状況では、累積された労働量が大きい方のチェーンが優位性を獲得する。しかし、この場合、古いノードは、新しいブロックを受け入れることができなかった。再編成自体は、ローカルの検証ソフトウェアが無効とみなすブロックを超越することはない。
この事件は、「最も長いチェーンが勝つ」という単純なルールの限界を明らかにした。より正確に言えば、ノードが最初に有効と認識するチェーンの中で、最も多くの計算量を持つチェーンが勝つ。ノードが有効性について一致しない場合、ハッシュレートだけでは即時の統一には十分ではない。
IRCは臨時の指令室として
開発者たちは、監視しているノードの高さやハッシュが異なり始めたときに問題に気づいた。通信はIRCチャンネルに集中し、そこではログやブランチのパフォーマンス、また大きなプールの反応を比較することができた。Gavin Andresenは後にBIP 50で、時間軸や夜間に下された決定を記述した。Gavin Andresen
完全に正しい枝と明らかに誤った枝の選択肢はなかった。0.8バージョンのサポートは、より多くの労力を伴うチェーンを維持するものだったが、多くの古いノードを切り離すことになった。0.7の枝に戻ることは、新しいマイナーを説得して、すでに正当に採掘したブロックを放棄し、報酬を期待していたブロックを諦めさせることを意味した。
実用的理由として戻ったのは互換性であった。0.8バージョンは古いブランチで作成された小さいブロックを受け入れることができたのに対し、0.7ノードは新しいブランチの問題のあるブロックを受け入れることができなかった。パフォーマンスが両方のグループに受け入れられるブランチに移行すれば、ネットワークはすべての古いノードの強制的なアップグレードなしで再び統一されることができる。
その決定は、Andresenがプロトコルを通じて出せる命令ではなかった。開発者はプールの運営者に連絡して状況を説明し、取引所には入金を一時停止するよう勧めた。Bitcoin.orgも警告を掲載し、大手プールに古いバージョンへ戻すよう呼びかけた。新旧どちらのソフトウェアでも受け入れられるチェーンに、ネットワークを再びまとめるためだった。
この調整は、主要な参加者の輪がまだ比較的小さく、人々が公開チャネルから互いに知り合っていたため、迅速に進められた。スピードは、ネットワークを長期的な分裂から救うのに役立ったが、同時に、初期の運用が依存していた社会的つながりを明らかにした。ビットコインにはリーダーはいなかったが、大きな影響力を持つ人々がいて、彼らの電話一本やメッセージ一つで、大きな力関係が変化することができた。
IRC上の対話は、法的拘束力も秘密の管理者鍵も持たなかった。その意義は、異なる介入手段を持つ人々を一つの場所に集めた点にあった。開発者は原因を説明でき、プールはハッシュレートを転向でき、取引所は入金を停止でき、ノード運営者はバージョンを変更できた。各ステップにはそれぞれ固有のリスクがあり、他者が従うことを誰にも保証できなかった。したがって、バージョン0.7と互換性のあるブランチを支持する決定は、ネットワークの中心からの技術的命令ではなく、この道が最も速く共通の履歴を回復し、ユーザーへの影響を最小限に抑えるという協調的な賭けであった。その成功は、当時のコミュニティの小さな規模から切り離して語れるものでもなく、普遍的な危機対応手順として持ち出すものでもない。
プールは採掘した労力を犠牲にした
決定的な行動を取ったのは、Eleuthriaの名で知られるMichael Marseeが運営するBTCGuildと、Marek PalatinusのSlush Poolだった。両者はバージョン0.8から0.7に戻し、計算能力を古い側のチェーンへ振り向けた。これによって、二つの履歴に積み重なった計算作業量の優劣が変わり始めた。
これは無償の行為ではなかった。再編成の際に廃止された枝で採掘されたブロックは、最長のチェーンの一部ではなくなったため、その報酬は支払われるべきではなかった。BIP 50は、プールがネットワークを共通の枝に戻すために多大な金額を犠牲にしたことを明示的に記している。
より古い枝が先行したとき、更新されたノード0.8はそれを採用し、履歴を再編成することができた。古いノードはそれに既に存在していた。分岐は、一つのバージョンが別のバージョンを遠隔で上書きしたことによって終了したのではなく、多くのマイナーが検証できるポイントの上でより多くの仕事を作成したことによって終了した。
この事件の際に、少なくとも一つの大きなダブルスペンドが発生し、これは実験とみなされ、計画的な攻撃ではなかった。しかしながら、この出来事は現実的なリスクを示した:取引は後に放棄される分岐上で確認される可能性があった。入金を停止するという勧告は、パニックによるものではなく、サービスを一時的な履歴に基づく会計残高から保護するためのものだった。
この時点で、プールはネットワークを所有していなかった。プールは、採掘者が与えた計算能力によってブロックの順序を影響させることができたが、全ノードが任意のルールを受け入れることを強制することはできなかった。その成功は狭い目標に依存していた。つまり、古いノードと新しいノードの両方が有効であると見なす枝を作成し、それに最も多くの仕事を提供することだった。
勝利の神話ではなく、障害の検証を残す
Gavin Andresenは後に、この障害をBIP 50にまとめた。そこには、ネットワークが何の問題もなく動いたとは書かれていない。原因と経過、失われたブロック、二重支払い、そして同様の不一致を早く見つけるための対策が説明されている。分析を公開したことで、あの夜の経験は当事者の記憶だけにとどまらず、ほかの開発者も学べる記録になった。
この一件が教えたのは、コンセンサスがコメントや文書に書かれた規則だけで決まるわけではないということだ。広く使われているプログラムの実際の動作が、意図せずネットワークの制約になる場合がある。誰も通貨の仕組みに関わるものとして設計していなくても、そうなる。だから、別のデータベースへの移行によってブロックを受け入れる判断が変わり得るなら、単なる内部変更として扱ってはいけない。
さらに得られた教訓は、アップグレードの調整をより慎重に行い、ブロックを運用上の限界に近いところでテストする必要性であった。0.8バージョンはパフォーマンスの改善をもたらしたが、違いは実際のチェーンで初めて現れた。インシデントの後、開発者たちは一時的な制限を導入し、古い依存関係を後で安全に放棄できる道を準備した。
この話は、時にはビットコインは数人の開発者によって管理されているという証拠として使われることがあり、また別の時には自動的に破壊不可能であるという証拠として使われることがある。しかし、これらの簡略化された説明のいずれも当てはまらない。人々は修正の調整を急ぐことができたが、プールや取引所、ノードの運営者の協力が必要だった。ソフトウェアは各コンピューターで個別に判断を下し、共通の結果はこれらのコンピューターの連携によって初めて生まれた。
3月11日から12日にかけての夜は、一つのメインチェーンを取り戻して終わった。ただし、不一致が自然に消えたわけではない。問題を知らせた人がいて、サービスを止めた人がいて、互換性のある履歴に戻すために、それまでの計算作業を犠牲にしたマイナーがいた。ビットコインが二つに分かれた過去を乗り越えられたのは、規則と経済的な負担、そして今回は新しいソフトウェアが譲る必要があると認めた人々のおかげだった。
BIP 50の価値は、この障害を「分散化の勝利」という一言で片づけていないことにある。具体的な原因、時系列、失われた計算作業、同じような事態を防ぐための対策が記録されている。認めたくない失敗が、次のテストの土台になるのだ。それでも問いは残る。互換性があると考えている二つのバージョンの間に、書かれていない前提はいくつ潜んでいるのか。コンセンサスは紙の上の規則だけではない。独立した実装とノードが、境界条件に当たるケースでも同じ結果にたどり着く必要がある。その一致の大切さは、失われたときに最もはっきりする。
Atlasの人物と用語
出典と、この物語で確認できる範囲
- 01BIP 50 — 三月 2013 チェーンフォーク事後分析
主な技術的報告は、原因、ハッシュレート、BTCGuildとSlush Poolの調整、ダブルスペンド、そして対策について述べています。
- 02Bitcoin.org — 11/12 三月 2013 チェーンフォーク情報
当時のネットワーク分裂期間中の商人やユーザー向けの一般的な警告。
- 03Bitcoin Core — バージョン0.8.0 リリースノート
新しいデータベース層とバージョンの変更の文脈において、予期せぬ非互換性が現れた。