Develop with pleasure!

福岡でCloudとかBlockchainとか。

LNDに実装されたStatic Channel Backup

先日リリースされたLND 0.6-beta↓

Release lnd v0.6-beta · lightningnetwork/lnd · GitHub

で新しくStatic Channel Backup機能が導入された。

通常のオンチェーンの場合であれば、全てのトランザクションはチェーン上に記録されているためバックアップは簡単で、BIP-32ベースのマスターシードさえ管理できていれば、自身の資金を失うことはない。

techmedia-think.hatenablog.com

ただ、Lightning Networkのようなペイメントチャネルを利用したオフチェーン決済の場合、これが難しくなる。オフチェーンの決済情報は二者間でしか管理していない。

オフチェーン決済は、二者間のマルチシグにロックされた資金をインプットとし、決済の度にアウトプットの両者の残高を更新していく。つまり、決済が行われる度に、このチャネルの状態が変化していく。古い状態がブロードキャストされるのを防ぐため、両者は古い状態のトランザクションを無効にするためのシークレットを交換する。もし古いチャネル状態のトランザクションがブロードキャストされると、その取引相手は交換したシークレットを使ってチャネルの資金を全て総取りすることができる。このペナルティが不正の防止策として機能する。

このため、両者は各チャネルの状態で使用している鍵や相手の署名、旧状態を無効化するためのシークレットを管理しなければならない。これらのデータを失うと、自分の資金が取り戻せなくなったり、バックアップが古かった場合、不正をする意図はなくても最新の状態と勘違いをして古いチャネル状態のトランザクションをブロードキャストしてしまうかもしれない。このようにチャネルのバックアップには課題がある。

Static Channel Backupの仕組み

Static Channel Backup(SCB)の仕組みはシンプルで、最新のチャネル状態を維持するための仕組みではなく、チャネルのオープン時にバックアップを作成しておき実際のリカバリーはData Loss Protection (DLP)プロトコルを使用する。

いくらバックアップをしていたとしても、データを失ったらそのバックアップがチャネルの最新状態を保管したものであるかの保証はなく、古いコミットメントをブロードキャストしてしまうとチャネルの資金を失ってしまうので、そういうリスクを冒さないようDLPプロトコルを使って資金をリカバリーする。DLPプロトコルは、チャネルを接続していたリモートピアに再接続し、リモートピアにチャネルを強制的にクローズするよう通知する仕組み。そうすることで、自分が誤って古い状態のトランザクションをブロードキャストするのを防ぐ。

このため、SCBを使ったバックアップは特定のチャネルについて1回のみ取得すればよく、チャネルが閉じられるまで有効である。完全にデータをロスした場合、このバックアップが最終的なリカバリー方法となる。資金を完全に回収するには、チャネルを閉じる必要があることに注意すること。

バックアップ/リカバリー方法

SCB機能では、チャネルをバックアップおよびリカバリーするための複数の安全な方法を公開している。

ファイルを使ったバックアップ

最も簡単なバックアップ+リカバリーの方法。

lndは現在、その他のすべてのファイルを格納している場所と同じ場所(.lnd/data/chain/bitcoin/mainnet/channel.backup)でchannels.backupファイルを管理している。ユーザーはいつでもこのファイルを安全にコピーおよびバックアップできる。

チャネルがオープンまたはクローズする度に、lndはこのファイルを最新のチャネル状態で更新するので、ユーザーはファイルへの変更を検知し、それらを自分にバックアップ場所にアップロードするスクリプトを作っておくだけで良い。ファイルの変更検知については、fsnotifyなどを利用すればいい。

また、ファイルはユーザーのシードから導出した鍵を使ってAEAD方式で暗号化されているため、クラウドストレージやSDカードなどにそのまま安全に保存できる。

リカバリーする際は、restorechanbackupコマンドを使う。

$ lncli restorechanbackup --multi_file /path/to/copied/channel.backup

上記コマンドにより、リモートピアに強制的にチャネルをクローズするよう通知がいく。リモートピアがチャネルをクローズすると、資金がオンチェーンウォレットに戻ってくる。

gRPCを使ったバックアップ

2つめの仕組みは、新しく追加されたSubscribeChanBackups ストリーミングgRPCを使う、より上級者向けの方法。このgRPCを使うと、ベースとなるSCBの状態が変わる度に、新しい通知を受け取ることができる。上記のようなフィルシステムの通知よりも、より複雑なバックアップの仕組みを構築することができる。

cliやRPCを使ってバックアップを要求

