Develop with pleasure!

福岡でCloudとかBlockchainとか。

マイニングプールのプロトコル

Bitaxeを入手したのをきっかけに↓、プールマイニングにも興味出てきたので、最近のマイニングプールの仕組みについて調べてみた。※ Bitaxe単体でマイニングに成功することは基本的にない。

プールマイニングは、多数のマイナーが協力して新しいブロックを見つけ、見つけたブロックの報酬を分配する仕組み。

シェア

プールマイニングでは実際に有効なブロックが発見できなくても、そのターゲットに近い値のハッシュを持つブロック*1を見つけた場合に、それが有効なシェアとして認められる。マイナーはプールにシェアを提出し、オペレーターはそれを元に各マイナーがどれだけの作業を行っているのかを追跡することができる。

報酬の支払い形態

プールは上記のシェアを元に、その貢献に対して報酬を支払う。報酬の形態として代表的なものが↓

PPS/FPPS(Pay Per Share)*2

たとえば、有効な作業量の10%のシェアを提供した場合は、通常のブロック報酬の10%を支払うといったように、条件を満たしたシェアが提供されればその作業量に応じて、実際にブロックを見つけていなくてもプールが支払いを行う。各マイナーも提出したシェアの数からプールが適切に支払いをしているかを判断できる。

  • ブロック報酬は明示的に分かるけど、手数料についてはほとんどのプールでシェアが作成された日に収集された手数料の平均値を用いることが多いらしい*3。そのため、シェアに対する報酬の計算が翌日になる。
  • 小規模なプールでは、ブロックを見つける機会が少ない中でシェアの報酬を支払う必要があるため、かなりの資本が必要となる。また、わずかなブロック保留攻撃でも収益性のダメージが大きくなり、マイニングの分散化を困難にする。

PPLNS(Pay Per Last N Shares)

実際にプールがブロックを発見した場合に支払われる報酬で、ブロックを見つける直前に見つかったN個のシェアに対してマイナーに報酬を支払う。

  • 1つのブロックに対してN個以上のシェアが提出された場合、直近N個なので、超過分早めに提出したマイナーには報酬は支払われない。ただ、N個見つかる前にブロックを発見した場合、複数回分の報酬を受け取れるのでそれで補間とするっぽい。
  • プールにとっては予め資本を用意する必要がないという利点がある一方、ハッシュレートの変動リスクやブロック保留攻撃に対するリスクは、参加するマイナーに転嫁される。
  • 実際に有効なブロックが見つかった場合、プールがブロックを見つけたことを判断できるのはそのブロックをマイニングしたマイナーのみで、プールが正しく報酬を支払っているか各マイナーが検証する方法が課題。

他にも、いろんな形態がある↓

https://en.bitcoin.it/wiki/Comparison_of_mining_pools

プールプロトコル

これまで提案された代表的なプールプロトコル

getwork

まだ、今のようなハッシュパワーが投入される前の初期のプールプロトコルでは、プールはBitcoin CoreのgetworkRPCで使用されていたテンプレートを各マイナーに送信し、各マイナーは受け取ったテンプレートを元にブロックヘッダーのnonceを変更しながら有効なブロックを見つける作業を行っていた。

このテンプレートに含まれる主なデータは、↓

  • マイニング対象のブロックヘッダー
  • midstate:ブロックヘッダーのハッシュ値を計算する際の中間状態。SHA-256の場合、入力データを64 byte毎に分割してハッシュ値を計算する。入力となる80 byteのブロックヘッダーの内、(nonceのみを変更してハッシュを計算するため)前半64 byteは変更ないので、その部分を処理した結果がこの値。この値を提供することで、各マイナーの計算を1入力分ショートカットできる。
  • 目標となる難易度。この値より小さいハッシュのみが受け入れられる。

ハッシュレートの増加と共に、ブロックヘッダーのnonceフィールドだけでは対象のハッシュを見つけるのが困難になり、プールへのgetworの要求が大量に発生するようになった結果、負荷や消費する帯域幅の増加など、HTTPベースのgetworkでのプールマイニングは現実的ではなくなっていった。

getblocktemplate

代わって、Bitcoin Coreに追加されたのがgetblocktemplate RPC。完全な仕様は、BIP-22BIP-23BIP-9BIP-145でカバーされている。

getblocktemplateでは、ブロックに格納するトランザクションのリストなど、getworkに比べて多くの情報をテンプレートとして返すようになっており、マイナーが独自のブロックを構築することが可能。ただ↓のStratum v1と同時期にリリースされたため、プールプロトコルとしては広く採用されることはなく、プールサーバーのバックグラウンドで、マイニングするのに適切なトランザクションのセットをBitcoin Coreから取得するのに使われている。

Stratum v1

getworkの代わりに、ASICマイナーの登場に備えて広く採用されたのが、2012年に発表されたSlush Poolが開発したStratum v1プロトコル*4。現在主流のプールプロトコルで、Bitaxeもこのプロトコルを使っててデフォルトでソロマイニング用のPublic Poolに接続するようになってる。

