Develop with pleasure!

福岡でCloudとかBlockchainとか。

LNの支払い経路の計算をアウトソースするトランポリンペイメント

Scaling Bitcoin 2019予習シリーズ第二弾は、「Improving routing in the Lightning Network with Trampoline Payments」について。

特にホワイトペーパーが出てる訳でも無いので、確かな内容は分からないんだけど、おそらく現在BOLTにプルリクが出されている↓の内容じゃないかと思われる(提案者もACINQのBastien Teinturierだし)。

github.com

トランポリンペイメントとは?

Lightning Networkをで支払いをする場合、現在は送信者が自身のノードから受信者のノードまでの経路を計算している。この経路を計算するためには、Lightning Networkのノードネットワークの最新情報を保持しなければならない。Lightning Networkが現在の規模のままであれば問題ないかもしれないが、Lightning Networkの採用が進み、チャネル数が数百万などに拡大するとどうなるだろう?経路計算するノードは、より多くのメモリ、ネットワーク帯域および計算能力が必要になる。特にスマートフォンやIoTデバイスのようなリソースが制限されたデバイスにとっては、そのハードルは高くなる。

トランポリンペイメントというのは、そういうリソースが制限されたデバイスのために、経路計算をトラストレスにアウトソースするための提案。例えば以下のようなAからFまでのチャネルグラフがあるとする。

A → B → C → D → E → F

ノードAはFにLNで決済をしたいけど,軽量クライアントで近隣のノード情報しか保持したいため、Cがどこにあるかは知っているけど、Fがどこにあるかは知らない。でもCはネットワーク全体の最新状態を維持するトランポリンノードであった場合、AはCに支払いを送信すると、Cがそこから先のFまでの効率的な経路計算し、支払いをしてくれるという仕組み。

また、通常のLN決済で使われるオニオンルーティングの場合、中継ノードは中継する前後のノードに関する情報は知っているけど、送信者、受信者の情報は分からないというプライバシー特性があるが、このトランポリンペイメントについても同様に、トランポリンノードに送信者の情報および受信者の情報が分からないような仕組みにする必要がある。

トランポリンペイメントの仕組み

では、具体的にどのようにしてトレストレスにトランポリンペイメントがワークするのか見ていこう。

ネットワークビュー

まず、トランポリンノードと制限デバイスのネットワーク形成について。

f:id:techmedia-think:20190731104853p:plain

トランポリンノード

ネットワーク・トポロジーの全体像を把握し、トランポリンペイメントをサポートするトランポリンノードは、option_trampoline_routingのサポートを広告する必要がある。

また、トランポリンペイメントペイメントを中継する意思があるトランポリンノードとなるノードはnode_updateという新しいメッセージを送信する。このメッセージはchannel_updateメッセージと同じ方法で中継される。トランポリンペイメントを中継する意思がないノードは、このnode_updateメッセージを送信しない。

制限デバイスはこのnode_updateによってトランポリンノードを識別する。

制限デバイス

制限ノードは上記のnode_updateを監視することで、トランポリンペイメントを行う際に送信先となるトランポリンノードの情報を得ることができる。これらのノード情報を保存し、どのトランポリンノードを使用するかは自由に選択できる。

単純にnode_updateを受信するだけでは、帯域幅の削減にはならないので、ゴシップメッセージのフィルタリングをする必要がある。制限デバイスoption_gossip_filtersをサポートするリモートノードとのみ接続する。そうすると、リモートノードはフィルタにパスしたメッセージのみを制限デバイスに送るようになる。現在定義されているのは以下の2つのフィルタ。

  • channel_update_filter
    制限デバイスは、リモートノードにchannel_update_filterを送信する。するとリモートノードは制限デバイスchannel_updateを送信する前にこのフィルタにかけ、フィルタをパスしたchannel_updateメッセージのみを制限デバイスに転送する。フィルタの中身は単純に距離数で、リモートノードから指定した最大ホップ数分離れているchannel_updateメッセージのみ受け入れ、それ以上離れているノードのchannel_updateは受け取らない。こうすることで、制限デバイスは近隣のノード情報のみを保持するノードとなる。
  • node_update_filter
    制限デバイスは、リモートノードにnode_update_filterを送信する。するとリモートノードは制限デバイスnode_updateを送信する前にこのフィルタにかけ、フィルタをパスしたnode_updateメッセージのみを制限デバイスに転送する。これによりトランポリンノードのリストを定期的に更新し、その手数料率とcltvを最新の状態に保つ。node_update_filterは、node_idsha256(local_node_id || latest_block_hash)の2つの値の距離に基づいたフィルタになっている。

制限デバイスは、node_updateとフィルタを利用して、ストレージコストとネットワークの帯域幅を削減する。

トランポリンノードを利用したトランポリンペイメント

アリス→ボブのLN支払いをしたく、両者がトランポリンペイメントをサポートする場合は、以下のように決済するようになる。

① ボブはまずインボイスを作成するが、この時ボブの近隣のトランポリンノード(TB1, TB2, TB3)を3つ記載する。

② アリスは近隣のトランポリンノードTA1を選択し、もう1つ異なる(近隣でなくてもいい)TA2を選択。そして最後のインボイスの中から1つのトランポリンノードTB3を選択したとする(アリスはインボイスに掲載されていたトランポリンノードを選択してもいいし、選択しなくてもいい)。この段階でトランポリンノードの経路はアリス -> TA1 -> TA2 -> TB3 -> ボブとなる。

