Develop with pleasure!

福岡でCloudとかBlockchainとか。

Watchtowerと連携したLightning Networkウォレットのバックアッププロトコル「Açai」

Scaling Bitcoin 2019復習シリーズ第一弾は、「Açai: a backup protocol for Lightning Network wallets」

通常のオンチェーン決済をするウォレットであれば、BIP-32やBIP-39などの技術を使って、ニーモニックワードさえ記録しておけば、そこからマスターシードを復元し、ウォレット内の取引で使用する秘密鍵を復元することができるが、LNのようなオフチェーン決済では、このような事が難しく、ウォレットの障害などでデータが破損、欠落してしまうとLNのチャネル内の資金を失う可能性がある。このような問題に対処するためのLNウォレットのバックアッププロトコルの提案が↑の内容。

Watchtower

バックアッププロトコルに関連するプロダクトの1つがWatchtower。

LNを利用した支払いでは、取引相手が不正をした場合(相手に有利な古い状態のチャネルをオンチェーンのブロードキャストするなど)、不正をした相手の資金を含むチャネルの全資金をペナルティとして没収するトランザクション(Justice Tx)をオンチェーンにブロードキャストすることで対抗する。ただ、これを正しく実行するためには常にオンチェーンの状態を監視しておく必要があるが、スマートフォンなど常にオンラインにあるか分からないようなデヴァイスにとっては難しいこともある。そこで監視とJustice Txのブロードキャストをアウトソースするための仕組みがWatchtowerだ。

Watchtowerの仕組み

アリスがボブとチャネルを開いいる場合、Watchtowerは以下のように動作する。

アリスはボブとのチャネルのコミットメントが更新される度に、最新のチャネル状態をWatchtowerに通知する。具体的には、以下のようにHintとBlobをWatchtowerに送信する。

  1. アリスとボブ間のチャネル状態を変更(新しいコミットメントに署名)
  2. アリスは新しいコミットメントTxのtxidの先頭16バイトをHintとする。
  3. アリスはtxidの後半16バイトを共通鍵としてコミットメント自体も暗号化したBlobを作成する。
  4. アリスはHintとBlobをWatchtowerに送信する。

ボブがアリスを裏切って古い状態のコミットメントをブロードキャストすると、

  1. Watchtowerはアリスから送られてきたHintとメモリプール内のトランザクションのtxidの先頭16バイトを比較し、合致するトランザクションが無いかチェックする。
  2. 合致するトランザクションがあれば、そのtxidがHintと一緒に送られてきたBlobを復号するための鍵になるので、その鍵を使ってBlobを復号する。
  3. WatchtowerはそのBlobのデータを使ってJustice Txを完成させ、ブロードキャストする。

という手順で監視およびJustice Txのブロードキャストをする。

※ Watchtowerに関しては、インセンティブの問題や、いつまでHintやBlobを保持するのか?、ちゃんとJustice Txをブロードキャストされるか?、プライバシーなど課題もまだあり、さまざまな提案が出ている。

Açaiプロトコル

識別子 Açaiプロトコルでは、Watchtowerをチャネルの監視だけでなく、バックアップサービスとして利用するプロトコルで以下の機能がベースになっている。

  • Watchtower
  • Eltoo
  • BIP-32, 44, 39

そしてWatchtowerののtxid、Hint、Blobの仕組みをバックアップの仕組みでも同様に使用する(監視とAçaiによるバックアップの仕組みを区別するのにAçaiバックアップに使用する際の表記をtxidç, Hintç, Blobçと表記する)。

Watchtowerへのバックアップの送信

チャネルを更新する都度、アリスは新しいチャネル情報(従来のHintとBlob)と新しいバックアップ( Hintçと Blobç)をWatchtowerに送信する。

  1. blobçを復号化したり、識別に使用するtxidçを生成するため*1、その準備としてまずアリスは現在のブロック高を導出変数として利用しBIP-44ベースで公開鍵を生成する(公開鍵= m’/108’/0(mainnet)/(アカウント番号)’/0/現在のブロック高)。108'はBIP-44の任意のpurpose番号で、アカウント番号は使用しているウォレットアカウントの番号。
  2. 続いて算出した公開鍵を使ってtxidçnを計算する。アリスは同じブロック高で多くの支払いを実行する可能性があるので、同じブロック高において新しいAçaiバックアップの状態:txidç_0, txidç_1, txidç_2, txidç_3を列挙する必要がある。同じブロック高ではその識別ができないので、同じブロック高内で行われた変更は、前のtxidçの値をハッシュした値として計算する。つまり、txidçnは前のtxidç_n-1のハッシュ値として計算される。3回支払いしているケースでは、txidç_1= SHA256(txidç_0)txidç_2= SHA256(txidç_1)txidç_3= SHA256(txidç_2)のようになる。
  3. txidç_nの前半16バイトをヒントHintç_n= txidç_n[:16]とし、後半16バイトを使ってBlobを暗号化するencrypt Blobç_n= Enc(dataç_n,txidç_n[16:])。ここで暗号化する対象のデータdataç_nはアリスが持つ全チャネルの最新のコミットメントTxのTXIDのリストだ。
  4. 新しいチャネル状態と一緒にバックアップ情報としてHintçnとBlobçnをWatchtowerに送信する。

ポイント

上記のように、ブロック高を変数に鍵導出した公開鍵からtxidçを計算し、その先頭16バイトをユーザーがWatchtowerへ問い合わせする際の識別子(Hintç)として使用し、後半16バイトをBlobçを暗号化/復号化する際の共通鍵として使用する。

Watchtowerへのバックアップの要求

