約60行でブロックチェーンを実装

# はじめに
[Udemy](https://www.udemy.com/course/python-blockchain/)の講座でざっくりブロックチェーンの中身を理解したので実装してみました。講座の内容を基に自力で実装しています。
本講座ではシリコンバレーの現役エンジニアである酒井潤さんが教鞭をとっており、受講することで以下のようなプログラムであれば何も見ずとも作れるようになります。本投稿では実装していないwalletやproof_of_workの実装も行われていますので、興味を持たれた方は是非受講してみてください。同じく酒井潤さんのPython基礎講座もおすすめです。
※一部ミスがあったため作り直しました。


# ブロックチェーンの要素
各ブロック内の要素は以下のようになっています。

- ブロック
  - previous_hash：前のブロックのハッシュ値
  - nonce：マイニングによって見つける値
  - transaction：ブロック内で処理したトランザクション
  - timestamp：ブロックを作成した時間

<img width="443" alt="Blockchain.PNG" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/315055/eae70259-deac-00c6-3830-944c51ffb459.png">

チェーン上の全てのブロックはprevious_hashでつながっているため、チェーンの途中のブロックを改ざんしたい場合には、それ以降のすべてのハッシュ値を再計算しなければならず改ざんの防止につながります。


# チェーンにブロックが追加されるまでの動作
新しいブロックがチェーンに追加されるまでの動作は以下の通りです。

1. 送金者、送金先、金額を基にトランザクションを作成する
2. 作成したトランザクションを一時登録(プール)しておく
3. プールされているトランザクションをマイニングする（ナンス値を見つけ出す）
4. 前のブロックのハッシュ値、ナンス、トランザクション、タイムスタンプを基にブロックを作成する
5. 作成したブロックをチェーンに追加する


# 実際に作ってみる

```Python
class BlockChain(object):

    # 最初のブロックを作成する
    def __init__(self):
        self.chain = []
        self.transaction_pool = []
        self.create_block(previous_hash='Initialize')

    # ハッシュ値を返す
    def hash(self, block):
        json_block = json.dumps(block)
        return hashlib.sha256(json_block.encode()).hexdigest()
    
    # 受け取った値を基にブロックを作成する
    def create_block(self, previous_hash=None, nonce=0, transaction=None, timestamp=time.time()):
        block = {
            'previous_hash': previous_hash,
            'nonce': nonce,
            'transaction': transaction,
            'timestamp': timestamp
          }
        self.add_block_to_chain(block)
    
    # ブロックをチェーンに追加する
    def add_block_to_chain(self, block):
        self.chain.append(block)

    # ナンス値を探す
    def mining(self):
        previous_hash = self.hash(self.chain[-1])
        nonce = 0
        transaction = self.transaction_pool
        self.transaction_pool = []
        timestamp = time.time()
        self.create_block(previous_hash, nonce, transaction, timestamp)

    # トランザクションをプールしておく
    def add_transaction(self, sender_name, reciever_name, value):
        transaction = {
            'Sender_name': sender_name,
            'Reciever_name': reciever_name,
            'Value': value
        }
        self.transaction_pool.append(transaction)

    # チェーンを見やすい形で出力する
    def print_chain(self):
        for chain_index, block in enumerate(self.chain):
            print(f'{"="*40}Block {chain_index:3}')
            if block['transaction'] is None:
                print('Initialize')
                continue
            else:
                for key, value in block.items():
                    if key == 'transaction':
                        for transaction in value:
                            print(f'{"transaction":15}:')
                            for kk, vv in transaction.items():
                                print(f'\t{kk:15}:{vv}')
                    else:
                        print(f'{key:15}:{value}')


if __name__ == '__main__':
    print('='*30 + 'Start' + '='*30)
    # BlockChainインスタンスを作成
    blockchain = BlockChain()
    #トランザクションを登録する
    blockchain.add_transaction(sender_name='Alice', reciever_name='Bob', value=100)
    # トランザクションを登録する
    blockchain.add_transaction(sender_name='Alice', reciever_name='Chris', value=1)
    # マイニングを行う（ナンスを探す）
    blockchain.mining()
    # トランザクションを追加する
    blockchain.add_transaction(sender_name='Bob', reciever_name='Dave', value=100)
    # マイニングを行う（ナンスを探す）
    blockchain.mining()
    # 作成したブロックチェーンを表示する
    blockchain.print_chain()
```


# 実行結果

```
========================================Block   0
Initialize
========================================Block   1
previous_hash  :54c72dc7390c09a6d2c00037c381057a7bd069e8d9c427585ce31bed16dfd0d8
nonce          :0
transaction    :
        Sender_name    :Alice
        Reciever_name  :Bob
        Value          :100
transaction    :
        Sender_name    :Alice
        Reciever_name  :Chris
        Value          :1
timestamp      :1578989130.9111161
========================================Block   2
previous_hash  :d4bb210d2e3ad304db53756e87a7513b2fca8672c6e757bef6db3fff8ff26bb1
nonce          :0
transaction    :
        Sender_name    :Bob
        Reciever_name  :Dave
        Value          :100
timestamp      :1578989132.9128711
```

# 最後に
少し前に流行って以降あまり名前を聞かなくなったブロックチェーンですが、ソニーが著作権の管理に使用していたりマイクロソフトが個人IDに使用していたりと活用事例はまだまだ増えていますので勉強しておいて損はないかと思います。
今後はFlaskと連携させたものを実装する予定です。