③ 続いてアリスは、この経路で支払いをするため、トランポリンペイメントのために新しく導入されるtrampoline_onion_packetを作成する。trampoline_onion_packetは固定サイズのTLVパケットで、以下の構造を持つ。

  1. タイプ:trampoline_onion_packet
  2. データ:
    • [1 : 0x08] (type)
    • [3 : 0xfde202] (length)
    • [1 : version]
    • [33 : public_key]
    • [672 : tranpoline_hops_data]
    • [32 : hmac]

この中のtranpoline_hops_dataフィールドが、次のトランポリンホップのアドレスや転送情報およびそれに関連するHMACの難読化データで構成されるtrampoline_hop_payloadのリストになる。そのため、ここでは、TA1、TA2、TB3、ボブの3つのtrampoline_hop_payloadをセットすることになる。ここで最後のボブはトランポリンノードではないが、TB3にボブが受信者であることを特定されないよう、TB3にとっては次のトランポリンホップであると認識させる(このあたりは従来のLNのオニオンルーティングの仕組みを踏襲している)。そのため、trampoline_onion_packetもトランポリンノードが使用されるトランポリンノードの数を推測できないように固定サイズになっている。

④ 続いてアリスは、最初のトランポリンノードTA1までの経路を計算する。この経路をアリス -> H1 -> H2 -> TA1とする。

⑤続いて、アリスは④の経路の支払いをするため、onion_packetを作成する。このonion_packethop_payloadはH1、H2、TA1用の3つのペイロードをセットする。最後のTA1用のhop_payloadには③で作成したtrampoline_onion_packetがセットされる。※ ただ、H2はその内容がtrampoline_onion_packetであることを知ること無く、他のノードと同様onion_packetとして転送する。

⑥ H1, H2を経由してTA1は受信したonion_packetからtrampoline_onion_packetを見つけ、トランポリンペイメントであることを認識する。そしてtrampoline_onion_packetから次のトランポリンホップTA2への経路を計算する。この経路をTA1 -> H3 -> H4 -> TA2とする。

⑦ TA1はTA2までの支払いを転送するonion_packetを作成する。このonion_packethop_payloadはH1、H2、TA1用の3つのペイロードをセットする。最後のTA2用のhop_payloadにはTA1が受信したtrampoline_onion_packetのTA1分を剥がしたものがセットされる。

⑧ H3, H4を経由してTA2はonion_packetからtrampoline_onion_packetを見つけ、トランポリンペイメントであることを認識する。そしてtrampoline_onion_packetから次のトランポリンホップがTB3であることを認識する。ここでTA2とTB3は直接チャネルを開いているので、T3へ支払いを転送するonion_packetを作成する。このonion_packethop_payloadには受信したtrampoline_onion_packetからTA2分の層が剥がされたものがセットされる。※ TA2→TB3間は直接チャネルを開いているのでルーティングコストはかからない。

⑨ TB3は受信したonion_packetからtrampoline_onion_packetを見つけ、トランポリンペイメントであることを認識する。そしてtrampoline_onion_packetから次のトランポリンホップボブへの経路を計算する。この経路をTB3 -> H5 -> ボブとする。最後のボブ用のhop_payloadにはTB3が受信したtrampoline_onion_packetのTB3分を剥がしたものがセットされる。 ※この時TB3はボブが受信者であることが分からないので、あくまで次のトランポリンホップであると認識している。

⑩ H5を経由してボブは、onion_packetからtrampoline_onion_packetを見つけ、トランポリンペイメントであることを認識する。但し、hmacの値が0x00...00なので自身が受信者であると認識する。また、最後の

以上のように、制限デバイスはトランポリンノードに途中の経路計算を代替させ、送信者、受信者の情報を従来のLNの支払いと変わらない匿名性を持って支払いを行う。図にまとめると↓のような感じ。

f:id:techmedia-think:20190731134818p:plain
トランポリンペイメントフロー

受信者がトランポリンペイメントをサポートしないケース

上記はアリスとボブ両者がトランポリンペイメントをサポートしているケースだったけど、ボブがトランポリンペイメントをサポートしない場合も途中までトランポリンペイメントを利用することができる。

アリスがtrampoline_hop_payloadのリストを構成する際、最後のトランポリンノード(ボブではない)のtrampoline_hop_payloadにだけ以下のrecipient_infoTLVパケットを含めるようにする。

  1. タイプ:recipient_info
  2. データ:
    • [1 : 0x0a] (type)
    • [1 : 0x01] (length)
    • [1 : 0x00] (option_trampoline_routing)

受信したパケットに↑が含まれていた場合、そのトランポリンノードは自身が最後のトランポリンノードであると認識し、最後のホップを標準のオニオン支払いに変換して送信してもらう。

こうすることでボブがトランポリンペイメントをサポートしていなくても送金できるが、この場合、最後のトランポリンノードに受信者の身元と送金額が分かってしまうというプライベー上のデメリットが発生する。プライバシーを確保したい場合は、トランポリンペイメントをサポートするか、受信者が身元を隠すために別途ランデブールーティングなど利用する他ない。

以上が、現在提案されているトランポリンペイメントの仕組み。まだ提案中の仕様なので、今後変更される可能性はある。

※ トランポリンペイメントで新しく導入されるメッセージの具体的なデータ構造についてはプルリクの提案内容を参照。↓は参考までに、プルリクを和訳したもの(こういう機能単位のドキュメントがあるのいいよね。BOLTの各章に分散して書かれると機能の全体像が掴みづらいので、こういうBIPみたいな方が機能を把握しやすい)。

トランポリンペイメントの提案の和訳 · GitHub