アリスは誤ってデータを失った場合、Watchtowerに対してバックアップを要求できる。また実際にデータを失っていない場合も、Watchtowerにバックアップを要求することで、Watchtowerがちゃんと約束したサービスを提供しているか確認できる。

  1. アリスはノードに現在のブロック高を確認する。
  2. ブロック高とシードを使って決定論的に公開鍵を計算する。 address= m/108’/0(mainnet)’/(アカウント番号’)/0/現在のブロック高
  3. 公開鍵を使ってtxidç_0 = 2SHA256(公開鍵)を計算し、その先頭16バイトをヒントhintç_0=txidç_0[:16]とする。
  4. Watchtowerに対してhintç_0を問い合わせる。
    • Watchtowerがhintç0を知っている場合、同じブロック内に複数のトランザクションがある場合はhintç1も含まれるので、アリスのウォレットはtxidç_1= SHA256(txidç_0)を計算し、Watchtowerにhintç1が含まれるか尋ねる。Watchtowerがhintç1を知っていればさらにtxidç2の計算hintç2の確認と繰り返す。Watchtowerがhintç2を知らない場合、txidç1に最新のチャネル情報が含まれていると想定できるので、アリスはblolbç_1を復号しtxidのリストを抽出する。
    • Watchtowerがhintç_0を知らない場合、アリスには現在のブロック高でのトランザクションは存在しないと想定できるので、ブロック高をデクリメントして新しい公開鍵を公開鍵= m/108’/0(mainnet)’/(アカウント番号)’/0/(現在のブロック高 - 1)を計算する。計算した公開鍵に対して再度ヒントを計算し、上記のチェックを行う。
  5. アリスのウォレットがhintçnを見つけたら、Watchtowerに対して、対応するBlobçnを送るよう要求する。Blobç_nはdataçとtxidç[:16]で構成され、dataç= [アリスが開いているチャネルの最新の状態のtxidのリスト(ボブとそれ以外ともチャネルを開いている場合、その最新のtxidのリスト)]
  6. アリスはdataçからボブとのチャネルの最新のtxid_Blobを復元できる。その値を使って、Hint_Bob = txid_Blobの先頭16バイトを計算し、対応するblob_BlobをWatchtowerに問い合わせる。アリスはtxid_Blobの後半16バイトを使ってblob_Blobのデータを復号し、ボブとのチャネルを復元することができる。
  7. この時点でアリスは自分のデータがWatchtowerに保存されているものと一致するかチェックしたり、データを復元することができる。

ポイント

上記のように、現在のブロック高からバックアップに使用した公開鍵を計算し、そのHintçをWatchtowerに照会し、見つかるまでブロック高をデクリメントしながら繰り返し、最新のバックアップを見つける。最新のバックアップには、アリスの全チャネルの最新のコミットメントTxのTXIDのリストが含まれているので、今度はこのTXIDの先頭16バイトをHintとしてWatchtowerにチャネル状態を問い合わせ、対応するBlobを取得し、TXIDの後半16バイトを使ってそのBlobを復号する。基本的にEltooであれば最新のコミットメントTxが復元できればいいので、復号化したBlobから最新のコミットメントTxを復元できればいい。

Açaiプロトコルの前提条件

  • LNウォレットがWatchtowerとデータ交換する機能がWatchtower側に実装されていること。
  • Watchtowerにはサービスのための追加のストレージや帯域幅を考慮し、経済的に実行可能なトラストレスは支払いの形態が必要であること。
  • Watchtowerに保存されるAçaiデータは削除されたり、置換/改竄されることが無いこと。
  • Açaiプロトコルを使用するユーザーはどのWatchtowerを使用したか分かっていること。

所感

既存のWatchtowerの監視とJustice Txの保持の仕組みと上手く連携して、鍵導出の仕組みを組み合わせた興味深いバックアッププロトコル。まだインセンティブやデータの保持期間など課題はまだあるけど。ちなみにAçaiは植物のアサイーからの名付けとのこと。

*1:txidçと書いてるけどバックアップに用いるtxidçの実体はトランザクションの識別子ではなく、これから計算する公開鍵を使った識別子でしかない

高速で秘匿性の高いスマートコントラクトをサポートするZkVM

Scaling Bitcoin 2019予習シリーズ第5弾は、「ZkVM: zero-knowledge virtual machine for fast confidential smart contracts」。おそらく内容はStellarが開発している↓のZkVMの話だと思われる。

https://github.com/stellar/slingshot/tree/main/zkvm

ZkVMブロックチェーン

ZkVMはTxVMの研究から生まれたゼロ知識仮想マシンで、キーとなる機能はゼロ知識証明を利用したコインやコントラクトの秘匿化だが、その他にもTaprootやUtreexoなど現在Bitcoinの改善案として提案されている新しい技術が導入されている。

ブロックチェーンの構造

ZkVMブロックチェーンの参加ノードはそれぞれがブロックチェーンステートを管理する。このブロックチェーンステートは以下の要素で構成される。

名称 定義
initialheader ブロックチェーンの初期ブロックヘッダー
tipheader 最新のブロックヘッダー
utxos Utreexoで管理するUTXOのルート

そしてブロックヘッダーは以下の要素で構成される。

名称 定義
version ブロックのバージョンで、現在は1
height ブロック高
previd 前のブロックのID
timstamp_ms タイムスタンプ
txroot ブロック内のトランザクションのマークルルート
utxoroot Utreexoのルート
ext 将来の拡張用でversion 1では空

既存のネットワークに参加する場合は、公開されている初期ブロックとブロックの履歴を入手しチェーンを同期する。新しいネットワークを作る場合は自分で任意のtimstamp_msutxosをセットして初期ブロックを作成するみたい。

各ノードは新しいブロックを受け取ると、ローカルに保持しているブロックチェーンステートを更新する。

トランザクション

ZkVMブロックチェーンはUTXOモデルのブロックチェーンで、トランザクションのインプットが前のトランザクションのアウトプットを参照し、そのコインを新しいトランザクションアウトプットへ移動させる仕組みはBitcoinと同様。

f:id:techmedia-think:20190906150918p:plain
UTXOモデルのトランザクション

各インプットは前のトランザクションアウトプットを参照する識別子を持ち、暗号署名でそのコインをアンロックする。各アウトプットはコインの新しい宛先。トランザクションの各アウトプットはコントラクトを持ち、コントラクトには値もしくはデータパラメータである任意の数のアイテムが含まれ、Predicateによって保護される。Predicateはこのアウトプットの資産をアンロックするために満たす必要がある条件で、公開鍵やサブプログラムで構成される。

トランザクションは一意のトランザクションIDを生成するのに必要なデータとロジックを含む以下の要素で構成される。

名称 定義
Version バージョン
Time bounds 最小時間と最大時間の範囲を表す時間制限
Program ZkVMの命令シーケンスを表す可変長のバイト配列で、スタックベースのZkVMで実行されるプログラム。
Signature 64バイトの署名
Proof VM実行中にConstraint systemを満たす証明で、可変長の点の配列とスカラー

表から分かるように、実はBitcoinトランザクションのように明示的にインプットやアウトプットをセットするフィールドは存在しない。ZkVMにはinput命令やoutput命令があり、インプットとアウトプットの組み立てもProgram内の命令コードとデータを使って行うようになっている。

ZkVMの実行

ZkVMはトランザクションを検証するためのスタックマシンで、トランザクションのプログラムを実行し、そのトランザクションの有効性を検証し、ブロックチェンステートの更新リストを計算するようになっている。

f:id:techmedia-think:20190906165557p:plain
ZkVMの処理フロー

上述したように、インプットおよびアウトプットの指定もこのProgram内で行われる。例えば、ZkVMがProgramを実行し、その中にinput命令があれば、スタックからUTXOを識別するprevoutをpopし、そのprevoutに対応するコントラクトを構築しスタックにプッシュし、トランザクションログにインプットエントリーを追加する。output命令があれば、スタックからPredicateおよびアイテムをpopしContractを作成し、アウトプットエントリーをトランザクションログに追加する。このようにして消費したUTXOと新しいアウトプットの情報はトランザクションの実行結果としてトランザクションアウトプットに記録される。そして最終的にトランザクションログを使ってブロックチェーンステートを更新する仕組みになっている。トランザクションの検証とトランザクションログによるブロックチェーンステートの更新を分離することで並列性を高めるみたい。

