Python で学ぶブロックチェーン

# 1. はじめに
本記事では Python を使用してブロックチェーンを学ぶ方法について解説していきます。ブロックチェーンは仮想通貨の分野でよく知られていますが、その技術は多岐にわたる分野で活用されています。今回は、Python の基礎知識がある方を対象に、ブロックチェーンの仕組みと Python での実装方法について詳しく解説していきます。

本記事では、コンセンサスアルゴリズムとして、最も広く知られている「Proof of Work (PoW)」について説明させていただこうと思います。
（コンセンサスアルゴリズムについては、[7. コンセンサスアルゴリズム](https://qiita.com/drafts/a7b0c2552e1fd937a789/edit#7-%E3%82%B3%E3%83%B3%E3%82%BB%E3%83%B3%E3%82%B5%E3%82%B9%E3%82%A2%E3%83%AB%E3%82%B4%E3%83%AA%E3%82%BA%E3%83%A0)にて説明しています。）

それぞれのセクションごとに該当するPythonによる実装例を表示しております。[9.1. ソースコード全文](https://qiita.com/drafts/a7b0c2552e1fd937a789/edit#91-%E3%82%BD%E3%83%BC%E3%82%B9%E3%82%B3%E3%83%BC%E3%83%89%E5%85%A8%E6%96%87)では、セクション毎に記載したPythonによる実装例も織り込んだ形でのソースコードの全文を記載しております。

## 1.1. ブロックチェーンとは
ブロックチェーンとは、分散型のデータベース技術で、データを分散させ、改ざん不可能な形で記録することができる技術です。ブロックチェーンには、ブロックと呼ばれるデータの塊が連鎖的につながった形でデータが格納されます。

ブロックチェーンは、一般的にはビットコインやその他の仮想通貨で使われる分散型台帳技術として有名ですが、実際には様々な用途に利用されています。たとえば、金融業界では、取引の透明性や信頼性を向上させるために、ブロックチェーンを利用しています。また、ブロックチェーンは、契約書や重要な文書のデジタル署名など、法的なプロセスの改善にも役立ちます。

ブロックチェーンの最大の利点としては、中央集権的なデータベースとは異なり、分散型のデータベースであるため、データの透明性や信頼性が向上することが挙げられます。

## 1.2. ブロックチェーンの仕組み
ブロックチェーンは、分散型のデータベースの一種です。つまり、複数のコンピューターで情報を共有することで、信頼性を高めることができます。ブロックチェーンは、ブロックと呼ばれる情報の集合体をつなぎ合わせることで、データを管理します。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/5af66814-6229-c227-ca24-1789910cf54f.png" width="850px">

# 2. ブロックの構造
ブロックチェーンは、ブロックと呼ばれるデータの塊が連鎖的につながった形でデータが格納される技術です。各ブロックには、複数のトランザクションが含まれており、ブロックチェーンはこれらのトランザクションの記録を保持するために使用されます。
ブロックチェーンの最初のブロックは、ジェネシスブロックと呼ばれます。

この記事では、ブロックの構造について詳しく見ていきます。

## 2.1. ブロックの概要
ブロックは、ブロックチェーンの基本的なデータ構造であり、用途によって要素が変動することが想定されますが、本記事では、以下の要素で説明していこうと思います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/4979353d-929c-36d2-ff59-e27c7bb4bbcf.png" width="230px"/>

| 要素 | 説明 |
|:--|:--|
| ヘッダー | ブロックの情報を識別するためのデータ。 |
| トランザクション | トランザクションの詳細が含まれている。 |
| ブロックハッシュ値 | ブロックの一意の識別子であり、ブロックのデータが改ざんされていないことを確認するために使用される。 |

## 2.2. ヘッダーの概要
ヘッダーには、以下の要素が含まれます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/f496cf45-fc6c-0f6e-f3c9-45152fc4cc25.png" width="230px"/>

| 要素 | 説明 |
|:--|:--|
| インデックス | ブロックのインデックス番号。 |
| タイムスタンプ | ブロックが生成された日時。 |
| ナンス | ブロックハッシュの生成に使用されるランダムな値。 |
| 前のブロックのハッシュ値 | 前のブロックの一意の識別子であり、ブロックチェーン内の前のブロックに対する参照。 |
| マークルルート | ブロック内のすべてのトランザクションのハッシュ値をマージすることで生成されるハッシュ。 |

## 2.3. Python 実装
Python でブロックのヘッダー定義および変数初期化を以下のように行います。
```python
class Block:
    def __init__(self, index, timestamp, nonce, previous_block_hash, merkle_root, transactions):
        self.index = index  # インデックス
        self.timestamp = timestamp  # タイムスタンプ
        self.nonce = nonce  # ナンス
        self.previous_block_hash = previous_block_hash  # 前のブロックハッシュ値
        self.merkle_root = merkle_root  # マークルルート
```

# 3. トランザクション
ブロックチェーン上で行われる取引は、トランザクションと呼ばれます。トランザクションは、仮想通貨として利用される場合は、送信元アドレス、送信先アドレス、送信される通貨の量、トランザクション手数料など、様々な情報が含まれますが、保持するデータは基本的には用途に応じて変わります。今回は構造を単純化するため、トランザクション内では項目としての定義は行いません。

## 3.1. トランザクションの概要
トランザクションはまずトランザクションプールに登録されます。その後、マイナー（採掘者）によってトランザクションプールからの取り出し、および新規ブロックへの挿入、ブロックチェーンへのブロック登録が行われ、トランザクションが承認状態となります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/5fc0c1d1-27bf-6121-68a8-a452272b68f9.png" width="600px" />

## 3.2. Python 実装
トランザクションプールからの取り出しは、仮想通貨の場合、手数料の大きいものから取り出されたりしますが、今回は、単純化するため、Pythonのキュークラスを用いて、FIFOで実装します。

トランザクションプールの登録については、以下の通り実装します。キュークラスで `transaction_pool` を定義し、`add_transaction` 関数でトランザクションを `transaction_pool` に PUT しています。

```python
from queue import Queue

class Blockchain:
    def __init__(self):
        self.transaction_pool = Queue()  # トランザクションプール
    
    # トランザクションを追加する関数
    def add_transaction(self, transaction):
        self.transaction_pool.put(transaction)
```

マイニング関数では、`transaction_pool` からトランザクションを取り出し、リストとしてセットしています。その後、ブロックチェーンとしてブロックを追加する際に、`transaction_pool` を初期化します。
```python
    # マイニングする関数
    def mine_block(self):
        ## ...
        new_block_transactions = list(self.transaction_pool.queue)
        ## ...
        while True:
            ## ...
            # ハッシュ値が要求された難易度より小さい場合、ブロックを追加して終了
            if new_block_hash[:self.difficulty] == '0' * self.difficulty:
                self.transaction_pool = Queue()
                ## ...
```

# 4. ハッシュとマークルルート
ブロックチェーンにおいて、ハッシュとマークルルートは非常に重要な役割を担っています。この記事では、ハッシュとマークルルートの概要について説明し、ブロックチェーンでどのように使用されるかについて詳しく解説します。

## 4.1. ハッシュの概要
ハッシュとは、ハッシュ関数を用いてデータから固定長の一意の値を生成したものを指します。
ブロックチェーンでは、セキュリティ強化のため暗号学的ハッシュ関数（以下、ハッシュ関数と記述）を利用しており、これは、同じデータに対しては常に同じハッシュ値を生成し、異なるデータに対しては異なるハッシュ値を生成します。ハッシュ値は、通常、数値または16進数で表されます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/df9da713-7cae-0a66-67ec-1f2bb7ea0e79.png" width="800px"/>

ハッシュ関数は、ブロックチェーンにおいて非常に重要な役割を果たしています。ブロックチェーン上のすべてのトランザクションやブロックには、ハッシュ値が割り当てられています。これにより、ブロックチェーン上のすべてのデータが一意に識別され、改ざんされていないことが確認されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/65575095-ecd9-8bf9-fa6a-38725527fa3f.png" width="650px" />

ハッシュ関数には、SHA-256やRIPEMD-160などのさまざまな種類があります。これらの関数は、異なる入力に対して同じ出力を生成することができますが、逆に同じ入力に対しては常に同じ出力を生成します。

## 4.2. ハッシュのブロックチェーンでの利用
ブロックチェーンにおいて、ハッシュは重要な役割を果たしています。各ブロックには、前のブロックのハッシュ値が含まれています。これにより、ブロックチェーン上のすべてのブロックが連結され、一意に識別されます。

また、ブロックチェーン上のすべてのトランザクションに対しても、ハッシュ計算されます。トランザクションの内容を変更した場合には異なるハッシュ値が生成されるため、トランザクションの改ざんは困難になります。

## 4.3. マークルルートの概要
マークルルートは、ブロックチェーンにおいて、複数のトランザクションのハッシュ値を一つのハッシュ値にまとめるために使用されるデータ構造です。マークルルートは、ハッシュ値を木構造に並べたものであり、ルートのハッシュ値をブロックのヘッダーに保存することで、複数のトランザクションの一意性を確認します。

マークルルートは、複数のトランザクションが含まれるブロックに対して使用されます。トランザクションのハッシュ値がリーフノードに配置され、隣接するリーフノードのハッシュ値が親ノードのハッシュ値として計算されます。これを繰り返すことで、全体のハッシュ値がルートに設定されます。

マークルルートは、ブロックチェーンにおいて、トランザクションが改ざんされていないことを確認するために使用されます。たとえば、ブロック内のあるトランザクションが改ざんされた場合、そのトランザクションのハッシュ値が変更され、その親ノードのハッシュ値も変更されます。これにより、ルートのハッシュ値も変更され、改ざんされたことが検出されます。

## 4.4. マークルルートのブロックチェーンでの利用
ブロックチェーンにおいて、マークルルートは、トランザクションの改ざんを検出するために使用されます。ブロック内のトランザクションが変更された場合、そのハッシュ値が変更され、その親ノードのハッシュ値も変更されるため、ルートのハッシュ値も変更されることとなり、改ざんを検出することができます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/f095ef98-cb42-3a5a-d1e5-52b3c6936eca.png" width="700px"/>

ブロックチェーンでは、ハッシュ値を計算するために、SHA-256アルゴリズムが使用されます。SHA-256アルゴリズムは、入力データから一定の長さのハッシュ値を生成する暗号学的ハッシュ関数であり、データの改ざんを防ぐために使用されます。

## 4.5. Python 実装
### 4.5.1. ハッシュ
ブロックのハッシュ値は、ヘッダーからSHA256で計算します。実装では、ヘッダーをJSON形式にして、ハッシュを計算しています。
```python
    # SHA256でハッシュ計算する関数
    def calculate_hash(self):
        block_string = json.dumps({
            'index': self.index,  # インデックス
            'timestamp': self.timestamp,  # タイムスタンプ
            'nonce': self.nonce,  # ナンス
            'previous_block_hash': self.previous_block_hash,  # 前のブロックハッシュ値
            'merkle_root': self.merkle_root,  # マークルルート
        }, sort_keys=True).encode()
        
        return hashlib.sha256(block_string).hexdigest()
```

前のブロックハッシュ値は、マイニングする際に、前のチェーンの `block_hash` から取得します。

```python
    # マイニングする関数
    def mine_block(self):
        # 直前のブロックを取得
        previous_block = self.chain[-1]
        # ...
        new_block_previous_hash = previous_block['block_hash']
```

### 4.5.2. マークルルート
マークルルートは以下のアルゴリズムで処理します。

1. トランザクション数が0の場合は、空文字列のハッシュ値を返す
2. トランザクション数が1の場合は、そのトランザクションのハッシュ値を返す
3. 要素数が奇数の場合は、最後の要素を複製して偶数にする
4. 2つの要素を組み合わせてハッシュ値を計算し、リストに格納
5. 3.〜4.を再起的に繰り返す。

```python
    # マークルルートを計算する関数
    def calculate_merkle_root(self, transactions):
        # 要素数が0の場合は、空文字列のハッシュ値を返す
        if len(transactions) == 0:
            return hashlib.sha256(b'').hexdigest()

        # 要素数が1の場合は、そのトランザクションのハッシュ値を返す
        if len(transactions) == 1:
            return hashlib.sha256(transactions[0].encode()).hexdigest()

        # 要素数が奇数の場合は、最後の要素を複製して偶数にする
        if len(transactions) % 2 == 1:
            transactions.append(transactions[-1])

        # ハッシュ値を格納するリストを初期化
        hashes = []

        # 2つのトランザクションを組み合わせてハッシュ値を計算し、リストに格納する
        for i in range(0, len(transactions), 2):
            transaction_pair = transactions[i] + transactions[i+1]
            hash_value = hashlib.sha256(transaction_pair.encode()).hexdigest()
            hashes.append(hash_value)

        # 再帰的にマークルルートを計算する
        return self.calculate_merkle_root(hashes)
```

# 5. ナンスと難易度
ブロックチェーンの分散型ネットワークは、複数のノードが競合して新しいブロックを追加しようとします。新しいブロックを追加するためには、競争相手よりも先に正しい答えを見つける必要があります。この答えを見つけるために、ブロックヘッダーのナンスと呼ばれる値が使用されます。

## 5.1. ナンスの概要
ナンスは、ブロックヘッダー内の一部であり、ブロックチェーンのセキュリティを維持するために使用されます。

ナンスは、単純にランダムな値を使用することができますが、その場合、ブロックのハッシュ値が特定の条件を満たすことは非常に稀であり、ブロックの採掘が困難になります。そのため、ナンスは、採掘者がブロックのハッシュ値を効率的に計算できるように、調整する必要があります。

## 5.2. ナンスのブロックチェーンでの利用
ブロックのマイナー（採掘者）は、ナンスの値を変更し、ブロックのハッシュ値が特定の条件を満たすようにします。この条件は、ブロックチェーンにおいて難易度と呼ばれます。

## 5.3. 難易度の概要
難易度は、新しいブロックが生成される平均的な速度を制御するために使用されます。
たとえば、ブロックがあまりにも速く生成されると、ネットワークは過負荷になり、トランザクションの処理が追いつかなくなる可能性があります。逆に、ブロックがあまりにも遅く生成されると、トランザクション処理が遅くなる可能性があります。そのため、ブロックを生成する速度を調整することで、ネットワークの安定性を保つことができます。
ビットコインの場合、10分に1度のペースでブロックが生成されるよう難易度が調整されています

## 5.4. 難易度のブロックチェーンでの利用
ブロックチェーンにおいて、新しいブロックを生成するためには、ブロックのヘッダーから計算される「ハッシュ値」が「難易度」の条件を満たす必要があります。

具体的には、ハッシュ値の先頭に特定の数の0が含まれている必要があります。この数字の量は、ネットワーク全体で共有された規則に基づいて決定され、難易度が調整されます。難易度は、ハッシュ値を生成するために必要なコンピュータの計算量を調整することで、ブロックを生成する速度を調整します。つまり、難易度が高い場合は、ハッシュ値を生成するために必要な計算量が増え、ブロックの生成速度が遅くなります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/1ece1906-c668-d0aa-976f-9ed99d7bfa87.png" width="500px"/>

難易度を変更すると、新しいブロックのマインニングに要する時間が変わりますが、一般的には平均して10分に1つブロックが生成されるように難易度が調整されます。このシステムは、Bitcoin など PoW (Proof of Work) 型ブロックチェーンで採用されています。

5.5. Python 実装
はじめに、ナンスを設定（初期値は0）後にハッシュを計算し、`new_block_hash` に代入をします。その後、`new_block_hash` の冒頭から難易度分のバイト数（今回の場合は2バイト）を取り出し、0が難易度分連続しているか（今回の場合は、'00'と一致しているか）を確認します。条件を満たす場合は、チェーンにブロックを追加してマイニングを終了し、条件を満たさない場合は、ナンスに1を加算して再度処理を繰り返します。

```python
class Blockchain:
    def __init__(self):
        # ...
        self.difficulty = 2  # 難易度
    # ...
    # マイニングする関数
    def mine_block(self):
        # ...
        new_block_nonce = 0
        # ...
        while True:
            # 新しいブロックを作成
            new_block = Block(
                index = new_block_index,
                timestamp = new_block_timestamp,
                nonce = new_block_nonce,
                previous_block_hash = new_block_previous_hash,
                merkle_root = new_block_merkle_root,
                transactions = new_block_transactions
            )
            # ...
            new_block_hash = new_block.calculate_hash()
            
            # ハッシュ値が要求された難易度より小さい場合、ブロックを追加して終了
            if new_block_hash[:self.difficulty] == '0' * self.difficulty:
                # ...
            
            # nonceを増やして再度試行
            new_block_nonce += 1
```

# 6. 電子署名、公開鍵、秘密鍵
ブロックチェーン技術では、電子署名、公開鍵、秘密鍵といった暗号技術が重要な役割を果たしています。この記事では、電子署名、公開鍵、秘密鍵の概要と、それらがブロックチェーンでどのように使用されるかについて説明します。

## 6.1. 電子署名の概要
電子署名は、文書の真正性や完全性を保証するために用いられる技術です。具体的には、ある文書に対して電子署名を行うことで、その文書が改ざんされていないことや、署名者が誰であるかといった情報を確認することができます。

電子署名は、公開鍵暗号方式を基礎としています。公開鍵暗号方式とは、暗号化と復号化に異なる鍵を用いる方式で、秘密鍵と公開鍵の2つの鍵が存在します。

## 6.2. 電子署名のブロックチェーンでの利用
ブロックチェーンでは、トランザクションに対して電子署名が用いられます。取引情報などのトランザクションでは、送信者のアドレスと受信者のアドレス、送信するコインの量などが含まれます。送信者は、自分の秘密鍵を用いてトランザクションに対して署名を行い、その署名を含めてネットワークに送信します。

ネットワーク上の他のノードは、送信者の公開鍵を使用して送信者の署名が正しいかどうかを検証することができます。署名が正しい場合、トランザクションは承認され、ブロックに追加されます。このようにして、ブロックチェーン上の取引は、信頼性とセキュリティが確保されたものとなります。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/95813f7c-1833-f82d-8fd9-2a5435f1d8ed.png" width="750px"/>

## 6.3. 公開鍵と秘密鍵の概要
公開鍵と秘密鍵は、暗号学的に関連する2つの鍵であり、非対称暗号のセキュリティに不可欠です。公開鍵は誰でも知ることができ、秘密鍵は所有者だけが知っています。

公開鍵暗号方式では、公開鍵を使って暗号化を行い、秘密鍵を使って復号化を行います。送信者は受信者の公開鍵を使用してメッセージを暗号化し、受信者は自分の秘密鍵を使用してメッセージを復号化します。この方式は、事前の鍵交換が不要なため安全であり、セキュリティ的に優れています。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/028ecfb8-bdcb-7d6f-5e27-0b32d972c7d8.png" width="550px"/>

## 6.4. 公開鍵と秘密鍵がブロックチェーンでどのように使用されるか
ブロックチェーンでは、公開鍵と秘密鍵はトランザクション関連で使用されます。トランザクションは、送信者の秘密鍵で署名されます。これにより、トランザクションが本当に送信者によって生成されたことが証明されます。

また、ブロックチェーンには、自己認証機能があります。これにより、トランザクションに含まれる公開鍵とトランザクションの署名から、送信者が誰であるかが確認されます。この方法により、送信者が正当な権利を持っていることが証明され、トランザクションが承認されます。

# 7. コンセンサスアルゴリズム
コンセンサスアルゴリズムとは、分散型のネットワークにおいて、ノード間で正しいブロックチェーンのバージョンを選択するためのアルゴリズムのことを指します。
ブロックチェーンでは、ネットワーク内の複数のノードが独立してトランザクションを検証し、新しいブロックを生成しています。しかし、ネットワーク内のノードは分散型であるため、誰もが自由にトランザクションを検証し、ブロックを生成することができるようになっているため、ネットワーク内のノード間で合意を形成し、正しいブロックチェーンのバージョンを選択することが重要になります。
コンセンサスアルゴリズムにより、ノードは "正しい" ブロックチェーンのバージョンを選択することができ、ブロックチェーン全体のセキュリティと信頼性を確保することができます。

ブロックチェーンのコンセンサスアルゴリズムにはいくつかの種類がありますが、ここでは代表的な3つを紹介します。

- **Proof of Work (PoW)**: PoW は、最も有名なコンセンサスアルゴリズムの1つで、ビットコインなどのブロックチェーンで使用されています。このアルゴリズムでは、ネットワークのノードは、数学的に難しい問題（ハッシュ値を特定の条件に一致させる問題）を解いて、ブロックをマイニングします。最初に問題を解いたノードが新しいブロックを追加できるようになり、報酬を得ることができます。
- **Proof of Stake (PoS)**: PoS は、ブロックチェーンのコンセンサスアルゴリズムのもう1つの代表的な方式で、イーサリアムなどのブロックチェーンで採用されています。このアルゴリズムでは、ノードは自分が保有する暗号通貨の量に応じて、新しいブロックをマイニングする権利を得ます。より多くの暗号通貨を保有しているノードほど、より多くのブロックをマイニングすることができます。
- **Delegated Proof of Stake (DPoS)**: DPoS は、PoS を改良したもので、ステーキングする代わりに、一部のノードがネットワークのブロック生成にのみ参加するようになっています。通常、ネットワーク上で最も信頼性の高いノードが選ばれ、他のノードに代わってブロック生成を行います。DPoSは、スケーラビリティが高く、高速で効率的なブロック生成が可能です。EOS などのブロックチェーンで使用されています。

# 8. ブロックチェーンのセキュリティ
## 8.1. ブロックチェーンのセキュリティの重要性
ブロックチェーンは、分散型台帳技術を用いて複数のノードが同じデータを保管し、管理することで、中央集権的なシステムと比べてセキュリティの高いシステムとされています。しかし、ブロックチェーンが保持する重要な情報に対して攻撃が行われることは避けられません。ブロックチェーンは、暗号学的技術を用いてセキュリティを確保していますが、攻撃者は常に新たな攻撃方法を開発し、ブロックチェーンの脆弱性を見つけ出そうと試みています。

ブロックチェーンが保持する情報の中には、取引履歴や個人情報など、攻撃者にとって価値のあるものが多く含まれます。そのため、ブロックチェーンのセキュリティは非常に重要であり、適切なセキュリティ対策が必要です。

今回は代表的な例として、51%攻撃について説明していこうと思います。

## 8.2. 51%攻撃
51%攻撃とは、PoW アルゴリズムに対する攻撃手法で、攻撃者がネットワーク上で過半数のハッシュパワーを持っている場合に、ブロックチェーンの攻撃を行うことができるというものです。

この攻撃手法では、攻撃者が過半数のハッシュパワーを持っているため、攻撃者が自分で生成したブロックが採用されるように仕向けることができます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/eedd7021-5968-71dd-7b7a-1a6050238fff.png" width="750px"/>

この攻撃を防ぐためには、ネットワーク上でのハッシュパワーの分散が重要となります。また、この攻撃は非常に高いコストがかかるため、攻撃者が簡単に過半数のハッシュパワーを獲得することは難しいとされています。

# 9. Python 実装

## 9.1. ソースコード全文

今回実装した Python コードは以下の通りです。
電子署名などは、送信者および受信者というロールの存在する取引を処理する場合に重要になる技術要素ですが、以下の理由により今回の実装の対象外としています。
- 今回はブロックチェーンの仕組みを理解することが目的であり、取引というシナリオでは実施していない
- 電子署名や公開鍵、秘密鍵を実装すると、実装が複雑化し、ブロックチェーンの実態が見えづらくなる

```python
import hashlib
import json
import time
from queue import Queue

# ブロックのクラス
class Block:
    def __init__(self, index, timestamp, nonce, previous_block_hash, merkle_root, transactions):
        self.index = index  # インデックス
        self.timestamp = timestamp  # タイムスタンプ
        self.nonce = nonce  # ナンス
        self.previous_block_hash = previous_block_hash  # 前のブロックハッシュ値
        self.merkle_root = merkle_root  # マークルルート
        self.transactions = transactions  # トランザクション
        self.block_hash = self.calculate_hash()  # ブロックハッシュ値

    # SHA256でハッシュ計算する関数
    def calculate_hash(self):
        block_string = json.dumps({
            'index': self.index,  # インデックス
            'timestamp': self.timestamp,  # タイムスタンプ
            'nonce': self.nonce,  # ナンス
            'previous_block_hash': self.previous_block_hash,  # 前のブロックハッシュ値
            'merkle_root': self.merkle_root,  # マークルルート
        }, sort_keys=True).encode()
        
        return hashlib.sha256(block_string).hexdigest()

    # マークルルートを計算する関数
    def calculate_merkle_root(self, transactions):
        # 要素数が0の場合は、空文字列のハッシュ値を返す
        if len(transactions) == 0:
            return hashlib.sha256(b'').hexdigest()

        # 要素数が1の場合は、そのトランザクションのハッシュ値を返す
        if len(transactions) == 1:
            return hashlib.sha256(transactions[0].encode()).hexdigest()

        # 要素数が奇数の場合は、最後の要素を複製して偶数にする
        if len(transactions) % 2 == 1:
            transactions.append(transactions[-1])

        # ハッシュ値を格納するリストを初期化
        hashes = []

        # 2つのトランザクションを組み合わせてハッシュ値を計算し、リストに格納する
        for i in range(0, len(transactions), 2):
            transaction_pair = transactions[i] + transactions[i+1]
            hash_value = hashlib.sha256(transaction_pair.encode()).hexdigest()
            hashes.append(hash_value)

        # 再帰的にマークルルートを計算する
        return self.calculate_merkle_root(hashes)

# ブロックチェーンのクラス
class Blockchain:
    def __init__(self):
        self.chain = [self.create_genesis_block()]  # チェーン
        self.transaction_pool = Queue()  # トランザクションプール
        self.difficulty = 2  # 難易度

    # ジェネシスブロックを生成する関数
    def create_genesis_block(self):
        genesis_block = Block(
            index=0,
            timestamp=time.time(),
            nonce=0,
            previous_block_hash='',
            merkle_root='',
            transactions=[],
        )
        return genesis_block.__dict__

    # トランザクションを追加する関数
    def add_transaction(self, transaction):
        self.transaction_pool.put(transaction)
    
    # マイニングする関数
    def mine_block(self):
        # 直前のブロックを取得
        previous_block = self.chain[-1]
        
        # 新しいブロックのデータを設定
        new_block_index = previous_block['index'] + 1
        new_block_timestamp = time.time()
        new_block_nonce = 0
        new_block_previous_hash = previous_block['block_hash']
        new_block_merkle_root = ''
        new_block_transactions = list(self.transaction_pool.queue)
        
        while True:
            # 新しいブロックを作成
            new_block = Block(
                index = new_block_index,
                timestamp = new_block_timestamp,
                nonce = new_block_nonce,
                previous_block_hash = new_block_previous_hash,
                merkle_root = new_block_merkle_root,
                transactions = new_block_transactions
            )
            new_block.merkle_root = new_block.calculate_merkle_root(new_block_transactions),
            new_block_hash = new_block.calculate_hash()
            
            # ハッシュ値が要求された難易度より小さい場合、ブロックを追加して終了
            if new_block_hash[:self.difficulty] == '0' * self.difficulty:
                self.chain.append(new_block.__dict__)
                self.transaction_pool = Queue()
                
                return new_block.__dict__
            
            # nonceを増やして再度試行
            new_block_nonce += 1
```

## 9.2. 実行シナリオ
1. "Alice" というトランザクションを追加して、チェーンの状態を確認します。
   この状態では、チェーンにはジェネシスブロックのみが存在していることが確認できます。
   <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/72f6721b-c5a7-443a-ba30-edb174becd14.png" width="900px"/>
2. マイニングを行うと、先ほど登録した "Alice" というトランザクションを含むブロック#1が処理されました。
   <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/7e77774c-5beb-ab1e-0cc0-fedc0a590d62.png" width="900px"/>
3. チェーンを確認すると、ブロック#1が追加されていることが確認できます。
   <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/4f914deb-b06c-73cb-a737-2351525ba807.png" width="900px"/>
4. 今度は、"Bob" と "Grace" いう2つのトランザクションを追加して、チェーンの状態を確認します。
   先ほどと同様、マイニング前なので、チェーン自体に変化はありません。
   <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/67cc3259-d669-c8c2-0218-a015dc74f1c9.png" width="900px"/>
5. マイニングを行うと、"Bob" と "Grace" いう2つのトランザクションを含むブロック#2が処理されました。
   <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/6cf7f4d0-22f9-cc56-b674-e5f0c49d3bd6.png" width="900px"/>
6. チェーンを確認すると、さらにブロック#2が追加されていることが確認できます。
   <img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2659159/b32fd103-ee76-6398-13bf-bf61317efbd7.png" width="900px"/>

# 参考文献
- 書籍: 絵で見てわかるブロックチェーンの仕組み, 米津武至
- 書籍: いちばんやさしいブロックチェーンの教本 人気講師が教えるビットコインを支える仕組み, 杉井靖典
- 書籍: 徹底理解ブロックチェーン ゼロから着実にわかる次世代技術の原則, Daniel Drescher 他
- 書籍: 図解即戦力 ブロックチェーンのしくみと開発がこれ1冊でしっかりわかる教科書, コンセンサス・ベイス株式会社
- Web ページ: "Cryptographic primitives in blockchains", Licheng Wang 他, file:///Users/jundo414/Downloads/Cryptographic_primitives_in_blockchains.pdf