送金の解説は、メッセージ交換についてと、交換するデータについてに分けて行う。
データについて把握しないとメッセージ交換だけ見てもわからない箇所が出てきてしまうが、並列して説明すると煩雑になってしまうため、順番に見ていこう。
2ノード間で送金を行った場合のシーケンスを以下に示す。
ここに出てくるメッセージは4種類である。
- update_add_htlc : HTLC追加要求
- update_fulfill_htlc : HTLC反映要求
- commitment_signed : transaction署名
- revoke_and_ack : commitment transaction確定
前回の解説で、「送金する情報(HTLC)の追加」と「送金を実行」に分かれると書いたが、具体的には「update_add_htlcを送信して確定するまで」と「update_fulfill_htlcを送信して確定するまで」に分かれている。
最初のメッセージはupdate_add_htlcから始まるが、その前に送金元からinvoiceを入手する必要がある。
最低限必要な情報は、以下である。
- 領収書IDのハッシュ値
- 請求額
領収書IDはpayment_preimage、そのハッシュ値はpayment_hashと呼んでいる。
ハッシュ演算は、SHA256である。
また、請求額の単位はmsatである。
この情報を表現するための仕様がBOLT11だが、上記データを相手に渡すことさえできればupdate_add_htlcメッセージを作成することができる。
渡すためのBOLTメッセージはないため、それ以外のルート(メールやQRコードなど)を使うことになるだろう。
update_add_htlcメッセージでは、payment_hashやamount_msat(請求額)を送信するが、それ以外に重要な情報として「cltv_expiry」と「onion_routing_packet」がある。
cltv_expiryは、OP_CHECKLOCKTIMEVERIFYというBitcoinスクリプトの命令で使う値で、スクリプトの制限時間を決めるために使用する。
update_add_htlcを送信する=相手に送金をする、ということになるため、通常はそのまま受けとってもらいたいのだが、HTLCを追加してupdate_fulfill_htlcを送金するまでの間に何か問題があり、相手のPCが故障などしていなくなるかもしれない。
その場合でもHTLCに手を出せないままにならないよう、一定期間以上経っても相手が受け取らない場合は、タイムアウトして取り戻すことが可能になっている。
onion_routing_packetは、送金するルートを指定した情報である。
今回は2ノード間のためルートは1つしかないが、BOLTの送金は転送を繰り返して相手に届けることが可能になっているため、どのノードを経由して送金するかを送金元が決定できるようになっている。
中継するノードは、多少の手数料を取ることができるため、最終的に安いルートを使いたいかもしれないし、信用が高いノードがあるのであればそこを経由させたいかもしれない。
名前に「onion_」とついているのは、ルート情報はノードをそのまま載せているわけではなく、受信した人はその次に転送する相手のノードしかわからないようになっているためである。
そのデータの作り方が、1つノード情報を入れたら暗号化、それに次のノード情報を追加して暗号化、というように、1回ずつ暗号化させてデータを作っていき、受信した人は1つだけ解読して次のノード情報を読み、また次の人はノード情報を読み・・・と繰り返していく。
それが、タマネギの皮をはいでいくような様子に見えるので、onion routing protocolと呼ばれている(のだと思う)。
onion routing protocolはBOLT4にて説明されている。サンプル実装はこちらである。
update_add_htlcを受信したノードは、payment_hashが自分のpayment_preimageのハッシュ値と一致するかを確認し、一致しているのであればamount_msatとcltv_expiryを期待値と一致するか確認する。
それで問題が無ければ、update_fulfill_htlcメッセージを送信する。
このときに、payment_preimageを返す。
2ノード間では、payment_preimageはpayment_hashのチェックにしか使用しないが、転送している場合には重要な意味を持つ(説明は送金の転送で行う)。
update_add_htlcとupdate_fulfill_htlcの後に送信し合うcommitment_signedとrevoke_and_ackについて説明する。
commitment_signedは、funding transactionからの出力であるcommitment transactionの署名と、各HTLCについての署名を送信するメッセージである。
commitment transactionはfunderとfundeeのMultiSigなので、それぞれが署名しないと送金できないため、commtiment transactionの内容が変わるたびに署名を送りあい、いつでもブロックチェーンに展開できるようにしている。
commitment transactionに署名してしまうと展開できるようになるが、こちらに送金してもらった後に相手が送金前のcommitment transactionを展開されてしまうと、自分への送金がなかったことになってしまう。
そういう裏切り行為をされないように、古いcommitment transactionを展開すると損をするようなスクリプトをcommitment transactionに埋め込んである。
その、今までのcommitment transactionを過去のものとして確定するためのメッセージが、revoke_and_ackである。
revoke_and_ackでは、per_commitment_secretという今まで使っていたper_commitment_pointの秘密鍵にあたるデータを相手に送信する。
このデータがあると、それによって作られたcommitment transactionでは、payment_preimageがなくてもHTLCを取得できるし、相手の配分になっていた額も取得できるようになっている。
Bitcoinのしくみ上、正しいトランザクションを展開することを止めることはできないが、展開すると損をするという制約をつけることで、不正をさせる抑止力にしようとしている。
基本的なメッセージ交換は以上である。
次回からは、データについて見ていく。