2016.07.07 (Thu) guides
誰でもわかるビットコイン半減期の仕組み 〜 非エンジニアでも読めるソースコードで解説
ご無沙汰しております。ビットバンク株式会社技術顧問 兼 ブロックチェーン大学校講師のジョナサンです。
今日は、間近に迫った半減期で浮き足立っているだろう皆さんのために、半減期によって何がどう変わるのか、技術的な仕組みにフォーカスして話したいと思います。
Bitcoin Coreのソースコード
殆どの方はご存知かと思いますが、ビットコインを動かすコードは https://github.com/bitcoin/bitcoin こちらからすべて見ることができます。
また、半減期に関わるコードはこちらになります(v0.12.1):
https://github.com/bitcoin/bitcoin/blob/9779e1e1f320a45255f2e81325f2feceec3fa944/src/main.cpp#L1567
CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
{
int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
// Force block reward to zero when right shift is undefined.
if (halvings >= 64)
return 0;
CAmount nSubsidy = 50 * COIN;
// Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
nSubsidy >>= halvings;
return nSubsidy;
}
一行ずつ見ていきましょう。
新しいブロックを発見したら、いくら貰える?
これは、「関数」と呼ばれるひとかたまりのコードで書かれています。
関数とは、引数(入力)を入れて、関数の処理を行い、戻り値(出力)を返すものを指します。
まずは1行目、この関数の引数を見てみましょう:
1: CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
- 赤:関数の戻り値; この関数は、ビットコインの数量(CAmount)型で戻り値を返します
- 青:関数名; この関数名は、『GetBlockSubsidy』(ブロック報酬額の取得)です
- 緑:ひとつめの引数; 整数型(int)の『nHeight』(ブロック高)を引数として使います
- 紫:ふたつめの引数; Consensusライブラリで定義されたパラメータを引数として使います
上記の4つの情報をもって、正しい報酬額を計算する「関数」となっています。
半減期が訪れたことをどうやって判断するか
3: int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
- 赤:変数『halving』(半減回数)を整数型(int)で宣言しています
- 青+緑:『nHeight』(ブロック高)を、『nSubsidyHalvingInterval』(報酬額の半減期間隔)で割って赤に代入します
変数は整数型(int)で宣言されているので、代入する値はすべて小数点が切り捨てられます。小数点以下を扱う場合は、(double)や(float)などを(int)の代わりに使います。
例えば、418944ブロックの時は次のようになります。
418944 / 210000 = 1.994
もう少しで2、つまり2回目の半減期が訪れますね!
この場合、小数点以下は切り捨てられるので、実際には halving = 1 となります。
248年後に訪れるバグを潰す
4: // Force block reward to zero when right shift is undefined.
5: if (halvings >= 64)
6: return 0;
- 赤:"エラーが出るからブロック報酬を強制的に0にする"との注意書きです(実行コードではありません)
- 青:もし、半減期が64回以上迎えていたら
- 緑:0を戻り値として返します
実際には33回目の半減期で0に達しますが、プログラムの仕様上の理由からこのようなバグ潰しのためのコードがあらかじめ含まれています。詳細は後ほど説明しますが、バグの内容は64回以上シフトできないというものです。
ブロック報酬の初期設定を定義する
8: CAmount nSubsidy = 50 * COIN;
- 赤:『nSubsidy』(報酬額)という変数を、『CAmount』(ビットコインの数量)として宣言します
- 青:固定値『COIN』(100,000,000)に50を掛けた値です
CAmountはビットコインの数量を表す型(タイプ)ですが、実は、1BTCという単位ではなく、0.00000001BTC(1億分の1BTC)を1としてすべての計算を行なっています。この単位はビットコインの発明者であるナカモトサトシの名前からもじって、「サトシ」と呼ばれています。ですので、固定値である『COIN』は1億サトシと呼ぶことができます。
つまり、半減期を迎えた回数(halving)が1未満であれば、報酬は初期の50BTCとなります。
報酬を半減させるための計算
9: // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
10: nSubsidy >>= halvings;
11: return nSubsidy;
- 赤:"21万ブロック(約4年間)ごとに半減します"との注意書き
- 青:『nSubsidy』(報酬額)を、『halving』(半減期の回数)回、右シフトして『nSubsidy』に代入します
- 緑:最終的な『nSubsidy』(報酬額)を戻り値として返します
右シフトはプログラマーじゃないと分かりづらいかもしれませんが、「パソコンは全てを1と0で計算している」という話は誰もが耳にしたことがあるはずです。
例えば、5,000,000,000の数字を1と0で表すと
0000000000000000000000000000000100101010000001011111001000000000
となります。
よりわかりやすくするために、「14」を2進法にして見てみましょう。
14 = 00001110 (0x0e)
さて、一番右の桁を捨てて、残りのものを1個ずつ右に一つずらしたら?(シフトしたら?)
7 = 00000111 (0x07)
そうです。2進法で数字を右に一個ずらしたら、2で割って切り捨てた時と同じ結果になります。
よって、
0000000000000000000000000000000100101010000001011111001000000000 = 50 BTC
0000000000000000000000000000000010010101000000101111100100000000 = 25 BTC
0000000000000000000000000000000001001010100000010111110010000000 = 12.5 BTC
0000000000000000000000000000000000100101010000001011111001000000 = 6.25 BTC
右にずらす(右シフトする)回数で、半減回数と報酬額を表しているわけです。
この関数が使われる場所
https://github.com/bitcoin/bitcoin/blob/9779e1e1f320a45255f2e81325f2feceec3fa944/src/main.cpp#L2387
この「ConnectBlock」という関数の中で、「このブロックの報酬を配布する取引の送金額が、(報酬+ブロックに含まれた手数料)よりも大きければエラーを返し、不正なブロックとして捨てる」という処理が入っています。
まとめ
このコードから察するに、ビットコインが33回目の半減期を迎えるとマイナーに対する報酬が0になり、ビットコインを使う人たちが取引に上乗せしている手数料だけで食っていかないといけなくなります。
2日後には2回目の半減なので、(33-2) × 約4年 = 約124年後の話になります。
ちなみに、124年前はというと明治25年です。インターネットが大きく普及したのが約20年前です。
そう考えると非常に長く感じますが、今週末の半減期で皆さんとビットコインの大きな第二歩を踏み出せたらなと思っています。
無料メールマガジン
BTCNの最新ニュースを毎日お昼ごろお届けします!