Develop with pleasure!

福岡でCloudとかBlockchainとか。

1つのUTXOの所有権を複数人でシェアするCoinPool

Lightning Networkなどの現在主流のペイメントチャネルプロトコルはいずれも2人で1つのUTXOの所有権を管理するプロトコルだけど、N(N > 2)人で1つのUTXOの所有権を管理できるようにするプロトコルがCoinPoolで、少し前にホワイトペーパーが公開された↓ので、内容を見ていこう。

https://coinpool.dev/v0.1.pdf

CoinPool

CoinPoolは、LNなどのプロトコルや運用から得られた教訓をもとに、UTXOの所有権を共有するこで新しいスケーラビリティ構造を提案するプロトコルになる。CoinPoolではN人のプール参加者のコインを1つのUTXO(プール)で管理する。つまりN人が1つのUTXOの所有権を共有することになる。そしてこのプールについて、以下の基本的な機能を提供する。

  • 参加者はプール内で、オフチェーンで資金の転送ができる(プール内の資金の配分を変更できる)。
  • 参加者は、他の参加者の承諾なしに、いつでもプールから抜けることができる。

そして、高度な機能として、ペイメントチャネルなどのコントラクトでの使用や、LNや他のプールのユーザーとの取引に使用することができる。

セットアップ

N人の参加者はUTXOを持ち寄って、CoinPoolをセットアップする。まずN人の参加者はキーキャンセルができない方法を使って、それぞれの公開鍵(N個の公開鍵)を加算して集約公開鍵Pを作成する。セットアップでは、以下の3種類のトランザクションを作成する。

f:id:techmedia-think:20220320160335p:plain
CoinPoolのセットアップ

Setup Tx

各メンバーのUTXOをインプットとして、単一のUTXOに参加者の資金をロックするトランザクション。このアウトプットをPre-CoinPoolアウトプットと呼ぶ。Pre-CoinPoolアウトプットは、参加者全員の鍵から計算した集約公開鍵Pにロックされる。

Update Tx

プールの状態を表すトランザクションで、Setup TxのPre-CoinPoolアウトプットをインプットとし、アウトプットは以下の支払いパスを持つTaprootアウトプット(CoinPoolアウトプット)になる。

  • Key-Path: 参加者全員の集約公開鍵P
  • Script-Path: 以下のアンロック条件を持つ。
    • 参加者全員が協力してUpdate Txを更新する際に使用する条件
    • N個の各参加者毎の引き出し条件
Withdraw Tx

これは各参加者が、他の参加者の許諾なしにプールを抜ける際に使用するトランザクションで、各参加者の人数分作られる。

Update TxのCoinPoolアウトプットをインプットとし、以下の2つのアウトプットを持つ。

  • CoinPoolから抜ける退出者の金額をロックしたアウトプット
  • 退出者を除いた残りのCoinPoolの残高をロックしたアウトプット
    • このアウトプットのscriptPubkeyは、Update TxのCoinPoolアウトプットからCoinPoolから抜ける参加者の条件を削除したもの。

途中で資金がロックされることがないように、署名はWithdraw->Update->Setupの順に行われる。

実際のTx構成の例は、以下で公開されてる

gist.github.com

プールの更新

プール内のユーザー間でコインを送金する場合は、新しいUpdate Txと送金後のバランスを反映したWithdraw Txのセットを作成することでオフチェーンで送金が完了する。

古い状態のUpdate Txがブロードキャストされるようなことがあれば、ブロードキャストしたユーザーがWithdraw Txで引き出す前に(タイムロックされてる間に)、eltooの仕組みにより最新のUpdate Txに置き換える。

プールからの引き出し

プール参加者は、他の参加者の許諾なしにいつでもプールから退出(引き出し)できる。

退出する参加者は、

  1. 最新のUpdate Txをブロードキャストする。
  2. 続いて、自身のWithdraw Txをブロードキャストする。
    • ただし、Update TxのCoinPoolのUTXOをWithdraw Txで使用する際はタイムロックが付与されているので、Update Txがブロックに格納されてから一定期間待つ必要がある。
    • タイムロックが経過したら他の参加者が署名済みの自身のWithdraw Txに自身の署名を追加してブロードキャストする。

この結果、退出する参加者のプールの残高は、Withdraw TxのUTXOとして利用可能になり、残りのプール参加者には同様にプールから退出するかプールに留まるかの選択肢がある。

  • プールから退出する場合は、このWithdraw TxのCoinPool UTXOをインプットとしてプールから抜ける。
  • 継続する場合は、Snapshot Txを作成&ブロードキャストし、これまで事前署名したWithdraw Txの署名を無効にする。Snapshot TxはWithdraw TxのCoinPool UTXOをインプットとし、残ったプールメンバーの集約公開鍵にコインをロックするトランザクションでSetup Txと似たトランザクションになる。当然ながら、Snapshot Txに署名する前に、後続となるUpdate TxおよびWithdraw Txのセットを作成し先に署名しておく必要がある。

Bitcoinに必要な機能追加

CoinPoolプロトコルは、現在のBitcoinプロトコルでは実装ができず、Bitcoinに以下の機能を追加する必要がある。

OP_MERKLESUB

OI_MERKLESUBは、Update TxおよびWithdraw TxのCoin Poolアウトプットの各ユーザーの引き出し条件のスクリプトに使われる。これは、プールからのユーザーの退出にあたって、

  • プールから退出するユーザーの引き出しに使用する条件ブランチが新しいCoinPoolアウトプットのTapScriptのツリーから削除されている。
  • プールから退出するユーザーの公開鍵が新しいCoinPoolアウトプット集約公開鍵から削除されている。

ことを保証する必要があり、その検証をするために新たに追加されるopcodeになる。このopcodeの仕様案は↓

https://github.com/ariard/bips/blob/coinpool-bips/bip-merklesub.mediawiki

SIGHASH_GROUP

Withdraw Txの2つのアウトプットの量が、それぞれ

  • 元々プール参加者全員が合意した退出ユーザーの残高であること
  • 残りのプールのCoinPoolアウトプット量はプールの量から退出者の残高を差し引いた額と等しいこと

を保証する必要がある。これを事前署名時にコミットするために新しいSIGHASHタイプであるSIGHASH_GROUPが必要になる。この具体的な仕様は↓

https://github.com/ariard/bips/blob/coinpool-bips/bip-group.mediawiki

SIGHASH_ANYPREVOUT

Update Txの更新にeltooスタイルで行うため、SIGHASH_ANYPREVOUTが必要になる。

また、Taprootアウトプットとして構成されるCoinPoolアウトプットのTapscriptでは、ツリーのリーフブランチに各ユーザーの引き出しが可能な条件が設定されている。このリーフを2社間のペイメントチャネルで利用可能にすることで、CoinPoolのスケーラビリティは大きく向上する。ただ、CoinPoolのステート(Update Tx)は随時更新されるため、このリーフレベルのペイメントチャネルを有効にするためには、特定のステートにロックされることがないよう、SIGHASH_ANYPREVOUTによりペイメントチャネルの参照先のUpdate Txを切り替えられる必要がある。