秘匿性

↑のZkVMはには、Program、スタック、トランザクションログ以外に、もう1つConstraint systemと呼ばれるものが含まれている。

ZkVMはゼロ知識証明システムの一種であるBulletproofs上に構築されている。コインの量を示す値やデータはデフォルトで暗号化され、Pedersen commitmentとして表現される。

f:id:techmedia-think:20190906184413p:plain
Constraint System

Programの実行中にさまざまな命令がConstraint systemに制約を追加し、VMがProgramの実行を完全に終えると、Bulletproofsプロトコルトランザクション内に格納された証明の文字列を使ってConstraint systemを検証する。トランザクションにセットする証明を作成するには、トランザクション作成者が最初にVMを証明モードで実行する。するとトランザクションのProgramは検証モードと同じ制約を作成するが、証明をチェックする代わりにConstraint systemを使って証明を生成するようになってるみたい。(この辺のBulletproofsを使った証明の仕組みはもっと掘り下げて別の記事で書きたい。)

Taprootの利用

トランザクションアウトプットに定義されるPredicateは公開鍵やサブプログラムで構成されると書いたが、この時Taprootのコミットメントスキームが利用される。コントラクトのアンロック条件をMASTで構成し、その条件セットをTaprootのスキームを利用して公開鍵にエンコードする。Taprootを利用することでロック時に全てのコントラクトロジックをが明らかになることを回避する。また、コントラクトの全参加者が協力する場合、アウトプットをアンロックする際にコントラクトの条件を公開することもない。

具体的なTaprootの仕組みについては以前書いた↓を参照。

techmedia-think.hatenablog.com

Utreexoを利用したUTXOセットの管理

ZkVMブロックチェーンは、UTXOセットの管理にUtreexoを使用する。現在のBitcoinはUTXOセットの全データをKVSで管理し、その容量は3〜4GBほどになるが、ZkVMブロックチェーンではUTXOセットをUtreexoというハッシュベースのアキュムレータを使って管理する。UtreexoではUTXOのセットで複数のマークルツリーを構成し、そのマークルルートのみを保存するため、UTXOセットの容量は数KBまで圧縮される。Uteexoの具体的な仕組みについては、以前書いた↓を参照。

techmedia-think.hatenablog.com

フルノードのストレージ負担を削減しつつIBDの支援を可能にするSecure Fountain Architecture(SeF)

Scaling Bitcoin 2019予習シリーズ第4弾は、カリフォルニア大学の「SeF: A Secure Fountain Architecture for Slashing Storage Costs of Blockchains」。ホワイトペーパーは↓

https://arxiv.org/pdf/1906.12140.pdf

ブロックチェーンのフルノードはジェネシスブロックから始まる全てのブロックチェーンのデータをスタンドアロンで検証し、保存する唯一のノードだ。一方ブロックチェーンはチェーンが伸びるに連れてデータも成長していく。フルノードの消費リソースとしては署名検証のためのCPUリソース、ネットワーク帯域、ストレージ容量などがあるが、今回フォーカスするのはこの内のストレージコストについて。現在Bitcoinブロックチェーンのデータは全体で215GBを超え、そのうちUTXOセットは3〜4GBになる。そしてブロックチェーンのデータは今後も線形増加していく。

このストレージコストを削減する方法として、現在とれる方法は以下の2つ。

  • 軽量ノード
    SPVノードとも呼ばれるが、ブロックチェーンのデータはダウンロードせずブロックヘッダーのみをダウンロードするタイプのノードで、信頼できるフルノードとの接続が必要になる。ダウンロードするデータ量が限定的であるため、スマートフォンやIoTデバイスなどの軽量デバイスでも動作する。トランザクションの有効性を個別検証することはできなかったり、フルノードに対するプライバシーの課題が残る。
  • プルーニングモード
    プルーニングモードはフルノードの動作モード1つで、フルノードと同様ジェネシスブロックから最新のブロックまで全てのブロックをスタンドアロンで検証する。ただ検証し終わった後の古いブロックは削除していくことで、消費ストレージを削減する。

(単純にブロックチェーンのデータの正しさの検証であればプルーニングモードでも可能だが)上記の2つの方法ではストレージコストを削減することはできても、Bitcoinネットワークに新たなノードが参加してきた際に、そのノードにジェネシスブロックから最新のブロックまで配信することはできない。そして、そのようなデータの提供が可能なフルノードの存在は、Bitcoinのような分散ネットワークを維持していくのに重要な役割を果たす。

SeFの提案では、フルノードのストレージコストを削減しつつも、プルーニングモードとは違い新しく参加するノードに対してブロックチェーンの復元をサポートできるような仕組みを提案するもの。

Secure Fountain Architecture

SeFのアプローチは、各ノードはブロックチェーンのデータを符号化し一部だけ保存することでストレージコストを節約する。新しくネットワークに参加したノードは、複数のノードからそれぞれ符号化されたブロックチェーンデータの一部を受け取り、それらを集めてデコードしブロックチェーンのデータを復元する。分散ストレージシステムにおいて、信頼性を低下することなく分散ストレージシステムのストレージコストを大幅に削減する方法として消失符号を利用したりするが、それと同じアプローチっぽい。つまり単一のノードが保持するデータ量は削減し、ネットワーク内の複数のノードからデータを集めることでブートストラップノードがブロックチェーンを復元できるようにする。

ちなみにRippleはHistory Shardingという仕組みで台帳履歴をネットワークで分散管理するようにしている。ただランダムサンプリングを採用しており、新しく参加したノードのブートストラップコストはSeFのアプローチに比べてかなり大きいみたい。

SeFがどのようにブロックをエンコードし、新しい参加ノードがどうやってそれをデコードしブロックチェーンを復元していくかみていこう。

用語

解説にあたって、SeFで扱う用語を整理↓

  • エポック
    ブロックチェーンがkブロック(kは調整パラメータで例えばk = 10000)成長するのに必要な時間の定義で、SeFにおいてブロックを符号化する処理の単位。
  • ドロップレット
    エポック単位にブロックチェーンのオリジナルのブロックをSeFにより符号化した符号化ブロック。
  • ドロップレットノード
    ストレージ制約のあるノードで、バケットノードに対してドロップレットを提供し、新規参加ノードがブロックチェーンを復元するのを支援を行う。
  • バケットノード
    ネットワークに新規参加するノードで、ドロップレットノードと繋いでブロックチェーンを復元する。ブロックチェーンの復元ができたら、ドロップレットノードになれる。

