Lightning Network BOLTの概要について、書いていくシリーズ。
前回の続きで、Lightning Networkで使われているHTLCの説明をしていきます。
なお、今の最新BOLTはcommit: f608c33です。
BOLTでは、2種類のHTLCがあります。
- Offered HTLC
- Received HTLC
Offered HTLCは送金側、Received HTLCは着金側になります。
今回はBOLTメッセージのシーケンスは関係ありませんが、HTLCの追加と反映はこのような流れになっています。
HTLCはスクリプトで、commitment transactionでは送金先として使われます。
私は、送金するamountを箱に入れて、送金先の人が渡した鍵で封印するようなイメージを描いてます。
送金元が自分のamountの一部を箱に入れ、封をして、送金先に渡してチェックされ、OKだったら封印を解く鍵をもらって、箱から取り出して送金先のamountに追加する、というところです。
封が解かれると、箱は消滅します。
実際には、これをスクリプトで行うことになります。
送金する人からすると、以下のような状況が発生すると困ります。
- 相手がReceived HTLCをもらってない、と言い張る
- HTLCは渡したが、着金を認めてくれない
- HTLCは渡して、相手は着金を認めたが、鍵を渡してくれない
前回のto_localスクリプトでは、OP_CSV(OP_CHECKSEQUENCEVERIFY)を使うことで、取り戻すまでに時間がかかるようにしていました。
ここでは、OP_CLTV(OP_CHECKLOCKTIMEVERIFY)という命令を使うことで、スクリプトがタイムアウトできるようにします。
送金先の人が一定期間内に鍵を渡さなかった(=スクリプトを解かない)場合、そのHTLCは送金元の人が取り戻すことができる、という条件を付けることで、放置したままになったり、相手との連絡が取れなくなった場合でも取り戻せるようにしているのです。
文字で書くと、なるほど、というところですが、これをスクリプトで表さなくてはなりません。
あまり深入りすると説明が終わらなくなるので、ざっと流したいと思います。
Offered HTLC
BOLTのドキュメントでは”Offered HTLC Outputs”となっていますが、commitment transactionの送金先として説明されているためです。
なお、仕様上のHTLC最大数は483となっています。
これが本体(?)で、to_localスクリプトと同じく、この前にデータを置くことで、OP_IFのルートを変えたり、チェックするデータを変えたりします。
OP_IFを通るのは、<revocationpubkey>などの結果がTRUEだった場合です。
to_localと同様で、「revocation」という単語が入っている場合は、古いcommitment transactionをブロックチェーンに展開した場合の対策になります。
古いcommitment transactionはスクリプト秘密鍵を相手に渡しているので、相手はそのルートを通すことができます(展開した人は通すことができない)。
そうすると、OP_CSVやOP_CLTVなどを通らないルートになるため、即座に相手は取り戻すことができる、というわけです。
OP_ELSEのルートが、タイムアウトなどの制限を付けたルートになります。
中のOP_NOTIFルートがタイムアウトして取り戻す場合のルート、OP_ELSEルートが鍵(preimage)を使って解くルートです。
通常、送金をした場合は、着金を確認した人がupdate_fulfill_htlcというメッセージを使ってpreimageを通知します。
preimageをもらった人は、HTLCの鍵であることをチェックして、問題なければHTLCをそのまま反映して、HTLCを消します。
HTLCが残ったままcommitment transactionになるのは、
- HTLCを追加して、
- preimageをもらわずに、
- commitment transactionをブロックチェーンに展開した
という場合だけです(unilateral close: local remote)。
commitment transactionが展開されたということは、Lightning Networkのチャネルはクローズされたことになります。
bitcoindのJSON-RPCでgettxoutするとfunding transactionがunspentかどうかチェックできます。
funding transactionがunspentでなくなった=クローズになった、でもあります。
それ以降は、1st Layerでの処理になります。
ブロックチェーンを見て、preimageがあればスクリプトを解くもよいし、タイムアウトまで待って取り戻すもよし、です。
どうしないといけないか、ということについて今のところBOLTでは既定がありません。
Received HTLC
説明したかったことはOffered HTLCのところで書いたので、Received HTLCは簡単に済ませます。
相手がOffered HTLCを追加すると、自分はReceived HTLCを追加することになります。
最初のOP_IFがペナルティーのルート。
OP_ELSE以下の、OP_IFがpreimageを持っている場合のルート、OP_ELSEがタイムアウトのルートになります。
Offered HTLCスクリプトも、Received HTLCスクリプトも、終わりがOP_CHECKSIGになっているルートと、OP_CHECKMULTISIGになっているルートがあります。
OP_CHECKSIGは署名が1つで、その署名は自分で作成することができます。
しかし、OP_CHECKMULTISIGは署名が複数必要で、このスクリプトでは2ついるようになっています。
複数必要になるのは、以下のルートです。
- Offered HTLC : タイムアウトして自分に取り戻す
- Received HTLC : preimageを使って自分に取り戻す
相手の署名も必要になりますが、それをどこで取得するかというと、commitment_signedメッセージです。
commitment_signedのhtlc_signatureがその署名になります。
あらかじめ署名ができるということは、送金先も決めておかなくてはなりません。
どこに送金するかというと、to_localスクリプトと同じ形のスクリプトになります。
タイムアウトする場合はHTLC Timeout output、preimageで取り戻す場合はHTLC Success outputと呼びます。
to_localと同じ形のため、そこから取り戻すためにはto_self_delayブロック待たなくてはなりません。
HTLCについては、以上になります。
なるべくゆっくり説明したつもりですが、それでも非常に難解だと思います。
きっちり理解されたい場合は、BOLTの#02, #03, #05あたりを読むことをおすすめします。