Block ChainPython

【Python】ブロックチェーンの実装方法_4 Proof of Workの定義

Block Chain

どうも、月見(@Suzuka14144156)です。

私は、ブロックチェーンに関する研究をしており、本ブログでは仮想通貨/暗号資産の情報を整理して発信しています。

今回は、Pythonでブロックチェーンを実際に実装していきたいと思います。

参考にした講座は以下のUdemyの講座です。

【教育・学習】資格・学習
総合情報サイト「コレダ!」がお届けする教育・学習における資格・学習の総合情報サイトです。

こちらの講座は、Pythonでスクラッチでブロックチェーンを実装するというものです。

Pythonの中級者以上の向けの講座となっています。

ブロックチェーンだけでなく、クラスを使ったコーディングを覚えたい方にもオススメの講座だと思います。

前回までの私の記事は、こちらです。

今回は、前回からの続きですので、お読みでない方は、ぜひ参考にしてみてください。

今回は、Proof of Workの実装です。

Proof of Workとは?

  • Proof of Workとはコンセンサスアルゴリズムの一つ
  • コンセンサスアルゴリズムとは、暗号資産(仮想通貨)の基盤技術となるブロックチェーンがブロックを追加する際のルール

PoWは以下3つの要素を加算し、そのハッシュ値の最初の3桁が000(ケタ数は任意)になったときのchallengeの値をnouneに記述します。

このハッシュ値がどのようになったときを正しいとするかは、アルゴリズムによります。

今は、仮で000としています。

当然、ケタ数が多ければ多いほど、計算時間はかかります。

  • challenge
  • prev hash
  • transaction

challengeは正の整数です。

これを1、2…と代入していくことでnonceの値を探索するというアルゴリズムです。

Proof of Workの実装

それでは、早速実装します。

def valid_proof(self, transactions, previous_hash, nonce,
                    difficulty=MINING_DIFFICULTY):
        guess_block = utils.sorted_dict_by_key({
            'transactions': transactions,
            'nonce': nonce,
            'previous_hash': previous_hash
        })
        guess_hash = self.hash(guess_block)
        return guess_hash[:difficulty] == '0'*difficulty

valid_proofのメソッドにより、ハッシュ値が000の時は、Trueをリターンします。

def proof_of_work(self):
        transactions = self.transaction_pool.copy()
        previous_hash = self.hash(self.chain[-1])
        nonce = 0
        while self.valid_proof(transactions, previous_hash, nonce) is False:
            nonce += 1
        return nonce

proof_of_workのメソッドにより、valid_proofからTrueが帰ってくるまでnonceに+1を加算し続けます。

これによって、000になるときのnonceを探索するアルゴリズムとなります。

utils.py

import collections


def sorted_dict_by_key(unsorted_dict):
    return collections.OrderedDict(
        sorted(unsorted_dict.items(), key=lambda d: d[0]))

ディクショナリーのitemの順序を整列かさせるための関数です。

詳細は、以下の記事を参考にしてみてください。

blockchains.py

import hashlib
import json
import logging
import sys
import time

import utils

MINING_DIFFICULTY = 3

logging.basicConfig(level=logging.INFO, stream=sys.stdout)


class BlockChain(object):

    def __init__(self):
        self.transaction_pool = []
        self.chain = []
        self.create_block(0, self.hash({}))

    def create_block(self, nonce, previous_hash):
        block = utils.sorted_dict_by_key({
            'timestamp': time.time(),
            'transactions': self.transaction_pool,
            'nonce': nonce,
            'previous_hash': previous_hash
        })
        self.chain.append(block)
        self.transaction_pool = []
        return block

    def hash(self, block):
        sorted_block = json.dumps(block, sort_keys=True)
        return hashlib.sha256(sorted_block.encode()).hexdigest()

    def add_transaction(self, sender_blockchain_address,
                        recipient_blockchain_address, value):
        transaction = utils.sorted_dict_by_key({
            'sender_blockchain_address': sender_blockchain_address,
            'recipient_blockchain_address': recipient_blockchain_address,
            'value': float(value)
        })
        self.transaction_pool.append(transaction)
        return True

    def valid_proof(self, transactions, previous_hash, nonce,
                    difficulty=MINING_DIFFICULTY):
        guess_block = utils.sorted_dict_by_key({
            'transactions': transactions,
            'nonce': nonce,
            'previous_hash': previous_hash
        })
        guess_hash = self.hash(guess_block)
        return guess_hash[:difficulty] == '0'*difficulty

    def proof_of_work(self):
        transactions = self.transaction_pool.copy()
        previous_hash = self.hash(self.chain[-1])
        nonce = 0
        while self.valid_proof(transactions, previous_hash, nonce) is False:
            nonce += 1
        return nonce

        

def pprint(chains):
    for i, chain in enumerate(chains):
        print(f'{"="*25} Chain {i} {"="*25}')
        for k, v in chain.items():
            if k == 'transactions':
                print(k)
                for d in v:
                    print(f'{"-"*40}')
                    for kk, vv in d.items():
                        print(f' {kk:30}{vv}')
            else:
                print(f'{k:15}{v}')
    print(f'{"*"*25}')


if __name__ == '__main__':
    block_chain = BlockChain()
    pprint(block_chain.chain)

    block_chain.add_transaction('A','B', 1.0)
    previous_hash = block_chain.hash(block_chain.chain[-1])
    nonce = block_chain.proof_of_work()
    block_chain.create_block(nonce, previous_hash)
    pprint(block_chain.chain)

    block_chain.add_transaction('C','D', 2.0)
    block_chain.add_transaction('X','Y', 3.0)
    previous_hash = block_chain.hash(block_chain.chain[-1])
    nonce = block_chain.proof_of_work()
    block_chain.create_block(nonce, previous_hash)
    pprint(block_chain.chain)

実行結果は以下です。

========================= Chain 0 =========================
nonce          0
previous_hash  44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a
timestamp      1630818254.176903
transactions
*************************
========================= Chain 0 =========================
nonce          0
previous_hash  44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a
timestamp      1630818254.176903
transactions
========================= Chain 1 =========================
nonce          5699
previous_hash  4be633c7836d1242f81142e28bb26b1f720e76c8f7e52e366d272d85cb6f7e86
timestamp      1630818254.7045
transactions
----------------------------------------
 recipient_blockchain_address  B
 sender_blockchain_address     A
 value                         1.0
*************************
========================= Chain 0 =========================
nonce          0
previous_hash  44136fa355b3678a1146ad16f7e8649e94fb4fc21fe77e8310c060f61caaff8a
timestamp      1630818254.176903
transactions
========================= Chain 1 =========================
nonce          5699
previous_hash  4be633c7836d1242f81142e28bb26b1f720e76c8f7e52e366d272d85cb6f7e86
timestamp      1630818254.7045
transactions
----------------------------------------
 recipient_blockchain_address  B
 sender_blockchain_address     A
 value                         1.0
========================= Chain 2 =========================
nonce          4905
previous_hash  123d9ce45d48712365d1732f0c0eae276dfe75e615f031df5956053be56205c3
timestamp      1630818255.035936
transactions
----------------------------------------
 recipient_blockchain_address  D
 sender_blockchain_address     C
 value                         2.0
----------------------------------------
 recipient_blockchain_address  Y
 sender_blockchain_address     X
 value                         3.0
*************************

コメント

タイトルとURLをコピーしました