エンコーディング

各ドロップレットノードは、エポック単位でブロックチェーンがkブロック成長したら、そのk個のブロックをs個(例えばs = 10)のドロップレットに符号化する。

SeFでは噴水符号と呼ばれる消失符号をベースにしてブロックをドロップレットにエンコードする。ドロップレットから元のブロックを復号する場合は、元のブロックの数より僅かに多い数分ドロップレットを収集し、そのドロップレットをデコードすることでブロックの復元ができる。

SeFでは基礎的な噴水符号であるLT(Luby Transform)符号を使用し、以下の手順でk個ブロックからs個のドロップレットに符号化する。

f:id:techmedia-think:20190826094722p:plain
SeFエンコード処理

  1. 最初にランダムに1〜kの範囲内の数値を選択する。この数値をdとする。
  2. エポックで取り扱うk個のブロックの中からランダムにd個のブロックを選択する。
  3. 選択したd個のブロックについてビット単位のXORを取り、その結果をドロップレットとする。ドロップレットの計算に使われたd個のブロックのことをそのドロップレットに対するネイバーと呼ぶ。
  4. 続いて長さkのバイナリベクトルを生成し、m番目のブロックがこのドロップレットの計算に含まれている場合は1、そうでない場合は0をセットする。これがドロップレットに対するd個のブロックのインデックス情報となる。
  5. 4で計算したインデックス情報と一緒に3のドロップレットを保存する。

上記、エンコードが済むとs個の符号化されたブロックが生成され、それを保存し、元のブロックは削除し、エンコード処理は次のエポックへ進む。

このようにして符号化するとk個のブロックがs個のドロップレットになるので、ノードが保存するデータのサイズはs/kに削減できる。例えば k = 10,000でs = 10であれば、データサイズは1/1000になる。Bitcoinの場合、現在の215GBのデータが215MBになる。

reorgへの対応

reorgが発生するとブロックチェーンの一部のブロックが変わる可能性があるため、直近τブロック(例えばτ=550)のブロックはドロップレットにエンコードから除外され、そのまま保存する。

デコーディング

新たにネットワークに参加するバケットノードは、最初に十分な数のn個のドロップレットノードに接続し、 {1 ≦ l ≦ e}個のドロップレットを収集する( e = (t - τ) / kで、tは現在のブロック高)。またまだ符号化されていないブロックを入手するため、1つもしくはそれ以上のドロップレットノードからτ個分のブロックを別途ダウンロードする。

バケットノードはまず最初に最長チェーンのブロックヘッダーをダウンロードしておく(ドロップレットノードもブロックヘッダーは全て保持している)。続いて、各ドロップレットノードから収集したドロップレットを使って、以下の手順でブロックチェーンを復元する。

f:id:techmedia-think:20190826111647p:plain
2部グラフの例:k = 6、ns = 9 ドロップレットの初期2部グラフ

  1. k個のオリジナルのブロックと、収集したドロップレットを使って2部グラフを形成する。各ドロップレットは何番目のブロックがそのドロップレットの生成に関与したか示すインデックスを持っているので、各ドロップレットからブロックに対して接続するエッジがある。
  2. 2部グラフの中からブロックとドロップレットノードの接続が1つだけのブロックを見つける。このようなドロップレットをシングルトンと呼ぶ(↑の図では {C_4}がシングルトン)。
  3. 見つかったシングルトンのヘッダー*1が、最初にダウンロードしているブロックヘッダーと一致するか検証する。またシングルトンのペイロード(ヘッダーより後ろのデータ)からトランザクションのマークルツリーを構築し、そのルートがブロックヘッダーのマークルルートと一致するか検証する。
    • これが一致する場合、このドロップレットは対象のブロックをデコードできたことになる。
    • 一致しない場合、このドロップレットは濁っているのでこのドロップレットを2部グラフから削除する。
  4. 上記のグラフで言うと {C_4}により {B_3}がデコードされたので、 {B_3}と繋がっている他のドロップレット( {C_1, C_2, C_6, C_8})に対して、 {B_3}とbit単位のXORを取り各ドロップレットを更新する。そして、 {B_3}との接続を削除し、2部グラフを更新する。
  5. 全てのブロックがデコードされるまで、2〜4を繰り返す。

上記のようにデコード済みのブロックのデータを各ドロップレットから除去するということを繰り返すことで、新たなシングルトンができそれによりブロックがデコードできるというプロセスを繰り返すことになる。

ちなみに収集したドロップレットに、シングルトンが存在しない場合、ノードは追加のドロップレットノードに接続し、シングルトンが見つかるまでドロップレットを収集する。

上記のデコードを繰り返すことで、ネットワークに新しく参加したノードは、ストレージ制約のあるノードから収集したドロップレットを使ってブロックチェーンのデータを復元できる。

悪意あるノードによるドロップレットの細工

中には悪意のあるノードがいて、正しくないドロップノードを提供するパターンも考えられる。SeFでは単純なLT符号に加えて、上記のデコード処理でシングルトンのヘッダーおよびペイロードと予めダウンロードされた正しいブロックヘッダーの値を比較することで、このような汚れたドロップレットを区別し、処理するように設計されている。

所感

以上が全ブロックチェーンのデータを保持せずストレージ負担を削減しながらも、他の新規参入ノードのブロックチェーンIBDを支援できるノード実装の提案。

  • ネットワークを維持するためには今のところ(既存の軽量クライアントやプルーニングノードでは提供できない)IBDを支援できるノードの存在は重要。
  • 今までそれは全てのデータを保持するフルノードしか無かったので、ネットワークを分散ストレージとみなして、データを再構成するアプローチも興味深い(XOR演算ベースのLT符号とか他にもいろいろ利用できそう)。

*1:(ドロップレットは複数のブロックをXORしたものなので、先頭80バイトはブロックヘッダー)

複数のPayment Channelのアトミックな更新を可能にする「Atomic Multi-Channel Update」

Scaling Bitcoin 2019予習シリーズ第三弾は、「Atomic Multi-Channel Updates with Constant Collateral in Bitcoin-Compatible Payment-Channel Networks」。ホワイトペーパーは↓

https://eprint.iacr.org/2019/583.pdf

著者の1人のPedro Moreno-Sanchezは、Scaling Bitcoin 2018でもMulti-Hop Locksの発表しており、Payment Channel Networkの興味深い新しい提案をよく発表している人物。

Payment Channel Networkの課題

Lightning Networkでも採用されている現在のPayment Channel Networkでは、支払いがアトミックに行われることを担保するため、2フェーズコミット型のプロトコルが採用されている。ここでいう2フェーズコミット型のプロトコルというのは、

  1. 最初に送信者から受信者への支払い経路の各チャネルで支払いの金額がロックされ
  2. 次に受信者から送信者への経路の順にシークレットの値を明らかにし支払いを受け入れる

