Develop with pleasure!

福岡でCloudとかBlockchainとか。

lnd v0.15.3-betaで発生した2度目の障害の内容

少し間が空いたけど、

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
    • マークルパスは空

つまり、呼び出された時点でスクリプトは成功するOP_SUCCESS系のopcode単体のスクリプトを1つもつTapscriptにコインがロックされている。単にコインを使用する(アンロックする)のであれば、↑のwitnessデータの内、0x50とControl Blockの2つの要素のみがあれば良い。今回はその前に500,000個の空データが余計にプッシュされている。インタープリターの処理としては、

  1. まずwitnessデータをスタックプッシュする。
    1. 500,000個の空データをプッシュ
    2. 0x50をスタックにプッシュ
    3. Control Blockのデータをスタックにプッシュ
  2. TaprootのscriptPubkey(OP_1 9bb9efbddf9d70afd3ac2cef011747236bdf90832a78b08f57d1139f07aa9185)を実行
    1. Control Blockをスタックからポップして検証
    2. 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に開示されていた模様。ただ、障害を発生するためには非標準トランザクションをマイニングするマイナーの協力が不可欠であったため、他の変更と一緒に修正することで脆弱性の修正を隠して対応する予定(脆弱性の悪用がされないように)だった模様↓

残念ながら、そのリリース前に悪用されてしまった。

Liquidにも影響

ちなみにこのトランザクションは、BlockstreamのLiquidのWatchmenにも影響し、ペグアウトが一時できなくなった模様。

使用しているrust-bitcoinのバグみたいだけど、rust-bitcoinでは数ヶ月前に修正版はリリースしていたっぽい。

状況的には、全体的にTaprootのコンセンサスについて各ライブラリがテストされてるような感じだなー。