少し間が空いたけど、
techmedia-think.hatenablog.com
の障害からそんなに間を開けずに、再度LNDでチェーン同期ができなくなる障害が発生したので、その内容をまとめておく。
障害の原因
障害のトリガーとなったは、500,142 byte(125,109 vbyte)のこのトランザクション。
トランザクションには1つのインプットと1つのアウトプットがあり、アウトプットは話題に挙がった
you'll run cln. and you'll be happy.
というデータがOP_RETURN
で書かれているだけ。
インプットが参照するUTXOは、このUTXO。TaprootのUTXOであることが分かる。
サイズが大きいのはインプットのwitnessデータ(500,042 byte)で、以下のデータで構成されている。
- 500,000個の空データ
0x50
:TapscriptではOP_SUCCESS80
として機能c11dae61a4a8f841952be3a511502d4f56e889ffa0685aa0098773ea2d4309f624
:Tapscript利用時のControl Blockで、- Control Byte:
c1
- Taprootの内部鍵:
1dae61a4a8f841952be3a511502d4f56e889ffa0685aa0098773ea2d4309f624
- マークルパスは空
- Control Byte:
つまり、呼び出された時点でスクリプトは成功するOP_SUCCESS
系のopcode単体のスクリプトを1つもつTapscriptにコインがロックされている。単にコインを使用する(アンロックする)のであれば、↑のwitnessデータの内、0x50とControl Blockの2つの要素のみがあれば良い。今回はその前に500,000個の空データが余計にプッシュされている。インタープリターの処理としては、
- まずwitnessデータをスタックプッシュする。
- 500,000個の空データをプッシュ
0x50
をスタックにプッシュ- Control Blockのデータをスタックにプッシュ
- TaprootのscriptPubkey(
OP_1 9bb9efbddf9d70afd3ac2cef011747236bdf90832a78b08f57d1139f07aa9185
)を実行- Control Blockをスタックからポップして検証
0x50
を評価した時点で、成功判定(スタックには500,000個の空データが残ったまま)
という処理が実行される。
LNDがライブラリとして使用しているbtcdでは、(DoS対策としているが)witnessデータの最大要素数を500,000個に制限していたため、それを超える↑のトランザクションを不正なトランザクションとして処理してしまったのが今回の障害の原因。
マイナーの協力が必要
前回の障害と違うのは、↑のトランザクションは以下の2つの理由から非標準トランザクションであること。
- まずトランザクションサイズが125,109 vbyteで、これは標準ルールの制約である100,000 vbyteの上限を超えている。
OP_SUCCESS
系のopcodeが含まれている。これらのopcodeは、将来のopcodeの拡張のため従来予約されていたOP_NOP
系のopcodeの取り回しを改善するために導入されたもの。現状Tapscriptの実行中にこれらのopcodeが登場した場合、非標準として処理される。
非標準トランザクションはBitcoin Coreではmempoolへは受け入れられずリレーもされない。それでもコンセンサスルールとしては有効なので、マイナーの協力があればブロックに格納することができる。ブロックに格納されていれば非標準トランザクションでも↑のインタープリターの処理が実行され有効なトランザクションとして判定される。
なので、このトランザクションのマイニングに協力したマイナーがいたということ。トランザクションアウトプットはOP_RETURN
のアウトプットのみなので、インプットのビットコイン(0.03682719 BTC)はすべてマイナーの手数料になる。これが報酬?
↑のスクリプト見る限り署名検証の必要はないので、むしろマイナーは500,000個の空データをプッシュ部分削除して、単に0.03682719 BTCだけ頂くということも可能よね。
修正内容
修正内容は、btcdのwitnessデータの最大要素数のチェックの値を500,000から4,000,000(コンセンサスである最大トランザクションweight)に引き上げるというもの↓
https://github.com/btcsuite/btcd/pull/1907/files
責任ある開示
もともとこのバグ自体は、Anthony Townsによって発見され、LNDとbtcdのリードメンテナである@roasbeefに開示されていた模様。ただ、障害を発生するためには非標準トランザクションをマイニングするマイナーの協力が不可欠であったため、他の変更と一緒に修正することで脆弱性の修正を隠して対応する予定(脆弱性の悪用がされないように)だった模様↓
also @ajtowns did contact me, by making an issue on my public fork of btcd w/ details, as the post was public I deleted it then followed up w/ him via email
— Olaoluwa Osuntokun (@roasbeef) 2022年11月1日
we had a patch ready to go for the minor release (w/ some other memory optimizations), but obv this preempted it
残念ながら、そのリリース前に悪用されてしまった。
Liquidにも影響
ちなみにこのトランザクションは、BlockstreamのLiquidのWatchmenにも影響し、ペグアウトが一時できなくなった模様。
The Liquid Federation Watchmen are currently affected by a bug in the rust-bitcoin library, related to the recent non-standard transaction. A fix has been identified and will be made available shortly. L-BTC funds are not at risk. Peg-outs will experience a temporary delay.
— Liquid Network 🌊 (@Liquid_BTC) 2022年11月1日
使用しているrust-bitcoinのバグみたいだけど、rust-bitcoinでは数ヶ月前に修正版はリリースしていたっぽい。
状況的には、全体的にTaprootのコンセンサスについて各ライブラリがテストされてるような感じだなー。