プロセスが処理されるプロトコルで、必ず経路順に処理が進む。

このPayment Channel Networkには以下の2つの課題がある。

経路制限

現在のPayment Channel Networkでは送信者から受信者までPayment Channelが繋がっている送金経路を確保し、さらにその経路の方向に各チャネルが送金額分送金できるだけの十分なキャパシティがないと送金はできない。

担保

Payment Channel Networkを利用した支払いを行う場合、経路内のチャネルの数をn個、支払うコインの量をαとすると、支払いを実行する際少なくともn × αのコインをロックすることになる。支払いが完了するまで、コインはロックされ、ロックされているコインは他の支払いに使うことはできない。そのため、コインがロックされている時間というのは重要だ。

支払いは通常数秒で終わるのでロック期間も数秒であまり意識することはないが、支払いの際に応答不能になるなどオンチェーン上での紛争解決が必要になった場合、n × αのコインがn × △時間(△はオンチェーン上でのトランザクションの承認時間)ロックされることになる。この支払いの経路に沿ってロックされるコインを担保と表現する。

攻撃者にとってはコインを盗めるようなメリットは無いが、単なる嫌がらせとしてチャネル上のコインをロックする攻撃は実際に考えられる。攻撃者が送信者、受信者となり十分に長い経路の支払いを行い、受信者が2フェーズコミットの②を可能な限り遅らせることで、攻撃者自体はαコインロックするだけで、経路上のコインn × αのコインをスタックさせることができる。チャネル全体で見た場合、担保は支払いの経路が長いほど大きくなる。

Atomic Multi-Channel Update(AMCU)の提案

Atomic Multi-Channel Update(AMCU)では、経路の関係性がない複数のPayment Channelの状態をアトミックに更新することで、上記の経路制限を緩和し、支払いに伴う担保を経路の長さに関係なく一定となるよう削減する。

Atomic Multi-Channel Update プロトコル

既存のPayment Channel Networkのアトミック性

Payment Channel Networkを利用したマルチホップ決済の重要な特性はアトミック性で、経路内の全てのペイメントチャネルの残高が更新されるか(支払いが行われるか)、されないか(支払いが行われないか)だ。

Lightning Networkなどで採用されている現在のPayment Channel NetworkはHTLCを使って、このアトミック性を担保している。ペイメントチャネルを持つ2人のユーザー(アリスとボブ)は、

  • アリスはy=H(R)となるRが提供されるとxコインボブに支払う(Hはハッシュ関数、つまりyのプリイメージが分かればコインを支払う)。
  • タイムアウト時刻tを経過すると、アリスはロックしたxコインを取り戻す。

という内容のコントラクトにコインをロックする。

Payment Channel Networkの支払い経路内の各チャネルのユーザーは、同じyを使ってそれぞれのチャネルでコントラクトを形成し(2フェーズコミットのフェーズ1)、受信者がRを公開してコインを受け取りチャネルを更新する(2フェーズコミットのフェーズ2)。もし、タイムアウト時刻になってもRが公開されない場合は、チャネルを元の残高に更新する(この時相手が応答しない場合はトランザクションをブロードキャストしチェーン上で紛争解決する)。

AMCU プロトコル

AMCUプロトコルは、プロトコルの参加者が以下の4つのフェーズを実行する。これらのフェーズは全てオフチェーンで実行される。

また、AMCUではプロトコルの参加者は他の参加者を認識し、認証された機密メッセージを送信してプロトコルを進める(参加者間でTLSチャネルを確立して使用する)。さらに参加者の内、プロトコルフェーズの調整を支援するコーディネーターを参加者間で1人決める。決め方のルールは強制されないが、参加者のアドレスのリストを辞書順にソートして最初のユーザーをコーディネーターとするなどで簡単に決められる。このコーディネータはネットワーク内のメッセージ数を減らす役割を果たす(その他のセキュリティやプライバシー上の利点などは無い)。

各フェーズにおいて全参加者がコーディネーターにOKの返信をすると次のフェーズに進む。

具体的にAMCUのプロトコルにおける支払いの4フェーズ(セットアップ、ロック、消費、ファイナライズ)について説明する。AMCUでは支払いのアトミック性をHTLCとは別の方法で担保しており、そのコアとなる機能は3つ目の消費フェーズにある。

セットアップ

プロトコルに参加する参加者の各チャネルで利用可能なコインをロックする。ここでチャネル内の残高が必要以上にロックされると、担保が不必要に増大することにもなるので、ペイメントチャネルの残高を2つに分割し、2つのサブチャネルを作る。

  • 1つは、AMCUのプロトコルセッションで必要な量のコイン
  • もう1つは、残りのコインで自由に使用可能

A→B→C→D→Eの経路でAからEに5コイン送金する例で考える(AMCUの場合、経路は関係ないが経路にした場合も、担保が経路の長さによって大きくなることはなく一定になるので、担保を小さく保つという意味ではメリットがある)。この時、それぞれの中間者への手数料を1コインとする。つまりB, C, Dに手数料1コインずつ払うのでAが支払うコインは合計8コイン。

チャネルを開いているAとBは、AMCUセッションで使用するコインと残りのコインにアウトプットを分割する {Tx^{A}_{setup}}トランザクションを作成し、お互いに署名する。これを他のチャネルのユーザーも並行して進める。すると以下のような状態になる。

セットアップフェーズ実行後

※ ユーザー間の数字はチャネルの総キャパシティで、初期状態は左側のユーザーが全残高を持っている状態とする。

セットアップフェーズが終わるとAMCUの送金に必要な額のアウトプットがそれぞれ分離できた状態(サブチャネルができた状態)になる。

ロック

AとBはセットアップフェーズで作成した {Tx^{A}_{setup}}のAMCU用のアウトプットをインプットとし、それをそのまま両者宛(AとBのマルチシグ)に送金するトランザクション {Tx^{A}_{lock}}を作成し、署名する。このトランザクションにはタイムロック {T_{△}}が設定されており、 {T_{△}}経過するまで、ブロックチェーンには追加できない。

これを他のユーザーも並行して進めると、ロックフェーズが終了すると以下のトランザクションをそれぞれ持つようになる。

ロックフェーズ実行後

このロックフェーズが実行されることで、参加者の誰かが将来のフェーズの進行を邪魔しても、 {T_{△}}経過したら、各チャネルはフォールバック可能になる。

消費フェーズ

消費フェーズで実際にコインを送金するが、この時重要になるのがアトミック性で、AMCUの参加者全てがそれぞれの受信者にコインを送金する状態か、全員が送金しない状態かのいずれかになることが担保される必要がある。

