正確にはマイニングで必要なブロックのハッシュを求めるプログラムを書いてみる。今更自力で実装したソフトでマイニングするのは無駄&無理なので、仕組みを理解するのが目的。
Bitcoinって
参考文献参照。
マイニング(採掘)って
詳細な説明は他の記事などに委ねますが、Bitcoinの取引を記帳(承認)する行為で、
- 前のブロックのハッシュ値
- 承認する取引から計算される値(マークルルート)
- 任意の32ビットの数値(nonce)
- その他(後述)
から計算できるハッシュ値の先頭から特定の数(2016年1月現在で17個)だけ0が並んでくれるようなnonceの値を探し出す行為です。世界で最初にそのブロックのnonceを見つけると、報酬として25BTC(2016年1月現在で約116万円)の新規発行コインと、記帳した取引の手数料がもらえます。
この報酬目当てに世界中の人が専用チップを積んだマシンを大量に使ってせっせとマイニングしています。マイニングの難易度は全世界でのリソースを使って平均10分かかるよう調整されているので、マイニングの参加者が増えれば増えるほど難しくなっていきます。
前のブロックのハッシュを元に計算するので、そこが前のブロックとの繋がっていて「ブロックチェーン」という名前の由来です。1つの取引履歴を改ざんするためには、その取引が含まれるブロックと、そこから先の全てのブロックのハッシュを再計算する必要があり、改ざん不可だと言われる所以です。
やってみる
本当にマイニングしようと思うととても時間がかかるので、すでに承認されている取引のnonceが本当に正しいのかを確かめるだけにします。
bitcoinのすべての取引や採掘の結果は公開されているので、
https://blockchain.info/ja/
等で見ることができます。
今回はサンプルとして
https://blockchain.info/ja/block/000000000000000003a0343cc001d21b97d15e97e665b68c790b98c871cf0731
を使います。
ハッシュ計算の入力になるのは
- ブロックのバージョン
- 前のブロックのハッシュ値
- マークルルート(承認対象の取引から計算される)
- 時刻
- bits (難易度をコントロールする値)
- nonce (この値を見つけるのがマイニング)
です。これらの値を上記のページから拾ってきます。
version = 4
prev_block = "0000000000000000005629ef6b683f8f6301c7e6f8e796e7c58702a079db14e8"
markle_root = "efb8011cb97b5f1599b2e18f200188f1b8207da2884392672f92ac7985534eeb"
timestamp = "2016-01-30 13:23:09"
bits = 403253488
nonce = 1448681410 # 承認済みのブロックなので、nonceの値もわかっている
それぞれこのままでは使えないので、所定のフォーマットに変換します。
バージョン
バージョンは0で埋めて8桁にします。また、他の値にも共通ですが、これらの値はすべてバイト順を逆順にして計算に使います(リトルエンディアン)。バイト順を逆順にするのは多分他にもっといいやり方がありますが、以下では一旦16進数の文字列にフォーマット変換してからまたデコードしています。
(python3ならintにto_bytesメソッドがあります)
version_h = format(version, "08x").decode("hex")[::-1]
前ブロックのハッシュ、マークルルート
前ブロックのハッシュとマークルルートはすでに16進数の形になっているので、デコードして逆順にします。
prev_block_h = prev_block.decode("hex")[::-1]
markle_root_h = markle_root.decode("hex")[::-1]
時刻
時刻はUnix標準時からの秒数を例によって逆順バイト列に変換します。
from datetime import datetime
timestamp_s = int((datetime.strptime(timestamp, "%Y-%m-%d %H:%M:%S")-datetime(1970,1,1)).total_seconds())
timestamp_h = format(timestamp_s,"x").decode("hex")[::-1]
bits, nonce
逆順バイト列に変換するだけです。
bits_h = format(bits,"x").decode("hex")[::-1]
nonce_h = format(nonce,"x").decode("hex")[::-1]
ハッシュの計算
Bitcoinのハッシュはsha256を2重に使います。また、結果も逆順バイト列になっているので、順序を変換して16進数に変換します
from hashlib import sha256
header = version_h + prev_block_h + markle_root_h + timestamp_h + bits_h + nonce_h
print(sha256(sha256(header).digest()).digest()[::-1].encode("hex"))
出力
000000000000000003a0343cc001d21b97d15e97e665b68c790b98c871cf0731
ちゃんと0が17個並んでいるのがわかります。
まとめ
- マイニングの仕組みがざっくり分かった
- 次はマークルルートの計算もやってみるかも
参考文献
-
http://jp.techcrunch.com/2015/03/31/bitcoin-essay/
- (日本語)ビットコイン全般に関する非常にわかりやすい記事
-
https://en.bitcoin.it/wiki/Protocol_documentation
- (英語)ハッシュの計算方法の定義が載っている。全部読むのはけっこう重い