トラストレスな双方向のオフチェーン決済を可能にするペイメントチャネルだが実用に向けてはまだ課題も多い。
techmedia-think.hatenablog.com
課題の1つにペイメントチャネルのキャパシティ(=チャネル内で決済できる金額の上限)が固定されている点がある。このためキャパシティを超える金額を送金したい場合や、2者間のチャネル決済において片一方に全ての資金が渡った後にさらに決済したい場合には、一度チャネルを閉じて、大きめのキャパシティや追加の資金を投入して新しいペイメントチャネルを構築する必要がある。チャネルを閉じて再度チャネルを開くということはクローズとオープンの2つのトランザクションをブロックに入れるためにブロードキャストする必要があり、当然各トランザクションには手数料が必要になる。
またキャパシティ以外にも取引相手のノードがクラッシュしたりオフラインになると、最終残高の資金を確保するためチャネルをクローズする必要があり、チャネルが不安定であればその機会も増え、これも手数料負担の増加につながる。
この問題を改善するマイクロペイメントチャネルのプロトコルを提案しているのが↓のホワイトペーパーだ。
Scalable Funding of Bitcoin Micropayment Channel Networks
Channel Factory
ホワイトペーパーでは、Bitcoinのブロックチェーンとそのオフチェーンのペイメントチャネルの間にChannel Factoryと呼ばれるレイヤーを追加することで、二者間のペイメントチャネルのキャパシティを動的に調整できるようにしている。
今までのペイメントチャネルだと、ペイメントチャネルを構築する2者がそれぞれのコインをインプットにセットし、両者のマルチシグアウトプットにそのコインを送るトランザクションを作ってオンチェーンにコインをロックし、そのコインをインプットにして決済毎に両者の残高を更新するコミットメントトランザクションを交換してオフチェーン決済を行う。
注釈
サークルはトランザクションアウトプットで、ボックスはトランザクション。サークルの各色は各アウトプットの所有者を表している。1つのサークルに複数の色があるのは、そのアウトプットを使用するのにサークルの色の所有者の署名が必要であることを示している。鍵マークはチャネルがオープンしている間、ブロックチェーン上では未使用のアウトプットになっていることを表す。
Channel Factoryの構成要素
- Hook
Hookトランザクションは、チャネルに参加する資金を全参加者のマルチシグにロックするトランザクション。今までのペイメントチャネルでいうと2者のマルチシグに資金をロックするファンディングトランザクション(オープニングトランザクション)で、2者でなくチャネルの全参加者という点が異なる。このトランザクションがブロックに格納されることでチャネルが開かれる。 - Allocation
AllocationトランザクションはHookトランザクションをインプットとし、アウトプットが後続の各ペイメントチャネル(サブチャネル)のインプットになる。後に作るペイメントチャネルのファンディングトランザクションのインプットをAllocationトランザクションで作成している。各アウトプットは各ペイメントチャネルの全参加者マルチシグアウトプットになる。 - Commitment
2者間のペイメントチャネルを構成するトランザクションで、既存のペイメントチャネルのCommitmentトランザクションと機能は変わらない。インプットとなるのが、既存のペイメントチャネルではオンチェーン上に2者のマルチシグにロックされたアウトプットであるのに対し、Channel FactoryではオフチェーントランザクションであるAllocationトランザクションのアウトプットになる。
今までのペイメントチャネルではチャネルの残高を管理する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の更新は以下の手順で行う。
- 他のペイメントチャネルに資金を移動したくなったユーザーは、新しいAllocationの作成をグループ内の全ノードに通知する。
- Allocationの更新リクエストを受信したノードは、自身が参加している全サブチャネルの取引相手に現在の各チャネルの状態(残高)で、新しいAllocationに対応するようリクエストする。
- 各サブチャネルの2人の参加者は協力して、新しいAllocationをベースにしたサブチャネルの初期状態を決め、それをグループに通知する。
- 各ノードはそれぞれ新しいAllocationトランザクションを作成する。このトランザクションはサブチャネルに資金を供給するものなので、全チャネルを通して1つの同じトランザクションでなければならない。
- 各サブチャネルは新しいAllocationトランザクションをインプットにしたCommitmentトランザクションを作成し、署名する。これ以降サブチャネルの参加者はサブチャネルの決済を更新する(Commitmentトランザクションを更新する)場合、新旧のAllocationトランザクション両方についてCommitmentトランザクションを作成することになる。
- 全ノードが新しいAllocationトランザクションに署名し、その署名を交換する。
- 新しいAllocationの署名が全て揃ったら、各ノードは古いAllocationに基づいたサブチャネルの更新を止めることができる。
また常に合意した新しいAllocationが適用される(=古いAllocationがブロードキャストされない)よう、各Allocationトランザクションには相対的なタイムロックが施されている。
新しいAllocationトランザクションを作る際は必ず古いAllocationよりも短いロックタイムが設定される。これによりAllocationトランザクションのインプットが参照するトランザクションがブロードキャストされた後、一番速いタイミングでブロードキャストできるのは最新のAllocationトランザクションであることを保証している。
2者間のペイメントチャネルに比べて、グループの参加者が増えるほど新しいAllocationを作成するための調整コストは増える。ただ、自身が資金移動する側ではないノードにとっては、新しいAllocationの通知が届いたら新しいAllocationベースのサブチャネルを開いて、新旧両方のサブチャネルを一緒に更新していけば、Allocationトランザクションの署名が全部揃うまで待つことなく、オフチェーンの決済自体は継続して行える。
尚、このAllocationの更新には参加者の総数をp
とした場合、O(p2)回の通信のオーバーヘッドが発生するが、これ自体はリーダーを置くことでO(p)まで減少できるみたい。
セトルメント
Channel Factoryを閉じたい場合は、今までのペイメントチャネルと同じように、各サブチャネルの状態を考慮して全参加者の最終状態(残高)を決め、Hookトランザクションをインプットとし、各参加者毎の残高をセットしたアウトプットを持つSettlement トランザクションを作成し、全員で署名しブロードキャストする。ブロックチェーン上にはHookトランザクションとSettlementトランザクションのみが現れる。
スプライスアウト
ペイメントチャネルの課題として相手のノードがクラッシュしたりオフラインとなったままで決済が継続できないケースがある。通常であれば最新の残高でCommitmentトランザクションをブロードキャストしチャネルをクローズする。Channel Factoryにおいても応答の無いノードがいると、新しいAllocationへの更新や応答の無いノードが参加しているサブチャネルのCommitmentの更新ができなくなる。この問題の解決方法の1つとして、以下のようにまだアクティブな参加者が集まってその全アウトプットを使って新しい共有アカウントを作る方法がある。
↑では4人が参加するChannel Factoryで、そのうちの2名ずつで計6個のサブチャネルを持っている。その状況で赤いノードが応答がなくなった場合、残りの3ノードはそれらで構成されるチャネルのインプットとなっているAllocationのアウトプットを全て集め、そのアウトプットをインプットにした新しいHookトランザクションを作り、それ以下にさらにChannel Factoryを構成する。この時作成するHookにはもちろん応答の無かった赤いノードは除外する。
新しく作成したHookトランザクションはブロードキャストする必要はなく、赤いノードが復帰したら新しいAllocationを作成してそこからチャネルを継続したり、通常のSettlementを作成してチャネルを閉じることもできる。赤いノードからずっと応答が無い場合は最後のAllocationをブロードキャストする必要があり、そうすると全てのサブチャネルの状態もブロックチェーン上に記録されることとなる。
このスプライスアウトの仕組みによって、クラッシュしたノードをある一定期間まったり、たまにオフラインになる取引相手などを許容することができる。
Channel Factoryの多層化
グループが大きければ大きいほど、オフチェーン決済の量が増え、ブロックチェーンのスペースは節約できる(当然、大きくなるほどその調整コストは上がるが)。大きなグループにするがAllocationの更新時の協調作業は少なくしたいといった場合に以下のようにChannel Factoryを多層化する方法がある。
↑では参加者が8人いて、それを1つめのAllocationトランザクションで4-of-4のマルチシグアウトプット3つに、その3つのアウトプットをインプットにした2層目のAllocationトランザクションを作る。この2層目のAllocationの配下に従来のサブチャネルを配置していく。これだと、1層目のAllocationを更新するのには8人の署名が必要だが、2層目の範囲内でAllocationを更新する分には4人の署名だけあれば済む。より大きなグループを構成する場合はこういった多層化が効果的になる。ただ大きくなるほどチャネルクローズ時のインパクトも大きい。