AとBはAからBにコインを送金するための {Tx^{A}_{consume}}トランザクションを協力して作成する。このトランザクションのインプットは以下の2つ。

  •  {Tx_{enable}}トランザクションのアウトプットの1つでAとBのマルチシグにロックされた7.99コイン
  •  {Tx_{enable}}トランザクションのアウトプットの1つでAとBのフレッシュアドレスにロックされた0.01コイン

アウトプットはB宛に8コイン送る単一のアウトプット。このトランザクションの作成を他のユーザーも並行して進めると、消費フェーズが完了すると、それぞれ以下のトランザクションを持つようになる。

消費フェーズ実行後

ここで、 {Tx_{enable}}はまだ作られていないトランザクションだ。そのため、このトランザクションをこの時点でブロードキャストしてもブロックチェーンに格納されることはない。この {Tx_{consume}} {Tx_{enable}}にアトミック性を担保する仕組みがある。

ファイナライズ

消費フェーズで全チャネルの消費トランザクションが作られたら、最後に {Tx_{enable}} {Tx_{disable}}を作成する。

まず {Tx_{enable}}トランザクションは、各チャネル毎に作られた {Tx_{setup}}のアウトプットをすべて集めてインプットとし、 {Tx_{consume}}のインプットとなる各チャネルごとに2つずつのアウトプットを持つ1つのトランザクションで、以下のようなトランザクションになる。

ファイナライズフェーズ実行後

つまり、各ユーザーが消費フェーズで作成した送金トランザクションは、この1つの {Tx_{enable}}がチェーン上にあらわれて初めて有効になる。この方法により、直接的な関連のない複数のPayment Channelの更新のアトミック性を担保する。

ただ、このままだと {T_{△}}経過したら {Tx_{setup}}を参照する2つの有効かつ矛盾する内容の {Tx_{lock}} {Tx_{enable}}が有効になってしまう。このため、 {T_{△}}経過したら {Tx_{enable}}を無効化する {Tx_{disable}}を実際は {Tx_{enable}}より先に作成しタイムアウト {T_{△}}を設定して署名しておく。

残高の更新

上記ファイナライズフェーズまで終えると、各ユーザーはやろうと思えばオンチェーン上で {Tx_{setup}} ->  {Tx_{enable}} ->  {Tx_{consume}}を公開することで、送金の紛争解決ができる。

通常はオフチェーン決済を続けると思われるので、チャネルの残高を更新したコミットメントTxを作成し、合意すればAMCUプロトコルは終了する。

所感

経路とHTLCを使わずどうやってアトミックに複数のチャネルを更新するのかと思ったけど、なるほど確かにこういう構成を取ればアトミックにできそうで面白い。これは単純に既存のLNの担保を小さくするだけでなく、チャネルの残高の調整や、ペーパーにも書いてあるとおりクラウドファウンディング(募集額集まったら支払いし、集まらななかったら集金しない)のようなケースにも対応できそうで興味深い。

個人的には以下の点が疑問。

  • 消費フェーズでアウトプット2つ分けてフレッシュアドレスを必要とする理由がイマイチ分かっていない。これ1つじゃダメなのか?
  •  {Tx_{consume}}には両者が署名するには、その後のフェーズで作られる {Tx_{enable}}トランザクション識別子とインデックス情報が必要になるが、この計算方法はどうする?もしくは、まだBitcoinでは導入されてないけど、bip-anyprevoutとかが導入されるとOutPointは空のまま署名できるから、そういう意図なのか?その場合別のOutPoinに切り替えられないよう、アウトプットを2つに分割し、フレッシュアドレスを導入してる?

それにしても、Payment Channelまだまだ奥が深いなー。

ブラインドマージマーニング(BMM)の仕様を定義したBIP-301

ブラインドマージマーニング(BMM)の仕様がBIP-301として定義された↓

https://github.com/bitcoin/bips/blob/master/bip-0301.mediawiki

マージマイニングの仕組みについては、以下の記事が分かりやすい。

btcnews.jp

このBIPでは、サイドチェーンのマイナー(ブロックの候補を作る人、Simon)がメインチェーンのマイナーにどのようにサイドチェーンのブロックのマイニングリクエストを出すかと、↑の記事の最後に挙げられていた賄賂(報酬)をやりとりする方法について定義されている。

簡単に内容をまとめると、サイドチェーンのフルノード運営者(Simonと呼ぶ)はサイドチェーン上で新しいブロックの候補を作成し、そのブロックに対するブラインドマージマイニングのリクエスト(BMMリクエスト)をメインチェーンのマイナーに投げる。このBMMリクエストを投げる方法はオンチェーン/オフチェーンの2種類の方法がある。いずれの方法でも、サイドチェーンのマイニング情報が含まれるCritical Dataと呼ばれるデータ構造をメインチェーンのマイナーに渡し、メインチェーンのマイナーはブロックをマイニングする際に、そのデータへのコミットメントをコインベーストランザクションのアウトプットに挿入することで、マージマイニングを行う(BMM Accept)。

オンチェーンBMMリクエス

BMMリクエストをオンチェーントランザクションとして投げる方法。

このトランザクションはSegwitで導入された拡張シリアライゼーションフォーマットを使用して、Critical Dataをセットするトランザクションになる。Segwitトランザクションは署名をトランザクションのアウトプットの後にwitnessと呼ばれるデータ領域を設けてそこに移動するような拡張フォーマットを導入した。この時flagフィールドも導入され、flag = 1がSegwitトランザクションとされた。今回のBMMリクエストランザクションはflag = 2が使われ、この場合、アウトプットの後にCritical Dataがセットされる領域が確保されるようになる。

そしてこのトランザクションのアウトプット自体がマイナーにより回収可能なマージマイニングの報酬となるようだ。具体的にどのようなアウトプットスクリプトになるかはBIPには書かれてないが、参照実装を見る限り、anyone can spendなアウトプットになるっぽい。

このリクエストはあるサイドチェーンの特定のブロックかつメインチェーンのブロックを指定したCritical Dataが含まれるトランザクションになるので、対象のブロックに取り込まれなければ無効になる。

オフチェーンBMMリクエス

オンチェーンではなくオフチェーンでBMMリクエストを投げる場合は、Lightinng Networkを利用する。この場合サイドチェーンのマイナー(Simon)とメインチェーンのマイナー(Mary)はSimon→Maryへ報酬を支払うためのLNの経路を持っておく必要がある。Critical Dataの内容も少し異なる。LNのCommitment Transactionのアウトプットに以下のアウトプットを追加することで、オフチェーンBMMリクエストの機能をチャネルに追加する。

  • Critical Dataの要件に合うブロックが作成されればメインチェーンのマイナー(Mary)へ報酬を支払い、対象のブロックが作られなければタイムロック後サイドチェーンのマイナー(Simon)が資金を取り戻す

ただこれどういうスクリプトを構成するのか気になる(BIPには記載されてない)。

