LNリサーチ#1: カラードコインとLightning Network

はじめに

こんにちは、ビットバンクのチーフ・ビットコイン・オフィサーのジョナサンです。
Lightning R&Dの取り組みとしてレポート形式でブログで公開します。

今回はその第一弾で、カラードコインとLightning Networkについて書きます。

背景

ビットコインが生まれて間もないころから、TXOに色付けを行い1サトシに証券・土地などの意味を持たせることにより、ビットコインにさまざまなユースケースを組み込もうという試みが行われてきた。

代表的なものとしては、Tetherに用いられているOmniや、Pepecashなどに用いられているCounterpartyなどが存在する。

このような多くの色付きコイン(Colored Coin、以下「カラードコイン」)は、それぞれのプロトコルにおいてビットコインの取引データに付加情報を埋め込むことで成り立っている。
しかし、たくさんの付加情報を埋め込みたい場合、それに比例しトランザクションサイズが大きくなるため、送金手数料が高くなってしまう。

よって、カラードコインプロトコルの開発者はこれまで、ビットコインのオンチェインスケーリングの未来を望んできたとしても不思議ではない。

そんな状況の中で、ビットコインのスケーリング課題への解決策として、オフチェインをなるべくトラストレスにするという方向性が見えてきた。
これによりブロックサイズの引き上げ議論は優先度が下がったため、多くのカラードコインは存亡の危機にさらされているかもしれない。

このことから、カラードコインとオフチェインとの相性が今問われている。
もしオフチェインの最先端技術Lightning Network(以下LN)で、カラードコインも取引できるようになれば、カラードコインの存続は確実になると思われるので考えてみたい。

カラードコインのしくみ

ここでは、カラードコインの発行のしくみなどは割愛し、LNと関係がありそうな送金プロセスに話題を絞る。

OP_RETURN

多くのカラードコインが、OP_RETURNの出力と通常の出力を隣り合わせにすることで、カラードコインの送金を成り立たせている。

例として、OP_RETURNを使ってTetherの送金を行う例を見てみよう。

const bitcoinjs = require('bitcoinjs-lib')

function createSimpleSend(unspents, alice_pair, recipient_address) {

  const txb = new bitcoinjs.TransactionBuilder()

  const alice_p2pkh = bitcoinjs.payments.p2pkh({
    pubkey: alice_pair.publicKey
  }).address

  const smallestOutputValue     = 546 // 最低出力金額
  const feeValue      = 5000 // 本当は手数料推測すべきですが、あくまで一例なので固定値
  const totalUnspent  = unspents.reduce((sum, { satoshis }) => sum + satoshis, 0)
  const changeValue     = totalUnspent - smallestOutputValue - feeValue

  if (totalUnspent < feeValue + smallestOutputValue) {
    throw new Error(`残高不足: ${totalUnspent} < ${feeValue} + ${smallestOutputValue}`)
  }

  // 注目:入力を追加している、とりあえずあるだけ追加する
  unspents.forEach(({ txid, vout }) => txb.addInput(txid, vout))

  const simple_send = Buffer.from([
    "6f6d6e69", // omni 4バイト (ASCII)
    "0000",     // version 2バイト
    "00000000001f", // 31 は Tether の識別番号 6バイト
    "00000000fa56ea00" // amount = 42 * 1e8 HEX  8バイト
  ].join(''), 'hex')

  const data = [ simple_send ]

  // payments.embed は OP_RETURN のことを指している
  // data は Buffer の Array でそれぞれのBufferをstackにプッシュする
  const omniOutput = bitcoinjs.payments.embed({ data }).output

  // 注目:最低金額のビットコイン出力の直後に生のデータを表した出力
  txb.addOutput(recipient_address, smallestOutputValue)
  txb.addOutput(omniOutput, 0)

  // あまりが最低金額下回っているならそのまま手数料に上乗せ (出力追加しない)
  if (changeValue >= smallestOutputValue) txb.addOutput(alice_p2pkh, changeValue)

  unspents.forEach((unspent, index) => {
    txb.sign(index, alice_pair)
  })

  // この16進の文字列を伝搬する
  return txb.build().toHex()
}

ご覧の通り、単に各入力が指している出力の隣の出力を参照し、「どのTXOに」「どのコインが」「どのくらいの金額なのか」を別管理しているだけに過ぎない。

OP_RETURNを活用するカラードコイン

代表的なものは以下の通り。

OP_RETURN以外のカラードコイン

OP_RETURNを利用せずカラードコインを実装する例としては、たとえば1-of-3 のマルチシグを作成し、公開鍵と見せかけているところにデータを埋め込む方式もある。