getblocktemplateと違って、各マイナーがブロックヘッダーを構築するために必要な最低限の情報のみを提供する↓

  • 前のブロックのハッシュ
  • コインベーストランザクションを構築するのに必要なトランザクションデータ
  • マークルブランチのリスト
    マイナーがコインベーストランザクションを作成したら、そこからマークルルートを計算するために必要なマークルツリーの兄弟ノードのハッシュリスト
  • ブロックのバージョン
  • ブロックの難易度
  • ブロックのタイムスタンプ

getworkと違ってコインベーストランザクションにextra nonce*5を各マイナーがセットできるようになる。↑を受け取った各マイナーは、プールと合意したサイズのextra nonceを試行してコインベーストランザクションを構成し、それを元にマークルルートを計算し、ブロックヘッダーを完成させる。

また、マイング機器とプールサーバー間はTCPベースのSocket通信によりネットワーク負荷を抑えるようになっている。ただ機器とサーバー間の通信は平文であるため、中間者攻撃に対してリスクがある。有名なのは、ハッシュレートハイジャックと呼ばれる攻撃で↓

  1. マイナーとプールサーバー間の通信を盗聴する攻撃者がマイナーのログイン資格情報を自分のものに置き換え、
  2. マイナーが有効なシェアをプールに送る際に、そのシェアを奪い、
  3. プールからの報酬は攻撃者が横取りし、
  4. マイナーにはリジェクトされた通知送信する

という攻撃が可能になる。

BetterHash

その後、プールの各マイナーが独自のトランザクションセットを選択できるようにしたプロトコルBetterHashが提案される。セキュリティ面の改善や、複数のマイニング機器での作業の効率的な分散の改善など残っていたものの、開発はStratum v2に置き換えられていったみたい。

Stratum v2

Stratum v2は、v1とは全く異なるプロトコルで仕様はGithubリポジトリに掲載されていて、v1と比べて仕様が詳細に定義されて文書化されている。採用するプールも徐々に増えてる。

v2では、以下の5つのロールを定義している:

  • マイナー(マイニング機器)
  • マイニングプール
  • プロキシ
    マイナーとプールの間プロキシサーバー。v1では正式に仕様化されておらず、クローズドな実装が使用されてることが多いみたい。
  • テンプレートプロバイダー
    ブロックテンプレートを提供する。マイナーとプールどちらでも担当でき、マイナーが担当する場合、マイナーがカスタムブロックテンプレートを作成することができる。
  • ジョブディクレーター
    テンプレートプロバイダーから受け取ったテンプレートを元に、マイングジョブを生成、配布する。

後者の2つのロールを担当するエンティティにより、プール以外がブロックテンプレートを作れるようにしてる。

他にも以下のような改善が行われている↓

バイナリプロトコル

v1ではマイナーとプール間でやりとりされるデータ形式が人が読みやすいJSON形式になっている。ただ、ASICマイナーでは、これをバイトコードシリアライズ/デシリアライズする必要ががあり、時間と計算リソース、帯域幅が浪費される。

v2では、このデータ形式がマシンリーダブルなバイナリプロトコルとなり、↑の浪費がなくなる。

認証付き暗号のサポート

マイナーとプール間の接続で認証付き暗号(AEAD)が使われ、↑の中間者攻撃リスクを排除する。

BraidPool

↑のプールプロトコルが集中型のマイングプールを構成するのに対し、BraidPoolは分散型のマイニングプールを構成するプロトコル*6で、以下のような特徴がある。

  • マイナー*7は、マイナー用のP2Pネットワークに参加する。
  • 参加するマイナーは、それぞれBitcoinのフルノードを実行し、自分でブロックテンプレートを作成する必要がある。
  • 参加するマイナーは、コインベースの報酬をt-of-nのマルチシグを使って共同で管理し、各マイナーの貢献度に応じて2016ブロック毎に支払いを行う。
    • 参加者が多くなるとマルチシグが肥大化したり上限が発生するけど、Taproot(Schnorr署名)の導入により可能になった閾値署名プロトコル(FROST)を利用することで、この問題を解決しようとしてる。
  • マイニングで発見されたシェアで、有向非巡回グラフ(DAG)を形成し、各マイナーの作業を追跡し、報酬を計算するのに使用する。

コンセプトは面白そう。

*1:weak blockとも呼ばれる

*2:PPSは手数料が含まれず、手数料分はプールが徴収する。FPPSは手数料額も報酬に含める

*3:また、プール毎に手数料の計算に微調整がある

*4:Stratum v1用にBIP-40とBIP-41の番号が割り当てられたけど実際のBIPドキュメントは作成されていない。またコミュニティがgetblocktemplateを開発する中、クローズドな形で開発が進められ批判が集まった

*5:インプットのscriptSigにセットされる

*6:分散型のプールと言うと、P2Poolというのがあったけど、その問題点を改善する代替プロトコル

*7:BraidPoolではHasherと呼んでるみたい