Develop with pleasure!

福岡でCloudとかBlockchainとか。

ペイメントチャネル間の資金移動を可能にするChannel Factory

トラストレスな双方向のオフチェーン決済を可能にするペイメントチャネルだが実用に向けてはまだ課題も多い。

techmedia-think.hatenablog.com

課題の1つにペイメントチャネルのキャパシティ(=チャネル内で決済できる金額の上限)が固定されている点がある。このためキャパシティを超える金額を送金したい場合や、2者間のチャネル決済において片一方に全ての資金が渡った後にさらに決済したい場合には、一度チャネルを閉じて、大きめのキャパシティや追加の資金を投入して新しいペイメントチャネルを構築する必要がある。チャネルを閉じて再度チャネルを開くということはクローズとオープンの2つのトランザクションをブロックに入れるためにブロードキャストする必要があり、当然各トランザクションには手数料が必要になる。

またキャパシティ以外にも取引相手のノードがクラッシュしたりオフラインになると、最終残高の資金を確保するためチャネルをクローズする必要があり、チャネルが不安定であればその機会も増え、これも手数料負担の増加につながる。

この問題を改善するマイクロペイメントチャネルのプロトコルを提案しているのが↓のホワイトペーパーだ。

Scalable Funding of Bitcoin Micropayment Channel Networks

Channel Factory

ホワイトペーパーでは、Bitcoinブロックチェーンとそのオフチェーンのペイメントチャネルの間にChannel Factoryと呼ばれるレイヤーを追加することで、二者間のペイメントチャネルのキャパシティを動的に調整できるようにしている。

今までのペイメントチャネルだと、ペイメントチャネルを構築する2者がそれぞれのコインをインプットにセットし、両者のマルチシグアウトプットにそのコインを送るトランザクションを作ってオンチェーンにコインをロックし、そのコインをインプットにして決済毎に両者の残高を更新するコミットメントトランザクションを交換してオフチェーン決済を行う。

f:id:techmedia-think:20171124223500p:plain
Channel Factoryの構成

注釈

サークルはトランザクションアウトプットで、ボックスはトランザクション。サークルの各色は各アウトプットの所有者を表している。1つのサークルに複数の色があるのは、そのアウトプットを使用するのにサークルの色の所有者の署名が必要であることを示している。鍵マークはチャネルがオープンしている間、ブロックチェーン上では未使用のアウトプットになっていることを表す。

Channel Factoryの構成要素

今までのペイメントチャネルではチャネルの残高を管理するCommitmentトランザクションが直接オンチェーン上にロックされている2者間のマルチシグをインプットとして参照していたが、その間にオフチェーンのAllocationトランザクションを挟み、CommitmentトランザクションがインプットとしてAllocationトランザクションのアウトプットを参照するようにし、Allocationトランザクションの内容をオフチェーンで更新していくことで、サブチャネルの各マイクロペイメントチャネルのキャパシティもオフチェーンで動的に変更できるようにしようというのがChannel Factoryのアプローチ。

また今までのペイメントチャネルでは1つのチャネルの参加者は2人でチャネルをオープン/クローズする際も2人で協力すればよかったが、Channel Factoryでは実際のマイクロペイメントチャネルの参加者は2者だが、Channel Factoryには多数のユーザーが参加するため、Channel Factoryをセットアップする際やAllocationトランザクションを更新する際は、Channel Factoryに参加しているメンバー全員の協力が必要になる。

↑の図では、3人のユーザーがChannel Factoryに参加し、3人の内2人ずつ組み合わせた計3つのペイメントチャネルを作っている。

Channel Factoryのセットアップ

Channel Factoryを初期セットアップするには、まずHook、Allocation、各Commitmentの一連のトランザクションを作成する(Hook→Commitmentまで未署名で作成するので当然Segwitが必須)。続いて、全参加者でAllocation、各Commitmentトランザクションの署名を完成させる。全ての署名が揃ったら最後にHookトランザクションに署名する。署名済みのHookトランザクションをブロードキャストしブロックに格納されてから十分時間が経ったらチャネルが使用できるようになる。

