[LN#023]HTLC (トランザクション)

Lightning Network BOLTの概要について、書いていくシリーズ。

LN#020, LN#021とLightning Network BOLTで使われているHTLCについて書きましたが、読んだ方から「スクリプトのどこでロックしているの?」という質問を受けました。
確かに、スクリプトの内容ばかり書いていて、どう制限がかかっているかについては、OP_CHECKLOCKTIMEVERIFYやOP_CHECKSEQUENCEVERIFYという命令名を書いただけになっていました。

今回は、HTLCとトランザクションについて、実データを例にしながら書いていきます。


regtestで行った例になります。
amountの単位として書いているmsatは msatoshi(ミリsatoshi)です。

  • Aさんが持つamount:300000000 msat
  • Bさんが持つamount : 300000000 msat

ここで、送金を行います。

  • Aさん→Bさん:200000000 msat

送金は、大ざっぱに書くと以下のような通信を行います。

image

送金する額のHTLCをcommitment transactionに追加する工程と、それを反映してcommitment transactionからHTLCを削除する工程です。
commitment transactionの構成が変わるのでそのたびに署名を交換します。

今回は、HTLCの追加に焦点を当てます。


Aさん:送金元(payer)

HTLC追加後の、Aさんが持つcommitment transactionはこうなりました。

ptarmiganが持っているトランザクション出力を使っているため、”bitcoin-cli decoderawtransaction” などとは構成が違うと思いますが、だいたいの雰囲気は伝わるかと思います。

image

HTLCへの送金になるのは、commitment transactionの出力が3つあるうちの真ん中になります。
Aさん=送金元なので、HTLCは「Offered HTLC output」になります。

Offered HTLC outputは、相手への送金を目的としているので、基本的にはBさん宛になるはずです。
Bさん宛=Bさんが署名してどこかに送金する、ということになります。
そのために必要になるのは、送金前に相手からもらったinvoiceに含まれている情報「payment_hash」のハッシュ計算をする前の値である「payment_preimage」という値です。

Aさんの立場からすると、

  • Bさんがpayment_preimageを使ってOffered HTLC outputをどこかに送金すれば、それでよし
  • もしそうしないまま放置するようだったら、送金はなかったものとして、Aさんがどこかに送金する

ということになっています。

この「放置するようだったら」の期限は、commitment transactionを見ても分からず、かといってOffered HTLCのスクリプトを見てもわかりません。
実は、BOLT仕様によって「時間切れになった場合のトランザクション」というものが決められています(2人の署名がいる)。
そして、HTLCを追加した後に署名交換を行いますが、そのときにHTLCの署名も交換するようになっています。

事前に署名をする以上、トランザクションの内容は仕様できっちり決められています。
そのため、Aさんは決められたトランザクション以外をブロックチェーンに展開することができません。

Aさんの時間切れになったときに取り戻すトランザクション(HTLC Timeout Transaction)は、このような形になりました。
(witnessは省略)

image

一番下の、locktimeに値が指定されているところに注目してください。

commitment transactionにもlocktimeは指定しますが、タイプは日時になっていて、それは既に過ぎ去った時間になっているためいつでも展開できますが、Timeout Transactionはブロック高になっています。

そのため、このトランザクションをブロックチェーンに展開するには、現在のブロック高がlocktime以上になるまで待たなくてはなりません(regtestなので、値は小さめになっています)。

Bさんの立場からすると、もしAさんがcommitment transactionをブロックチェーンに展開したとしても、送金をAさんが取り戻すまでにlocktimeまでの余裕があることになります。
その間にpayment_preimageを使って、下図の赤枠の経路を通って取り戻します。

image


Bさん:送金先(payee)

Bさんのcommitment transactionはこうなりました。

image

こちらも、真ん中のoutputがHTLCです。
なお、commitment transactionはBIP69に従ってソートします。

Bさんはお金を受け取る方なので、

  • payment_preimageを使ったトランザクションを期限までに展開する

という動作を行います。

payment_preimageを使って取り戻すトランザクション(HTLC Success Transaction)は、こうなりました。

image

構成はHTLC Timeout Transactionとほぼ同じで、違いはlocktimeの有無になります。
Success Transactionはlocktimeが0なので、payment_preimageを持っていればすぐに展開できます。

Aさんの立場からすると、もしBさんがcommitment transactionを展開したままpayment_preimageを使わずに放置したままになっていても、実はそれほど困りません。
それは、Aさんがpayerだからです。

しかし、Aさんが単に送金を中継している場合、それでは困ります。
Aさんが転送する元になった入金を手に入れるためには、payment_preimageが必要になるからです。

image

放置したままにならないよう、Bさんがcommitment transactionを展開した場合は、payment_preimageを持たなくても一定時間が経過したら取り戻せるようになっています。
それが、下図の赤枠で囲んだ命令です。

image

<cltv_expiry>というのはブロック高で、そのブロック高以上の時間になればその経路が有効になります。
Bさんにとってみれば、その経路をAさんが使う=自分の手に入れられない、ということになり、それまでの間にpayment_preimageを使ってしまおう、と考えることになります。


今回はトランザクションを含めて、Offered/Received HTLCの説明をしました。

今回の話が出てくるのは、HTLCを追加して、そのまま反映されずに残って、チャネルを閉じたくなった場合です。
通常は、HTLCを追加した後、すぐにHTLCを反映するので、commitment transactionにHTLCが残ったままになることはあまりないでしょうが、そういう場合も考慮されているということは知っておいてよいと思います。

[LN#022]送金の転送fee

Lightning Network BOLTの概要について、書いていくシリーズ。

今回は、送金を転送する際のfee計算についてです。


Lightning Network BOLTには、送金を転送するという仕様があります。
だいたいの場合、Lightning Networkで送金をする際には、このような流れになります(図の数字と連番は関係ありません)。

  1. 送金する人(payer)が、送金先の人(payee)からinvoiceの文字列をもらう
  2. payerは、Lightning Networkのノードアプリにinvoiceを伝える
  3. payerのノードアプリが、今まで通知されたchannelの情報を使って、payeeまでのルートを作る
  4. payerは、ルートの最初の人に暗号化されたルート情報と送金額を通知
  5. 受け取った人は、暗号化されたルートから次の送金先と送金額をデコードし、それに従って通知
  6. 手順5を繰り返していき、payeeまでたどり着くと、payeeはinvoiceを解く鍵を送り返す
  7. 鍵を受け取った人はinvoiceを解いて自分への送金を受け取り、送金したルートと逆順に鍵を送っていく

image

中継する人は、経路を使った見返りとして、送金したfeeを受け取ることができます。

feeは、「受け取った送金額」と「次に渡す送金額」の差になります。
たとえばこの図では、中継Aさんがfeeとして10、中継Bさんが20を要求した場合、payeeへ100送りたいならば、payerは130送金します。


手数料はpayerが勝手に決めるわけではなく、各ノードがchannel情報をアナウンスするメッセージの中に入っています。

BOLTメッセージで言えば、channel_updateになります。
feeに関係するパラメータは、この2つです。

image

fee_base_msatは、ベースとなるfeeで、固定です(単位はmsatoshi)。
fee_proportional_millionthsは、100万satoshi=10mBTC辺りのfeeです。

なお、単に相手に送金するだけであればfeeは発生しません。

feeは、経由するチャネルごとにかかるため、経路のチャネルが増えると、feeが多くなっていきます。
しかし、feeはチャネルごとに異なるため、あまり高いfeeを設定しているとpayerがルート計算する際に除外されることでしょう。

2018年2月にTESTNETで値を見たときは、各ノードのデフォルト値はこのようになっていました。
https://github.com/nayutaco/lightning-memo/wiki/%E6%8E%A5%E7%B6%9A%E3%83%86%E3%82%B9%E3%83%88#table

TESTNETなので値が高い低いというのはあまり意味がありません(MAINNETでの値は調べていません)。

パラメータはノードアプリで設定できると思いますので、確認されると面白いでしょう。

[LN#021]HTLC (2)

Lightning Network BOLTの概要について、書いていくシリーズ。

前回の続きで、Lightning Networkで使われているHTLCの説明をしていきます。
なお、今の最新BOLTはcommit: f608c33です。


BOLTでは、2種類のHTLCがあります。

  • Offered HTLC
  • Received HTLC

 

Offered HTLCは送金側、Received HTLCは着金側になります。

今回はBOLTメッセージのシーケンスは関係ありませんが、HTLCの追加と反映はこのような流れになっています。

 

image

 

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となっています。

 

image

 

これが本体(?)で、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は簡単に済ませます。

 

image

 

相手が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あたりを読むことをおすすめします。

[LN#020]HTLC (1)

Lightning Network BOLTの概要について、書いていくシリーズ。

今回は、BOLTで使われているHTLCについて説明します。
以前「[LN#010]送金(4)」でも説明しましたが、もう少しゆっくりやります。


HTLCは、Hashed TimeLock Contractsの略で、BIP112などに説明があります。

BitcoinにはEthereumのようなスマートコントラクトみたいなものは今のところないのですが、IF文は使うことができます。
また、トランザクションのバージョン2からは、OP_CHECKLOCKTIMEVERIFYとOP_CHECKSEQUENCEVERIFYという命令も使うことができます。
(使用できる命令については、wiki/Script参照。)

 

例えば、こちらはregtestで作成したcommitment transactionです。
voutに「to_remote」「Received」「to_local」と書かれていますが、「Received」と「to_local」についてはスクリプト(P2WSH)への送金になっています。

image

 

BOLTでのHTLCは「Offered HTLC」「Received HTLC」になりますが、今回はBitcoinでのスクリプトを中心に説明するため、to_localについて見ていきます。


ここでのto_localスクリプトは、このような構造になっています。

image

 

この構成は、BOLT#3で決められています。

image

 

OP_IF~OP_ELSE~OP_ENDIFという、比較的見慣れた構造になっているのが分かるかと思います。
Bitcoinのスクリプトは、FORTHに似ているといわれています(私はよく知りません)が、私は逆ポーランド記法のようなイメージで考えています。

値(1や0など)をスタックし、次にOP_IFに来ると、直前に積まれているスタックの内容を判断して、OP_IFの方かOP_ELSEの方かの分岐が生じるようになっています。
0が偽で、それ以外は真という扱いです。

最後のOP_CHECKSIGは、スタックから2つ取り出して、1つは署名、1つは公開鍵として署名のverifyを行い、真か偽かをチェックするという命令です。


簡易表記していますが、OP_IFのルートを通す場合は、このようなスタックの動きになります。
左から右に向かって読んでください。
太線の下が動作で、例えば一番左側であれば「”rev-sig”という値をスタックに積んだ」ですし、左から3番目であれば「OP_IFのルートを通る」という意味です。

image

 

OP_IFのルートでは<revocationpubkey>という公開鍵をスタックすることになっているので、その前に<revocationpubkey>の秘密鍵で署名したデータをスタックしておかなくてはなりません(ここでは “rev-sig”と記載)。

そして、OP_IFのルートを通すために”1”をスタックし、あとはスクリプトを順番に処理していきます。


では、OP_ELSEルートを通してみましょう。

この場合は、<local_delayedpubkey>がスタックされるので、前と同様に<local_delayedpubkey>の秘密鍵で署名したデータをスタックしておかなくてはなりません。

しかし、その前にOP_CSV(OP_CHECKSEQUENCEVERIFY)があります。
これは、直前にスタックされている値を取り出し、vinとなるトランザクションがブロックに入ったときのブロック高+スタック値以上のブロック数が経過していない場合はスクリプト自体が偽となる命令になっています。

 

スタックの動きは、こうなります。
OP_DROPは、OP_CSVの結果が真だった場合、スタックしていたto_self_delay値が邪魔になるので、取り除くのに使われています。

 

image

 

そうなると、OP_CSVを経由しない方がすぐに使用できるので、そちらを使いたくなるかもしれません。
しかし、<revocationpubkey>の秘密鍵を使うことになるのは、revoked transaction closeをされた場合、すなわち相手が古いcommitment transactionをブロックチェーンに展開した場合に、ペナルティーとして相手のすべてを取り戻す場合になります。

ブロックチェーンに展開されているので、to_self_delayブロック経過してしまうと、相手がOP_ELSEルートを通るスクリプトを作ることができてしまうので、それまでに取り戻さないといけません。
to_self_delayはChannel Establish時にopen_channel / accept_channelで交換するので、小さすぎず(ペナルティーとして有効になるくらいの期間)、大きすぎず(unilateral closeで自分に取り戻すのに長すぎない期間)であることを確認する必要があります。


今回は、主にto_local scriptの解き方について説明しました。

BOLTでHTLCというと、送金/着金が反映される前、最初のトランザクションでいえば「Received」のようなものを指しますので、次回はそれらについて説明する予定です。

[LN#019]ptarmigan(2018/04/11)

Lightning Network BOLTの概要について、書いていくシリーズ。

今回は趣向を変えて、開発中のLightning Networkノードであるptarmiganの概要を説明します。

image


https://nayutaco.github.io/ptarmigan/

ptarmigan(たーみがん、と発音)は、日本名でいえば「雷鳥」になります。
Lightning Networkなので、雷に由来しています。

GitHubで見るとC++プロジェクトのように見えてしまいますが、実際はC言語です。
これは、単体テストでgtestsを使っていて、テストデータが大量にあるためにそうなってしまいました。

C言語で作っていますが、c-lightningをベースにしているわけではなく、ライブラリを使っている箇所以外はほとんど自作しています。

また、ptarmiganは弊社が作り始めましたが、オープンソースですので、issueを上げてくださったり、Pull Requestしてくださる方を歓迎しています。
日本語でも問題ありません!
(タイトルはなるべく英語で書いてますが、中身はほぼ日本語です)


gitのbranchは development で作業しています。

developmentで、簡単に他ノードとの動作確認したあとでリリースを行っています。
この時点の最新は、2018-04-11です。
https://github.com/nayutaco/ptarmigan/releases/tag/2018-04-11

他のノード(c-lightning / eclair / lnd)の使い方については、別のwikiにメモを作成しています。
https://github.com/nayutaco/lightning-memo/wiki

ptarmiganについてはdocsに書いています。
バージョンやcommit-idは記載当時のものになっていますが、だいたいは現在でも使えるようになっていると思います(動作しなかったら、issueくださると助かります)。


動作環境はUbuntuを想定していますが、Linuxであれば動作するのではないかと思います。
regtestでの動作はWindowsのWSL(Ubuntu)で行っています。

bitcoindの機能を使っていて、スクリプトではbitcoin-cliを呼び出し、ptarmiganのプロセス(ucoind)からはJSON-RPCを呼び出しています。

bitcoindのバージョンは、テスト環境ではv0.16を使っています。
おそらくv0.15でも動作するとは思いますが、今後のことを考えるとv0.16の方が無難かもしれません。
close後の送金アドレスは getnewaddress を使っているので、v0.15ではP2PKH、v0.16ではP2WPKH nested in BIP16 P2SHになります。

ptarmiganは、testnet/regtestでしか使用できません。


開発は、以下を中心に行っています。

  • BOLTを読んで、実装されていないところを追加、修正
  • 他ノードとやりとり
    • 認識が合わない動作があれば、BOLT再読やissueで確認
  • 操作性の向上やログ出力の見直し

BOLTの内容を読んで、それを実装レベルまでどう持っていくのか考えるのに時間がかかります。

まだまだ開発中ですので、ptarmiganに興味を持っていただけるとうれしいです。

[LN#018]announcement

Lightning Network BOLTの概要について、書いていくシリーズ。

今回は、announcementについて書きます。


転送(1)で簡単に紹介しましたが、BOLT#7でannouncement関連のメッセージが定義されています。

  • node_announcement
  • channel_announcement, channel_update

 

node_announcementは、alias名やIPアドレスなど、node自体の情報を展開しています。
相手nodeに接続したい場合は、このnodeからIPアドレスを調べ、接続させることでしょう。

 

1つのchannelには2つのnodeが関係するので、channel自体のannouncementメッセージ(channel_announcement)と、それぞれのnodeが持つchannel情報のannouncementメッセージ(channel_update)があります。
送金を転送するfeeなどは各nodeが主張できるので、通る方向によってfeeが異なる場合もあります。

 

 

このannouncementですが、Lightning Nodeをログ出力する状態にしてコマンドラインから実行するとわかりますが、相手nodeに接続すると、取りあえず大量に送信されてきます。
接続して最初に送信するinitメッセージで、相手nodeが持つchannel関連のannouncement情報を同期させるかどうか選べる(initial_routing_syncフラグ)のですが、だいたいは「同期する」にしているため、相手は持っている情報を送りつけるし、自分も持っている情報を送りつけます。

 

ならば、initial_routing_syncをオフにすればいいじゃないか、と思ってしまいますが、testnetではお金を掛けずにchannelを作ることができるためか、作って放置されるchannelが結構あります。
そういうchannelの情報しか持っていなかった場合、送金の転送をしたくても使用できないルートしか見つけることができなくなってしまうのです。

それを避けるため、取りあえず同期させようとしているのだと思います。

この辺りについては効率が悪いので、BOLTで解決していくのではないかと思われます。

[LN#017]2nd layer

Lightning Network BOLTの概要について、書いていくシリーズ。
LN#000~#016で大まかに行っていることを説明してきたので、これからは個々の部分について書いていきたいと思います。

今回は「大まかな2nd layerのイメージ」についてです。


Lightning Networkは、2nd layer技術の1つ、と呼ばれています。

2nd layerがあるということは、1st layerがあるということになります。
Bitcoinの場合、1st layerはBitcoinのブロックチェーンです。
パブリックなものとしてはmainnetとtestnetがありますが、ノードとして「mainnetのノード」「testnetのノード」という種別は作っていません。

では、どこでmainnet/testnetを分けるかというと、チャネルになります。
チャネルを開設するときのメッセージにgenesis block hashを載せるので、それを受け付けるかどうかで決まることになります。
もし、自分が対応しない種別のブロックチェーンであれば、チャネル開設を行わないようにできます。
また、チャネルの開設途中でfunding transactionという2nd layerの開始となるトランザクションを1st layerに展開するのですが、異なるブロックチェーンをINPUTにすることはできないので、そこで失敗するでしょう。

そのfunding transactionがブロックチェーンに展開されて、ある程度のconfirmationが経過すると、そこが2nd layerでのチャネル開設完了になります(正確には、完了したことを通知し合うメッセージを交換した後)。

以降は2nd layer上でいろいろやって、チャネルを閉じる処理をします。
閉じるときは、funding transactionの出力から送金することになります。
つまり、1st layerから見ると、funding transactionがspentになるとチャネルが閉じたことになります。


閉じ方は3つあります。

1つは、チャネルの双方が合意して閉じるパターン。
この方法は、その時のチャネルに入っている額がそれぞれのアドレスに送金されるので、一番早く1st layerで使えるようになります。
BOLT5で”The good way (mutual close)”と言われるやり方です。

image


その次は、”The bad way (unilateral close)”と呼ばれ、どちらかが現在の状況を使って閉じる方法です。
2nd layer上で送金が確定すると、毎回commitment transactionというトランザクションを作ります。
これは、funding transactionを入力としたもので、それをブロックチェーンに展開すると取りあえずクローズできるというトランザクションになります。
お互い、チャネルにある額は戻ってくるのですが、不正防止のために展開した人はアドレスでは無くスクリプトへ送金され、そこから自分で使えるようにするまでロックがかかっているため、その時間が経過するまでは使用することができません。

また、送金途中のHTLCもスクリプトに送金され、それを取り戻すにはさらに時間がかかります(図には描いていません)。

通常はやりたくないですが、チャネルの相手が行方不明になった場合など、「Good Way」でどうしても閉じられない場合に使用することになるでしょう。

image


最後が”The ugly way (revoked transaction close”と呼ばれる方法。
これは、最新のcommitment transactionをブロックチェーンに展開するのでは無く、過去のcommitment transactionを展開した場合です。

毎回、2nd layer上で取引が発生すると、commitment transactionを作成し、いつでも展開できるように署名をするので、展開しようと思えばできてしまうのです。
ただ、その展開は「取引を無かったことにしてしまおうという」ということに他ならないため、罰則が与えられます。

すなわち、すべての額が展開しなかった人が取り戻せるようなスクリプトに送金されている、ということです。

image

ただ、万能では無く、一定時間内に相手が取り戻す動作をしなくてはなりません。
その時間が、前の「bad way」で取り戻すのに時間がかかる理由にもなってきます。


このように、1st layerから見ると、2nd layerで行われている内容はfunding transactionとその出力しかありません。
その間の細かいやりとりはブロックチェーンには載らず、結果のみが残される形となります。
2nd layerはブロックチェーンに戻ってくることで確定される、という言い方もできると思います。

[LN#016]転送 (3)

引き続き、Lightning Network BOLTの送金転送について説明していく。
前回は、update_add_htlcで各チャネルでHTLCが追加されるところまでだったので、今回はHTLCの反映について説明する。


HTLCの反映は2点間の送金と同じで、update_fulfill_htlcメッセージを使用する。
必要となるのは、invoice作成元が持っているpayment_preimageという、invoiceに入っていたハッシュ値(このブログでは「請求書ID」と記載している)の元になる値である。
2点間であれば、送金した相手がpayment_preimageを持っているが、転送している場合は相手が持っているのかはわからない(送金元ノードと送金先ノードだけはわかる)。

以下のことは覚えておいてよいだろう。
・送金元は、送金先までのルート(どのノードを経由させるか)を作成する
・ルート情報は暗号化されている
・ルート情報を受け取ったチャネルは、1つ先までの転送情報を復号できる
・送金先は、次の送金先が無いということがわかるし、請求書IDの元データを自分が持っていることも確認できる。

update_fulfill_htlcに載っているpayment_preimageがHTLCの請求書IDの元データだとわかれば、HTLCを減らしてamountに反映することができる。
これは、通常の送金と同じである。
違うのは、update_add_htlcを別チャネルに転送したのと同じように、update_fulfill_htlcも同じルートで戻していくことになる点である。
update_add_htlcにはルート情報が載っているが、update_fulfill_htlcにはルート情報がないので、各自の責任で戻していくことになる。


送金の転送についての説明は、以上となる。
最後に、3者で転送した場合の簡単なシーケンスを図で示す。

image

BOLTではHTLCを、送金する方を「offered HTLC」、着金する方を「received HTLC」と呼んでいる。
図では、青い方がoffered HTLC、赤い方がreceived HTLCとしている。
反映の際には、offered HTLCは自分のamountから減らして相手のamountを増やし、received HTLCは自分のamountを増やして相手のamountを減らす。

[LN#015]転送 (2)

引き続き、Lightning Network BOLTの送金転送について説明していく。

今回は送金に関するメッセージについて見ていく。


送金の転送は、2ノード間の送金処理を送金元から行っていくことになる。
請求書の発行者が直接の相手ではないため、送金元から着金したノードは、別のノードに送金する。
これを繰り返すことで、送金先まで届くことになる。
BOLTメッセージで言えば、 update_add_htlcによってHTLCを追加する動作が行われることになる。

 

ここまでで、いろいろ疑問点が出てくる。
すぐ出てくるのは、こういうところだ。

  • 送金されたノードは、それをそのままもらったままにしないのか?
  • 送金されたノードは、次の転送先をどうやって決めるのか?

まず、もらったままにしないかどうかだが、update_add_htlcはHTLCを追加するだけのため、それだけでは自分の持ち分にすることができない。
HTLCは中に請求書IDのハッシュ値が入っていて、請求書IDそのものをもらうことによってスクリプトを解くことができ、自分の持ち分にすることができるのだ。
そして、請求書IDは送金先だけしか知らないので、それもまた遡るようにして転送してもらうことになる。

 

次に、次の転送先の決め方であるが、これはupdate_add_htlcのパラメータに入っている。
送金元から送金先までのルート情報は、送金元がすべて決定し、BOLT#4に沿って変換し、update_add_htlcに載せて送っている。
受け取ったノードはルート情報を自分が分かる鍵でデコードすると、次に転送するノードと、転送額がわかるようになっている(相手から送られてきた額と転送額の差が、転送する手数料として受け取る)。

転送するときは、デコードしたルート情報を載せて送る。
次に受けとった人も同じようにデコードすると、また次に転送する情報が載っているので、転送していく。
デコードして次に転送先がなかった場合、それが自分への送金ということがわかるようになっている。


送金の転送は、異なるチャネル間をノードが中継することになる。
チャネル内にfundingされている額は、チャネル外に出すことはできない。

例えば、よく送金に使われる経路があった場合、片方のチャネルは着金を受け付けるだけで、もう片方のチャネルは送金を行うだけ、ということがあるかもしれない。
そうすると、ノードとしては持っている額のトータルは変わらない(手数料によって増えることはあるが)ものの、チャネル内の額の偏りが生じてしまい、いつかは送金できる額がなくなってしまうだろう。

image

もちろん、経路の途中で送金ができなかった場合は、update_fail_htlcというメッセージがあり、HTLCを追加する前の状態に戻すことになっている。

額が足りなくなったチャネルは、今のところ一度closeして、またチャネルを作り直すしかないと考えられる。
次のBOLT仕様ではrefundという項目があるため、そこで解決される可能性もある。


このようにして、まずは送金元までの経路でHTLCを追加していく作業が行われる。

次回は、HTLCを反映させて自分の持ち分にするところを説明していく。

[LN#014]転送 (1)

BOLTでの、中継ノードを挟んだ送金の転送について説明していく。

基本は2ノード間の送金と同じで、送金の反映前と反映後の2動作になる。
ただ、いくつか前提があるため、そこから始めたい。


送金は、いくつかのノードを中継していくことになる。
各ノード間はチャネルでつながっているため、そのチャネルを使わせてもらうことになる。
そのため、ノードが要求する手数料を払いつつ転送することになる。

支払いには期限を指定するが、送金の真ん中で先に期限が切れるようなことが起きると、払い損が生じてしまう可能性がある。
そうならないよう、期限は送金先から順に長くなるように設定しなくてはならないし、各ノードごとに「最低限このくらいの期間はほしい」という要求があるので、それを満たす必要もある。

また、どのノード/チャネルを経由するかは送金するノードが送金時に決定して、update_add_htlcのonion_routing_packetに載せる。

 

よって、送金するノードは以下の情報を持っていなくてはならない。

  • 送金先までの各ノード(node_id)
  • ノード間のチャネル(short_channel_id)
  • 各ノードが要求する手数料
  • 各ノードが要求する期限

BOLTでは、この情報は各ノードが発信することになっている。
その発信方法もBOLTメッセージを使っていて、BOLT7で規定されている。


ノードの情報はnode_announcementメッセージによって、チャネルの情報はchannel_announcementchannel_updateメッセージによって通知される。

ノード名やアドレス(IPv4、IPv6など)、ノードの色などはnode_announcementで通知される。
ノード名やノードの色というのは直接BOLTの送金に関係があるものではなく、一覧などを作成した場合に見やすくするためのものと思われる(少なくとも、BOLTメッセージで出てくるのはここだけである)。

 

それ以外はチャネルの情報になる。
channel_announcementでは、short_channel_idと、そのチャネルの両端のノードのnode_id、およびそこで使われるブロックチェーンの種類(genesis block)が通知される。
channel_updateでは、それぞれのノードが要求する手数料や期限などの情報が通知される。


これらの情報から、送金元→送金先の経路を作ることになる。
経路の作り方については、最近になって推奨が追加されていた。

経路情報を作れば、そこからはBOLT4に従ってonion_routing_packetを作成し、update_add_htlcメッセージを送信する。

次回は、送金元がメッセージ送信するところから説明する。