最後の方法は、単一のチャネルまたは全てのチャネルのバックアップをcliやRPCで要求する方法。以下のようにcliで要求できる。

$ lncli --network=simnet exportchanbackup --chan_point=29be6d259dc71ebdf0a3a0e83b240eda78f9023d8aeaae13c89250c7e59467d5:0
{
    "chan_point": "29be6d259dc71ebdf0a3a0e83b240eda78f9023d8aeaae13c89250c7e59467d5:0",
    "chan_backup": "02e7b423c8cf11038354732e9696caff9d5ac9720440f70a50ca2b9fcef5d873c8e64d53bdadfe208a86c96c7f31dc4eb370a02631bb02dce6611c435753a0c1f86c9f5b99006457f0dc7ee4a1c19e0d31a1036941d65717a50136c877d66ec80bb8f3e67cee8d9a5cb3f4081c3817cd830a8d0cf851c1f1e03fee35d790e42d98df5b24e07e6d9d9a46a16352e9b44ad412571c903a532017a5bc1ffe1369c123e1e17e1e4d52cc32329aa205d73d57f846389a6e446f612eeb2dcc346e4590f59a4c533f216ee44f09c1d2298b7d6c"
}

$ lncli --network=simnet exportchanbackup --all
{
    "chan_points": [
        "29be6d259dc71ebdf0a3a0e83b240eda78f9023d8aeaae13c89250c7e59467d5:0"
    ],
    "multi_chan_backup": "fd73e992e5133aa085c8e45548e0189c411c8cfe42e902b0ee2dec528a18fb472c3375447868ffced0d4812125e4361d667b7e6a18b2357643e09bbe7e9110c6b28d74f4f55e7c29e92419b52509e5c367cf2d977b670a2ff7560f5fe24021d246abe30542e6c6e3aa52f903453c3a2389af918249dbdb5f1199aaecf4931c0366592165b10bdd58eaf706d6df02a39d9323a0c65260ffcc84776f2705e4942d89e4dbefa11c693027002c35582d56e295dcf74d27e90873699657337696b32c05c8014911a7ec8eb03bdbe526fe658be8abdf50ab12c4fec9ddeefc489cf817721c8e541d28fbe71e32137b5ea066a9f4e19814deedeb360def90eff2965570aab5fedd0ebfcd783ce3289360953680ac084b2e988c9cbd0912da400861467d7bb5ad4b42a95c2d541653e805cbfc84da401baf096fba43300358421ae1b43fd25f3289c8c73489977592f75bc9f73781f41718a752ab325b70c8eb2011c5d979f6efc7a76e16492566e43d94dbd42698eb06ff8ad4fd3f2baabafded"
}

$ lncli --network=simnet exportchanbackup --all --output_file=channels.backup

リカバリープロセス

リカバリープロセスが開始されるとlndは以下のプロセスを実行する。

  1. リカバリーするチャネルのセットが与えられると、データベースにchannel shellを挿入する。これにはDLPプロトコルを開始するのに必要な情報だけが含まれる。結果、これらのチャネルはデータベース内で「recovered」とマークされ、他のプロセスがそのチャネルを使用するのを防ぐ。
  2. channel shellが「recovered」になると、chanbackupパッケージは、ピアに到達できた以前の全てのアドレスを含むLinkNodeを挿入しようとする。その過程でそのチャネルのエッジ(送信方向にのみ)もデータベースに挿入される。
  3. 続いてlndが起動し、いつもどおりチャネルを開いている全てのピアとの接続を確立しようとする。lndがすでに実行されている場合は、新しい接続の試行が開始される。
  4. ピアと繋がったら、次にDLPプロトコルを開始する。リモートピアはデータが失われたことを知り、すぐに強制的にチャネルを閉じる。チャネルを閉じる前に、こちら側が資金を回収するのに必要な鍵を導出するために必要な、最新のコミットメントポイントを含むチャネル再確立ハンドシェイクメッセージを送り返す。
  5. リモートピアがブロードキャストしたコミットメントトランザクションがチェーン上で確認されたら、SCBの情報から資金を回収するのに必要な鍵を再導出し、資金を回収する。

バックアップ/リカバリ−される資金

1点、注意が必要なのは、SCBにより回収可能な資金はベースコミットメントのアウトプットにある資金のみであるということ。つまりHTLCの資金は含まれない。このバックアップファイルはチャネル作成時に作られるが、将来作られるであろうHTLCの情報は当然含まれないので、HTLCの情報は欠落しており、未処理のHTLCがあれば、その資金は回収できない。