🌏

ブロックチェーン(簡易版:Python)の実装(前半)

に公開

今日は、ブロックチェーン(簡易版)を実装しよーと思います。
ざっくりの仕組みを把握することを、目的にしてる感じです。
やり取りするのは、通貨ではなく感謝(単位は MIK)をイメージしてます♪
ややボリュームが多めになるので、2回に分けよーと思います。
では、前半いきまっしょい♪

今回やること

  1. ユーザー作成
  2. トランザクション作成(MIK を発行)
  3. トランザクション作成(MIK で感謝)
  4. トランザクション検証
  5. 実行

(後半予定)

  1. マイニング
  2. ブロックチェーン検証
  3. ブロックチェーン作成
  4. 実行

準備:インポート

block_chain.py
import binascii
from datetime import datetime
import json
import pprint
from ecdsa import BadSignatureError, SECP256k1, SigningKey, VerifyingKey

1. ユーザー鍵データ作成関数

block_chain.py
def make_key_data() -> dict:
    """ 
    curve: SECP256k1
    return: dict(keys=['secret_key_str', 'public_key_str'])
    """
    secret_key = SigningKey.generate(curve=SECP256k1)
    secret_key_str = secret_key.to_string().hex()
    public_key = secret_key.verifying_key
    public_key_str = public_key.to_string().hex()
    key_data = {
        'secret_key_str': secret_key_str,
        'public_key_str': public_key_str
    }
    return key_data

2. トランザクション作成関数1(MIK を発行)

block_chain.py
def make_mikoto_trasaction(receiver_public_key_str: str, MIK: int) -> dict:
    """
    MIK 発行用トランザクションを作成
    return: dict(keys=['time', 'sender', 'receiver', 'MIK', 'signature'])
    sender, signature = 'mikoto_project'
    """
    mikoto_transaction = {
        "time": datetime.now().isoformat(),
        "sender": "mikoto_project",
        "receiver": receiver_public_key_str,
        "MIK": MIK,
        "signature": "mikoto_project",
    }
    return mikoto_transaction

3. トランザクション作成関数2(MIK で感謝)

block_chain.py
ef make_thanks_transaction(
        sender_secret_key_str: str, sender_public_key_str: str, 
        receiver_public_key_str: str, MIK: int) -> dict:
    """
    MIK 感謝用トランザクションを作成
    return: dict(keys=['time', 'sender', 'receiver', 'MIK', 'signature'])
    """
    thanks_transaction = {
        "time": datetime.now().isoformat(),
        "sender": sender_public_key_str,
        "receiver": receiver_public_key_str,
        "MIK": MIK,
    }
    sender_secret_key = SigningKey.from_string(
        binascii.unhexlify(sender_secret_key_str), curve=SECP256k1)
    signature = sender_secret_key.sign(
        json.dumps(thanks_transaction).encode('utf-8')).hex()
    thanks_transaction['signature'] = signature
    return thanks_transaction

4. トランザクション検証関数

block_chain.py
def verify_transaction(transaction: dict) -> bool:
    """ 
    トランザクションの signature を検証する
    return: bool
    print: error(BadSignatureError)
    """
    public_key_str = transaction['sender']
    public_key = VerifyingKey.from_string(binascii.unhexlify(public_key_str), curve=SECP256k1)
    # binascii.Error: Odd-length string
    # ecdsa.errors.MalformedPointError
    signature = binascii.unhexlify(transaction['signature'])
    # binascii.Error: Odd-length string
    copy_transaction = transaction.copy()
    copy_transaction.pop('signature')
    try:
        public_key.verify(signature, json.dumps(copy_transaction).encode('utf-8'))
        return True
    except BadSignatureError as e:
        print(e)
        return False

5. 実行

block_chain.py
if __name__ == "__main__":
    # ユーザー情報の辞書を作成
    name_list = ['Dog', 'Cat', 'Lion']
    user_info_dict = {}
    for name in name_list:
        user_info_dict[name] = make_key_data()
    
    transaction_pool = []
    # mikoto_project -> Dog: 100MIK
    transaction_pool.append(
        make_mikoto_trasaction(user_info_dict['Dog']['public_key_str'], 100)
    )
    # Dog -> Cat: 10MIK, Dog -> Lion: 20MIK
    transaction_pool.append(
        make_thanks_transaction(
            user_info_dict['Dog']['secret_key_str'],
            user_info_dict['Dog']['public_key_str'],
            user_info_dict['Cat']['public_key_str'],
            10
        )
    )
    transaction_pool.append(
        make_thanks_transaction(
            user_info_dict['Dog']['secret_key_str'],
            user_info_dict['Dog']['public_key_str'],
            user_info_dict['Lion']['public_key_str'],
            20
        )
    )
    print('トランザクション・プール')
    pprint.pprint(transaction_pool, sort_dicts=False)

    for transaction in transaction_pool:
        # 発行したものは検証しない
        if transaction["sender"] == "mikoto_project":
            continue
        else:
            # 検証結果を表示
            print(verify_transaction(transaction))

結果

参考文献など

Satoshi Nakamoto (2008), ビットコイン:P2P 電子通貨システム,
https://bitcoin.org/files/bitcoin-paper/bitcoin_jp.pdf, 論文
モヤっとデータサイエンティスト (2022), 『Python によるブロックチェーン開発教本』, 電子書籍
安田恒 (2023), 『ブロックチェーンを作る!』, 秀和システム, 書籍

以上になります!ありがとうございましたー♪

Discussion