仕様以外で気になったのはデプロイに関して、BIP-9を使ったデプロイの日時が2020年01月15日開始と明記されている。Segwit以降ちゃんと日時が設定されたソフトフォークは初めてじゃないだろうか?ただ、現状まだtestnetへのデプロイもされていないし、Bitcoin Coreにマージもされていないので、計画通りにデプロイされるのかは不明。

CriticalDataや、拡張トランザクションフォーマット、コインベースに挿入するBMM Acceptのデータ構造などプロトコルの詳細についてはBIPの内容を参照。以下、BIPの意訳↓

概要

ブラインドマージマイニング(BMM)はオプションで(非対称サイドチェーンなどの)extension blockをマイニングする方法だ。BMMは任意のルールセットに対して、ブロックが有効であるという弱い保証を生成し、かつマイナーに実際にその任意の検証を行わせることなく実行される。

BMMは実際には2つ以上のチェーンにまたがるプロセスだ。ここではメインチェーンであるBitcoinへの変更について焦点をあてる。全体像の説明についてはこのポストを参照。

ここでの我々の目標は、メインチェーンのマイナーにサイドチェーンのブロックを見つける行為をトラストレスに「売る」ことができるようにすることだ。

動機

通常の「マージマイニング」(MM)では、マイナーはハッシュ処理を他のチェーンを保護するために再利用できる(Namecoinなど)。ただし、従来のMMには2つの欠点がある。

  1. マイナーは他のチェーンのフルノードを実行しなければならない。(これは彼らがMMするブロックが有効でない限り、自身に対して有効な支払いを作成しないためで、マイナーはまず有効なブロックを作って、次にそれをマージマイニングしなければならない。)
  2. マイナーへの報酬は通常のBTCメインチェーンではなく、他のチェーンで支払われる。例えばNamecoinをマージマイニングしているマイナーはNMCを稼ぐ(そして、電気料金の支払いのためのBTCを売る前に、BTCのためにNMCを売る必要があるだろう)。

BMMは両方の欠点を解決する。

仕様

※このドキュメントでは、メインチェーンのバージョンと対応するサイドチェーンのバージョンを区別するため、曖昧な単語(blockやnode、chainなど)の前にside:\*main:\*という表記を使用する。またサイドチェーンのフルノードを指すためにSimonを使用し、メインチェーンのマイナーを指すのにMaryを使用する。

BMMリクエス

サイドチェーンのブロックを見つけるための権利を購入するため、ユーザーはBMMリクエストをブロードキャストする。

このリクエストは2種類の形式を取ることができる。1つはLightning Networkを必要としないが、Immediate Expiration(以下参照)のための新しい要件を持つ。2つめの形式は、Lightning Network自体からImmediate Expirationを継承するが、追加の準備と異なるより大きなメッセージを必要とする。

どちらの形式でも、トランザクションが含まれているブロックのコインベース内で特定のCritical Dataをコミットする必要がある(BMM Accept参照)。Lightningではないオンチェーンバージョンについては、新しい拡張シリアライゼーショントランザクションタイプを作成した(segwitがwitness dataをどうハンドリングするかとよく似ている)。

Immediate Expiration ("Fill-or-Kill")

このトランザクションの相手方に対して特別な保証をしたい。具体的には、SimonがMaryに「支払い」をするのではなく、SimonがMaryに「オファー」を提供することを推奨する(Maryはこれを承諾または辞退できる)。

重要なことに、Simonはリアルタイムで(つまり迅速かつオフチェーンで)、複数の異なるMaryに安全に多数のオファーを出したい。ただし、最終的に1つのオファーしか受け入れられないようにする。言い換えると、Simonのオファーを直ちに期限切れにする必要がある。1つのオファーのみが本物のトランザクションになることができれば、Simonは一日中複数のオファーを簡単に作れるだろう。全てのSimonが多数のオファーを作るので、Maryはたくさんのオファーの中を選択するためのアクセスを得る。

オンチェーンBMMリクエス

オンチェーンBMMRはLightning Networkを必要としないが、検証のための新しい要件がある。

構造

以下のデータが必要になる。

32-bytes  - h* sideHeaderHash
?~?-bytes - critical data extended serialization
    3-bytes - 0x00bf00 identifying bytes
    1-byte  - nSidechain
    2-bytes - prevSideBlockRef
    4-bytes - prevMainHeaderBytes

sideHeaderHashは、side:chainから来る(side:nodesがside:blocks/headersをビルドする)。identifying bytesは0x00bf00。nSidechainはどのサイドチェーンをBMMするか識別するもので、BMMが行われる頃には世界的に知られるようになる。

prevBlockRefは少し複雑で次のセクションで説明する。

ブロックに含めるための資格を得るため、BMMリクエストには以下の要件が適用される:

  1. リクエストは対応する「BMM Accept」(後述)と一致しなければならない。
  2. 多くてもmain:blockにはサイドチェーンあたり1つのリクエストしか許可されない。言い換えると、700人がサイドチェーン#4のBMMリクエストをブロードキャストしても、main:minerはブロックに含めるリクエストを1つだけ選択しなければならない。
  3. 4バイトのprevMainHeaderBytesは、前のmain:blockheaderの最後4バイトと一致しなければならない。しがたって、Simonのtxnsはそれが知るブロック履歴の中で(そして現在のサイドチェーンの履歴の中で)、現在のブロックに対してのみ有効となる。
prevBlockRef

prevBlockRefは、現在のside:blockの親ブロックを見つけるためにside:chainで行わなければならない「スキップ」の数を数える整数だ。サイドチェーンが再編成されている場合(もしくは無効なサイドチェーンブロックをスキップしている場合)を除いて、この値はゼロだ。side:nodeが直近Nブロックをオーファンさせたい場合、現在のブロックのこの値はNと等しくなり、その後のブロックでゼロに戻る。

https://github.com/bitcoin/bips/raw/master/bip-0301/bmm-dots-examples.png?raw=true

上記は、(小さい数字で記載されている)最大長、再編成の履歴、prevBlockRefの数が異なる3つのブロックチェーン。各side:blockの「prevSideBlockRef」で与えられる順序付けは、各side:blockの「prevSideHeaderHash」の順序と同型になる(prevSideHeaderHashはサイドチェーンにおけるメインチェーンのprevBlockHashと同等)。一方から他方へ自由に変換できる。

拡張されたシリアライゼーション

トランザクションレベルで新しい要件を課すために、Segwitスタイルのトランザクションからダミーのvinおよびflagトリックを借用する。サイドチェーンのCritical Dataトランザクションの要件の全てが、そのトランザクションが含まれるブロックで満たされない限り、そのトランザクションは無効だ。Segwitにおけるこの追加データはSegwitの署名スタックであり、追加要件は署名の場所と有効性だ。サイドチェーンのBMM Critical Dataトランザクションでは、追加データは(nSidechain, h*) のペアで、上記の最初の2つの要件と上記のmain:blocknumberの3つめの要件を満たす必要がある。

