簡単なブロックチェーンをつくる(その6 ジェネシスブロックのマイニング)

 前回のプログラムを使ってジェネシスブロックのマイニングを行う.ジェネシスブロックはブロックチェーンインスタンス生成時にコンストラクタを通じて作成する.ジェネシスブロックに入れるトランザクションは,コインベーストランザクションプルーフオブワークによりブロックを生成したマイナーに報酬として与えられるコインのトランザクション)のみとする.ここでは,senderを"0"とし,Satoに1000コインを支払うとした.

import hashlib, json

from time import time
from flask import Flask, jsonify, request

app = Flask(__name__)

class Blockchain():

    # ハッシュ値の上4文字が0000となるナンスを見つける
    difficulty = 4
    target = '0000'

    def __init__(self):
        # ブロックチェーン本体
        self.blockchain = []
        # 1ブロックのトランザクションリスト
        self.tx_list = []
        # ジェネシスブロックの"前ブロック"のハッシュ値
        self.prev_block_hash = hashlib.sha256("genesis".encode()).hexdigest()
        # ジェネシスブロック
        block = {
            'index': 0,
            'timestamp': time(),
            # コインベーストランザクション: 'Sato'に1000コインを送付
            'tx_list': [{'sender': '0', 'recipent': 'Sato', 'amount': 1000}],
            'nonce': 0,
            'prev_block_hash': self.prev_block_hash
        }
        # ジェネシスブロックのノンスを計算
        block['nonce'] = self.proof_of_work(block)
        # ジェネシスブロックをブロックチェーンに追加
        self.blockchain.append(block)

    # プルーフオブワーク
    # ターゲットの条件を満たすハッシュ値を与えるノンスを見つける
    def proof_of_work(self, block):
        while True:
            hash = hashlib.sha256(json.dumps(block, sort_keys=True).encode()).hexdigest()
            if hash[:self.difficulty] == self.target:
                # 見つけたブロックのハッシュ値(次のブロックに必要)
                self.prev_block_hash = hash
                break
            block['nonce'] += 1

        return block['nonce']


# ブロックチェーンインスタンス
bc = Blockchain()
print(bc.blockchain)
print(bc.prev_block_hash)

# ブロック生成
@app.route("/block", methods=["GET"])
def block():
    nonce = 0
    block = {
        'index': len(bc.blockchain),
        'tiemstamp': time(),
        'tx_list': bc.tx_list,
        'nonce': nonce,
        'prev_block_hash': bc.prev_block_hash
    }

    # 次のブロック用に現在のブロックのハッシュを計算しておく
    bc.prev_block_hash = hashlib.sha256(json.dumps(block, sort_keys=True).encode()).hexdigest()
    
    # トランザクションリストをブロックに入れたのでクリア
    bc.tx_list = []

    # ブロックチェーンにブロックを追加
    bc.blockchain.append(block)

    return jsonify(bc.blockchain), 200

# トランザクション生成
@app.route("/tx", methods=['POST'])
def tx():
    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:
        bc.tx_list.append(tx)
        message ='Tx added'
        status_code = 201
        print(bc.tx_list)

    responce = {'message': message}
    return jsonify(responce), status_code

if __name__ == "__main__":
    app.run()

結果

> curl http://localhost:5000/block|jq

[
  {
    "index": 0,
    "nonce": 55557,
    "prev_block_hash": "aeebad4a796fcc2e15dc4c6061b45ed9b373f26adfc798ca7d2d8cc58182718e",
    "timestamp": 1624842624.1001291,
    "tx_list": [
      {
        "amount": 1000,
        "recipent": "Sato",
        "sender": "0"
      }
    ]
  },
  {
    "index": 1,
    "nonce": 0,
    "prev_block_hash": "0000271953947ae4849069f9fd73b2c489a76d4cc02f98c1c9a3a8327e46e89b",
    "tiemstamp": 1624842626.487038,
    "tx_list": []
  }
]