次にブロックのハッシュを計算する.ブロックチェーンの各ブロックは,その直前のブロックのハッシュ値を保存している.ジェネシスブロックは例外で,「直前の」ブロックは存在しない.そのため直前のブロックのハッシュ値は適当に決めることになる.
ハッシュは hashlib モジュールの sha256 関数を使うことにする.sha256 は256ビット(32バイト)のハッシュを返す関数である.ジェネシスブロックの直前のブロックのハッシュ値を,ここでは 文字列 genesis をハッシュした
> hashlib.sha256("genesis".encode()).hexdigest() 'aeebad4a796fcc2e15dc4c6061b45ed9b373f26adfc798ca7d2d8cc58182718e'
を使うことにする.encode() は文字列をバイト列に変換する関数,hexdigest() は16進形式文字列にする関数である.ちなみにビットコインのジェネシスブロックにおける,対応するハッシュは hashPrevBlock=00000000000000 となっている(Bitcoin Core の src/chainparams.cpp).ジェネシスブロック以外のブロックのハッシュについては,ブロック全体のハッシュを取ることにする.
import hashlib, json from time import time from flask import Flask, jsonify, request app = Flask(__name__) # ブロックチェーン blockchain = [] # 1ブロックのトランザクションリスト tx_list = [] # 直前ブロックのハッシュ値 prev_block_hash = 0 # ブロック生成 @app.route("/block", methods=["GET"]) def block(): global blockchain, tx_list, prev_block_hash nonce = 0 # ジェネシスブロックの場合 if len(blockchain) == 0: prev_block_hash = hashlib.sha256("genesis".encode()).hexdigest() block = { 'index': len(blockchain), 'tiemstamp': time(), 'tx_list': tx_list, 'nonce': nonce, 'prev_block_hash': prev_block_hash } # 次のブロック用に現在のブロックのハッシュを計算しておく prev_block_hash = hashlib.sha256(json.dumps(block, sort_keys=True).encode()).hexdigest() # トランザクションリストをブロックに入れたのでクリア tx_list = [] # ブロックチェーンにブロックを追加 blockchain.append(block) return jsonify(blockchain), 200 # トランザクション生成 @app.route("/tx", methods=['POST']) def tx(): global tx_list tx = request.get_json() fields = ['sender', 'recipient', 'amount'] if (not all(k in tx for k in fields)) or (tx['amount'] <= 0): message = 'Input Error' status_code = 400 else: tx_list.append(tx) message ='Tx added' status_code = 201 responce = {'message': message} return jsonify(responce), status_code if __name__ == "__main__": app.run()
辞書の block をencodeすることはできないので,json.dumpsでjson形式にしている.現バージョンのpythonでは辞書のキーの順番は固定されているはずだが,念のため sort_keys=True により順番を明示的に固定している.これはブロックの有効性を検証するためにハッシュを再計算した際,ブロックの内容が同じであれば同じハッシュになることを保証するためである.
ブロック生成のコマンド
> curl http://localhost:5000/block | jq
を3回行ったときの結果を示す.
[ { "index": 0, "nonce": 0, "prev_block_hash": "aeebad4a796fcc2e15dc4c6061b45ed9b373f26adfc798ca7d2d8cc58182718e", "tiemstamp": 1624683426.8969722, "tx_list": [] }, { "index": 1, "nonce": 0, "prev_block_hash": "0b60c5f9bf90ebcb6093606a6b3b355cc15997d5329b34c4e1c6229be7c7474e", "tiemstamp": 1624683430.699087, "tx_list": [] }, { "index": 2, "nonce": 0, "prev_block_hash": "b5bf0f4f518efaf6db4e2842222f2314e5836ffcc500c4d7d0288264fbd58716", "tiemstamp": 1624683463.404587, "tx_list": [] } ]