ブラインドマージマーニング(BMM)の仕様がBIP-301として定義された↓
https://github.com/bitcoin/bips/blob/master/bip-0301.mediawiki
マージマイニングの仕組みについては、以下の記事が分かりやすい。
この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つの欠点がある。
- マイナーは他のチェーンのフルノードを実行しなければならない。(これは彼らがMMするブロックが有効でない限り、自身に対して有効な支払いを作成しないためで、マイナーはまず有効なブロックを作って、次にそれをマージマイニングしなければならない。)
- マイナーへの報酬は通常の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リクエストには以下の要件が適用される:
- リクエストは対応する「BMM Accept」(後述)と一致しなければならない。
- 多くてもmain:blockにはサイドチェーンあたり1つのリクエストしか許可されない。言い換えると、700人がサイドチェーン#4のBMMリクエストをブロードキャストしても、main:minerはブロックに含めるリクエストを1つだけ選択しなければならない。
- 4バイトのprevMainHeaderBytesは、前のmain:blockheaderの最後4バイトと一致しなければならない。しがたって、Simonのtxnsはそれが知るブロック履歴の中で(そして現在のサイドチェーンの履歴の中で)、現在のブロックに対してのみ有効となる。
prevBlockRef
prevBlockRefは、現在のside:blockの親ブロックを見つけるためにside:chainで行わなければならない「スキップ」の数を数える整数だ。サイドチェーンが再編成されている場合(もしくは無効なサイドチェーンブロックをスキップしている場合)を除いて、この値はゼロだ。side:nodeが直近Nブロックをオーファンさせたい場合、現在のブロックのこの値はNと等しくなり、その後のブロックでゼロに戻る。
上記は、(小さい数字で記載されている)最大長、再編成の履歴、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つめの要件を満たす必要がある。
これらのトランザクションタイプは僅かに異なる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