ただしこのような方法は非推奨とされているため、後の考察には含めないこととする。

Lightning Network

LNのしくみ(省略版)

LNのチャンネルというのは、簡潔にいうと

「両者で管理するマルチシグ取引における出力の中身と金額を、お互いの送金し合った結果の最新状態が反映されるように調整するしくみ」

である。

詳細に関しては以前、過去に私がイベントで使ったスライドをどうぞ
(Dockerを利用した実践も含まれている)

よし、使えること決定じゃん!はい、次のお題ー!

ちょっと待った! そう簡単な問題ではない。

LNのチャンネル一つに焦点を絞れば、たしかにカラードコインの概念をもたせることは簡単にできる。(OP_RETURNの出力が増えるだけ)

ただし、「Network」の部分に大事な論点がいくつか存在する。

相性を考えよう

ビットコインを送金するためのLNでは、ネットワークの円滑な稼働を計るために必要な要素がいくつかある。

  • ルーティング
    • チャンネルの存在を確認し、相手へ送金するためにどのチャンネルを通れば良いかを知る必要がある。
  • キャパシティと流動性
    • 特定の送金相手までのルートにて、十分な金額がなければ送金できない。
  • 手数料
    • 手数料はオンチェイン取引に比べ非常に安いが、各ホップで1サトシ程度の手数料を払わされることが主流。
ルーティング

カラードコインのルーティングを行うためには、「チャンネル」および「ノード」レベルで、カラードコインへの対応の有無を知ることが必要。

LNには、ノード接続時のinitメッセージおよびチャンネルのアナウンスを行うchannel_announcementにて features フラグというものが存在する。

このフラグは機能のオン/オフを表現するために用いられるものであり、以下のしくみである。

  1. ビットの配置が偶数 = 必須
    • 偶数配置のビットで対応していないものは、拒否される
  2. ビットの配置が奇数 = オプション
    • 奇数配置のビットで対応していないものは、無視してそのまま接続またはチャンネルを活用してよい

このフラグを用いてカラードコイン対応の有無を表現するとしたら、

  • ノードのフラグを必須にすると、カラードコインに対応するノードとしか接続しない。
  • チャンネルのフラグを必須にすると、カラードコインに対応するノードしかそのチャンネルを活用しない。

ここで戦略が2つあると思われる。

  1. 既存のビットコインLNに便乗する
    • この場合、優先的にカラードコインに対応するピアと接続しチャンネル開くロジックを入れないと厳しそう
  2. 別のLNネットワークの構築
    • ルーティングは簡単になるが、流動性の問題などが目立つようになる
キャパシティーと流動性

カラードコインと一言で言っても、付いている「色」(コインの種類)は一つだけではない。

よって、ルーティングの途中で別の種類のコインどうしが交換されるしくみ(Lightning Atomic Swap) はほぼ必須な要件であると思われる。

ここで、たとえばBTCとLTCなどのオルトコインとのスワップと比べた時に、圧倒的な利点は「検証しないといけないブロックチェインが一つのみ」というところ。
同じビットコイン上で管理するカラードコインどうしであれば、スワップのしくみはどちらかというと coinjoinに似ているのでアトミックスワップの実装の難易度が下がるはず。(交換レートはどうやって交渉するのかという論点は同じだが)

もしそういった機能なしで運用するとしたら、特定の一つのカラードコインプロトコルの特定の一つの種類のコインしか扱えなくなってしまい、流動性が損なわれることとなるだろう。

手数料

カラードコインの利用者はビットコインでオンチェインの手数料を払うことに慣れている。LNになったとしても、チャンネルの開閉時の手数料は今までどおり、ビットコインで支払うことに変わりはない。

ただし、LNのルーティング手数料はカラードコインで徴収することも可能。

そう考えると、たとえばUSDTなどのステーブルコインのネットワークを構築し、「チャンネルの開閉コストはBTCで払うが既存のチャンネルを利用するだけならUSDTで完結する」という状況が簡単に作れそうだ。
チャンネルファクトリーなどを活用すればさらにおもしろいネットワークが作れる。

結論

  • カラードコインを扱う別LNが必要と思われる。
  • カラードコインどうしを同一チャンネルで交換できるよう「coinjoin方式」 になっていないと厳しい。
  • カラードコインのLNネットワークの中に流動性の高いコインが一つでもあれば、ほかのコインが便乗してくるかもしれない。
  • 初動はUSDTなどで実験的なカラードコインネットワークができあがればおもしろい。
expand_less