用語集 / マイニングとコンセンサス
nBits
別名はCompact targetです。
- nBitsとは?
- nBitsは、すべてのブロックヘッダーにある4バイトのフィールドで、マイニングのターゲットを1バイトの指数と3バイトの係数からなる浮動小数点形式の簡潔な符号化に詰め込んだものです。
ビットコインは、32バイトを割けないヘッダーの中に256ビットのターゲットを持つ必要があるため、丸めた値を4バイトに格納しています。最初の1バイトが指数、残りの3バイトが係数であり、ターゲットは係数に256を(指数から3を引いた数)乗じた値です。すべてのノードが期待する値を再計算するため、ルールが許すより易しいターゲットを主張するヘッダーは即座に拒否されます。
仕組み
nBitsは指数1バイトとそれに続く3バイトの係数として読まれ、両者が組み合わされて256ビットの完全な数値になります。
ジェネシスブロックが持つ値、0x1d00ffffを取り上げます。指数は0x1dで、これは29に相当し、係数は0x00ffffで、これは65,535に相当します。したがってターゲットは、65,535に2を208乗した値を掛けた数であり、16進数のゼロ8個、続いてffff、続いて64桁を埋めるゼロとして書かれます。これがメインネットが許す最も易しいターゲットであり、難易度1の定義です。
人を戸惑わせる癖が2つあります。1つ目は精度です。24ビットしかない係数では任意の256ビットの数値を表せないため、符号化されたターゲットは常に丸められた値になり、ターゲットからnBitsへ変換して元に戻しても、元の値が常に戻るとは限りません。2つ目は符号ビットです。係数の最上位ビットが立っている場合、値は負として扱われるため、符号化する側は係数を1バイト分下へずらし、釣り合いを取るために指数を上げます。ジェネシスの値がより分かりやすい0x1cffff00ではなく0x1d00ffffと読めるのはこのためであり、係数の先頭にゼロバイトがあるのが不具合ではなく正常であるのもこのためです。
シリアル化されたヘッダーでは、このフィールドはバイトオフセット72に位置し、リトルエンディアンで書き込まれるため、その4バイトはディスク上でもネットワーク上でもff ff 00 1dとして現れます。
目にする場所
nBitsはいくつもの異なる名前で流通しており、それを取り巻く混乱の大半はここから来ています。
ブロックエクスプローラーはこれを「bits」と呼び、より分かりやすい難易度の数値の横に16進数の値を表示します。Bitcoin CoreのRPCであるgetblockはこれを「bits」として返し、getblocktemplateは候補ヘッダーが満たさなければならない要件としてマイニングソフトウェアに渡します。ソースコード上ではCBlockHeaderのnBitsメンバーであり、arith_uint256::SetCompactとGetCompactによって変換されます。マイニングプールがこれを表に出すことはほとんどありません。Stratumは同じ4バイトをジョブ通知の中に入れてマシンへ送り、ファームウェアはその意味を考える必要がないからです。
また、このフィールドは継続的にではなく、決まったスケジュールで変わります。2,016ブロックのウィンドウ全体にわたって固定され、難易度調整のときだけ新しい値を取るため、その間に難易度調整が挟まらなければ、1時間差でマイニングされた2つのブロックは同一のnBitsフィールドを持ちます。
nBits vsターゲットしきい値
nBitsは符号化であり、ターゲットしきい値はそれが符号化する数値です。ノードはヘッダーのハッシュをnBitsと直接比較することはありません。まず4バイトを256ビットの完全なターゲットに展開し、その後でハッシュがその値以下であることを確認します。nBitsをターゲットそのものとして扱うのは会話の中では問題ありませんが、コードの中では誤りです。1単位だけ異なる2つのnBitsの値は、絶対量として膨大に異なるターゲットにデコードされるからです。