Allocationの更新

サブチャネルのペイメントチャネルで資金が不足した場合、Allocationトランザクションの各アウトプットの残高を変更した新しいAllocationトランザクションを作成し置き換えることサブチャネル内の別のチャネルから資金を移動してくることができる。Allocationが置き換わると当然それを参照してるサブチャネルのCommitmentも更新が必要になる。Allocationの更新は以下の手順で行う。

  1. 他のペイメントチャネルに資金を移動したくなったユーザーは、新しいAllocationの作成をグループ内の全ノードに通知する。
  2. Allocationの更新リクエストを受信したノードは、自身が参加している全サブチャネルの取引相手に現在の各チャネルの状態(残高)で、新しいAllocationに対応するようリクエストする。
  3. 各サブチャネルの2人の参加者は協力して、新しいAllocationをベースにしたサブチャネルの初期状態を決め、それをグループに通知する。
  4. 各ノードはそれぞれ新しいAllocationトランザクションを作成する。このトランザクションはサブチャネルに資金を供給するものなので、全チャネルを通して1つの同じトランザクションでなければならない。
  5. 各サブチャネルは新しいAllocationトランザクションをインプットにしたCommitmentトランザクションを作成し、署名する。これ以降サブチャネルの参加者はサブチャネルの決済を更新する(Commitmentトランザクションを更新する)場合、新旧のAllocationトランザクション両方についてCommitmentトランザクションを作成することになる。
  6. 全ノードが新しいAllocationトランザクションに署名し、その署名を交換する。
  7. 新しいAllocationの署名が全て揃ったら、各ノードは古いAllocationに基づいたサブチャネルの更新を止めることができる。

また常に合意した新しいAllocationが適用される(=古いAllocationがブロードキャストされない)よう、各Allocationトランザクションには相対的なタイムロックが施されている。

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

新しいAllocationトランザクションを作る際は必ず古いAllocationよりも短いロックタイムが設定される。これによりAllocationトランザクションのインプットが参照するトランザクションがブロードキャストされた後、一番速いタイミングでブロードキャストできるのは最新のAllocationトランザクションであることを保証している。

2者間のペイメントチャネルに比べて、グループの参加者が増えるほど新しいAllocationを作成するための調整コストは増える。ただ、自身が資金移動する側ではないノードにとっては、新しいAllocationの通知が届いたら新しいAllocationベースのサブチャネルを開いて、新旧両方のサブチャネルを一緒に更新していけば、Allocationトランザクションの署名が全部揃うまで待つことなく、オフチェーンの決済自体は継続して行える。

尚、このAllocationの更新には参加者の総数をpとした場合、O(p2)回の通信のオーバーヘッドが発生するが、これ自体はリーダーを置くことでO(p)まで減少できるみたい。

セトルメント

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

Channel Factoryを閉じたい場合は、今までのペイメントチャネルと同じように、各サブチャネルの状態を考慮して全参加者の最終状態(残高)を決め、Hookトランザクションをインプットとし、各参加者毎の残高をセットしたアウトプットを持つSettlement トランザクションを作成し、全員で署名しブロードキャストする。ブロックチェーン上にはHookトランザクションとSettlementトランザクションのみが現れる。

スプライスアウト

ペイメントチャネルの課題として相手のノードがクラッシュしたりオフラインとなったままで決済が継続できないケースがある。通常であれば最新の残高でCommitmentトランザクションをブロードキャストしチャネルをクローズする。Channel Factoryにおいても応答の無いノードがいると、新しいAllocationへの更新や応答の無いノードが参加しているサブチャネルのCommitmentの更新ができなくなる。この問題の解決方法の1つとして、以下のようにまだアクティブな参加者が集まってその全アウトプットを使って新しい共有アカウントを作る方法がある。

div.fc-ab-root").style.setProperty('display', 'none', 'important');