LNでは送金の度に残高を更新したコミットメントトランザクションを新しく作り署名する。チャネルを閉じる際には、
の2パターンがある。前者であれば両者が新しくトランザクションを作成するのでその時点の手数料市場を参考に手数料を再設定する余地があるが、後者の場合、手数料面で問題が発生する。コミットメントトランザクションを作成し署名した時点から、チャネルをクローズするためにコミットメントトランザクションをブロードキャストするタイミングまでかなり時間が経過しているケースの場合、トランザクション作成時に設定した手数料と比べて、ブロードキャスト時の手数料はその時点の手数料市場からみて低すぎたり、高すぎたりする場合が考えられる。
高めの手数料の場合は単純に手数料を損するだけだが、手数料が低い場合は以下のような問題が発生する。
- 相手がオフラインで自分がコミットメントトランザクションをブロードキャストした場合、自分の残高のアウトプットは
OP_CSV
により相対的なタイムロックされているが、そのタイマーが稼働開始するのはコミットメントトランザクションがブロックに格納されてからであるため、コミットメントトランザクションがブロックに格納されるまで時間がかかるとタイマーの開始も遅くなり、長時間自分の資金がスタックされる。 - マルチホップ支払いのためのHTLCアウトプットがタイムアウトする。単純にチャネル参加者2者の残高を管理しているアウトプットは一方に
OP_CSV
を使ったタイムロックが設定されているが、これは相対的なロックタイムなので問題にならない。しかし、マルチホップのHTLCアウトプットに設定されているタイムロックはOP_CLTV
を使った絶対時間によるタイムロックなので、この部分とトランザクション承認の遅延が問題になる。もしコミットメントトランザクションがHTLCの絶対時刻までにブロックに含まれない場合、タイムアウトによる払い戻しが可能になり、HTLCの資金を失う可能性がある。また先日書いた以下のような攻撃手法も考えられる↓
techmedia-think.hatenablog.com
こういった問題に対応するために、現在提案されているのがAnchor Outputと呼ばれる新しいチャネルタイプ↓
Anchor Output
コミットメントトランザクションの手数料自体はトランザクション作成時に決まってしまうので、その際の手数料は最小限に設定しつつ、CPFP(Child Pay For Parent)*1を使って手数料をバンプできるようにするために追加されるのがAnchor Output。
CPFP carve-out
なお、この仕組みをワークさせるために事前にBitcoin Core 0.19.0でCPFP carve-outというトランザクションリレーポリシーが追加された。もともと親子関係のあるトランザクションについてBitcoin Coreでは、メモリプールのトランザクションに25の子孫があった場合、 もしくはトランザクションとその全ての子孫が101,000vbyteを超えていた場合、 新しく受信したトランザクションもその子孫であれば無視するという制限がある。マルチパーティのトランザクションにおいてこれを悪用し、攻撃者が予めメモリプールに自身の作った子孫Txを大量に作ることで、相手にCPFPを使わせないといった攻撃が可能になる。そのためこの条件を緩和し、子孫がトランザクションの直接の子であり、子のサイズが 101,000 vbyte以下の場合、もう1つの子トランザクションの受け入れを許可するというもの。つまり、パッケージ制限を突破できる子トランザクションの条件は
- 子トランザクションの未承認の親は1つだけ。
- 子トランザクションのサイズが制限値以内。
- 親のアウトプットを使用するのは新しく追加しようとする子トランザクションで2つめであること(多分3つめ以降は他の条件を満たしていても追加できない)。
これによりペイメントチャネルのようなマルチパーティコントラクトのアウトプットに対して、CPFPによる手数料のバンプを両者が確実に実行できることが保証される。
Anchor Outputの仕組み
通常コミットメントトランザクションは自分と相手の残高をセットした2つのアウトプットを持つ(マルチホップの場合HTLCアウトプットが追加される)。
Anchor Outputの追加
この従来のコミットメントトランザクションについて、チャネル参加者につき1つ、(現状ペイメントチャネルの参加者は2名なので)合計2つのAnchor Output(to_local_anchor
とto_remote_anchor
)を新たに追加する。このアウトプットにロックされる資金は1アウトプット辺り330satoshi(P2WSHのdust limit)と少額なもので、チャネル開設者が資金をセットする。
Anchor Outputのスクリプトは以下の構成になっている↓
<local_funding_pubkey/remote_funding_pubkey> OP_CHECKSIG OP_IFDUP OP_NOTIF OP_16 OP_CHECKSEQUENCEVERIFY OP_ENDIF
チャネル参加者であればすぐに使用可能で、コミットメントトランザクションがブロックに格納されて16ブロック経過したら誰でも利用可能になる。これはこの少額のUTXOによるUTXOセットの汚染を防ぐため。Anchor Outputの署名鍵がlocal_funding_pubkey/remote_funding_pubkey
になっているのも、第三者がこのUTXOを回収できるようにする(redeem scriptを計算できるようにする)ため。
他のアウトプットに1 OP_CSV
の条件を追加
コミットメントトランザクションに2つのAnchor Outputを追加したので、チャネル参加者の両者がすぐに子トランザクションを作成できるようになる訳だが、CPFP carve-outにより許可されるのは2つまでだと思われるので、このAnchro Output以外にすぐ使用可能なアウトプットがあるとまずい。そのため、コミットメントトランザクション内の非Anchro Outputのアウトプットのスクリプトには1 OP_CSV
の条件が付与される。つまり既存のコミットメントトランザクションのアウトプットには1ブロックの相対タイムロックが付与される。
その他
Anchor Outputはコミットメントトランザクションをブロードキャストした際、どちらの参加者が手数料を支払うかについて選択肢を与えることにもなる。両者それぞれが使用可能なAnchor Outputを1つずつ持つので、素早くブロックに含めたい方がCPFPで手数料を付与できる。
というのが現状のAnchor Outputの仕組み。仕様はまだ正式にBOLTにマージされてるわけではないので、今後変更が入る可能性もある。ちなみに先日リリースされたlnd v0.10.0-betaにはすでにAnchor Commitmentの機能が実験的に導入されている↓