https://github.com/bitcoin/bips/raw/master/bip-0301/witness-vs-critical.png?raw=true

これらのトランザクションタイプは僅かに異なるmempoolの振る舞いをするため、2つめのmempoolに保存する必要がある。これらのtxnsが受信され、すぐにチェックされ、有効であればブロックに入れるかどうかチェックされる。それらが要求した特定のブロックに含まれない場合(要求したブロック高よりチェーンTipの方が長い場合)、それらは破棄される。実際、main:blockが見つかった後は、次のブロック高のための新しい支払いがすぐに作成されるため、2つ目のmempool内のすべては破棄される。(これはブロックチェーンが再編成される場合も同じだ)このようなmempool内のtxnsの再評価はこれまでなく、一度評価されてブロックに含まれるか破棄されるかのどちらかだ。再スキャンする必要はない。

おもしろいことに、これらの支払いは常にnon-main:minersからmain:minersに向けられる。したがって、非マイニングフルノードはそれらをmempoolに保持する必要はまったくない。非マイナーノードは、ブロックが見つかるのを待ってからtxnをチェックするだけだ。これらの取引は株式市場のピットトレードオファーによく似ている(対照的にBitcoinの通常の取引は紙の小切手のようなものだ)。

Lightning BMMリクエス

Lightning BMMRでは、SimonsがMarysとのLNのチャネル経路を開く必要がある。特に今日、これは常に実用的であるとは限らない。

LN txnsはprevSideBlockRefを利用できない。なぜならそれらがいつオンチェーンにブロードキャストされるか誰にも分からないからだ。代わりにprevSideBlockHashを使用しなければならない。それ以外は同じデータを必要とする:

4-bytes - Message header (0xD0520C6E)   
1-byte - sidechain number
32-bytes  - h* side:block hash  
32-bytes  - prevSideBlockHash   

オンチェーンのBMMRでは、main:block毎およびサイドチェーン毎に1つのBMMRだけ含めることができたので、Simonが必要なもの全てで同じh*を再利用できることに注意すること。ただし、LNではそのようなルールを適用できない。目標が、zero txnを含む全てをオフチェーンに入れるためだ。そのため、我々はそのリクエストが何であったのか、或いは何に影響を与えたのか知ることはない。

そのためSimonは、各Maryに異なるh*を与えることを保証しなければならない。Simonはこれをside:blockのブロックの内容を制御し、単純にside:nonceをインクリメントすることで簡単に行える。これはside:blockを変更し、そのハッシュを変更する(つまりh*を変更する)。

Mary毎に(より正確にはチャネル毎に)一意のh*を使用し、(サイドチェーン毎に)最大1 h*をブロックにすることで、Simonは最大1回だけ課金されることを保証できる。

おそらく混乱しているので、ここで例を示す。Simonは13 BTCから始まりMaryは40 BTCから始まる。side:block'のtx-feeは合計で現在7.1 BTCで、Simonは自身で0.1 BTC保持し、Maryに7 BTC支払っている。

まず、開始時点Ⅰでは、

Simon 13 , Mary 40 で合計 53
     [Maryによって署名された]Simonのバージョン
        13 ; TimeLockが経過したらSimonへ、もしくはSimonの署名があればMaryへ
        40 ; をMaryへ
     [Simonによって署名された]Maryのバージョン
        40 ; TimeLockが経過したらMaryへ、もしくはMaryの署名があればSimonへ
        13 ; をSimonへ

続いて両者ともⅡに進む

Simon 13 , Mary 40 で合計 53
    [Maryによって署名された]Simonのバージョン
        6 ; TimeLockが経過したらSimonへ、もしくはSimonの署名があればMaryへ
        40 ; をMaryへ
        7 ; critical dataの要件に合えばMaryへ、そうでなければLongTimeLock後Simonへ
    [Simonによって署名された]Maryのバージョン
        40 ; TimeLockが経過したらMaryへ、もしくはMaryの署名があればSimonへ
        6 ; をSimonへ
        7 ; critical dataの要件に合えばMaryへ、そうでなければLongTimeLock後Simonへ

ここから、問題のh* side:blockがマージマイニングされると、両者はⅢに進む。

Simon 13 , Mary 40 で合計 53
    [Maryによって署名された]Simonのバージョン
        6 ; TimeLockが経過したらSimonへ、もしくはSimonの署名があればMaryへ
        47 ; をMaryへ
    [Simonによって署名された]Maryのバージョン
        47 ; TimeLockが経過したらMaryへ、もしくはMaryの署名があればSimonへ
        6 ; をSimonへ

Simonがすぐに処理するなら、彼はこのside:block上に構築されているブロックを気にするMaryのインセンティブを取り除く。Simonのside:block がオーファンすると彼は7 BTCを失う。Simonはそれを安全に実施でき、先に進む前に(つまり上記ⅢのLN txnに進む前に)100 side:block待つか、問題ないと思えばリスクを冒すこともできる。

h* side:blockが見つからない場合、ⅡとⅢは互いに等価だ。SimonとMaryは協力してⅠを再構築してそこに戻ることもできるし、新しいバージョンのⅡに進むこともできる(異なるh*を使って、次のmain:blockで新しいside:blockを再試行する)。

BMM Accept

main:minerが受け入れる各BMMリクエストに対して、main:minerらはmain:coinbase txnにOP_RETURNアウトプットを入れなければならない。(複数のOP_RETURNを許可するようTxのヒョジュんポリシーを変更)

受け入れ用のOP_RETURNアウトプットには以下のデータが必要になる:

1-byte - OP_RETURN (0x6a)
1-byte - Push the following 36 bytes (0x24)
4-bytes - Message header (0xD3407053)
32-bytes - h*
~5-bytes - BMM identifier bytes

このOP_RETRUNアウトプットがない場合、BMMリクエストは受け入れられていない。(そして受け入れられなければ、 main:blockに含めることは出来ない)

後方互換

このBIPは「blindmm」という名前でbit 4を使ってBIP9の「version bits」を使って展開される。

// Deployment of Drivechains (BIPX, BIPY)
consensus.vDeployments[Consensus::DEPLOYMENT_DRIVECHAINS].bit = 4;
consensus.vDeployments[Consensus::DEPLOYMENT_DRIVECHAINS].nStartTime = 1579072881; // 2020年01月15日
consensus.vDeployments[Consensus::DEPLOYMENT_DRIVECHAINS].nTimeout = 1610695281; // 2021年01月15日

参照実装

https://github.com/DriveNetTESTDRIVE/DriveNet

Bitcoin Coreをフォークしたメインチェーンに必要な変更についてはこちら: https://github.com/drivechain-project/bitcoin/tree/sidechainBMM