あにまるブログ


「あにまるAIらぼ」はDjangoで作成しています
ラボクオリティなので、
コードのご利用などは自己責任でお願いします

2025年6月12日19:43, みことプロジェクト
ブロックチェーン(簡易版)を Python で実装

最近は、プログラミング関連については、zenn ブログの方だけで、書いてきたんですが、どーも見てくれる人が少ないので、やっぱ、こっちでも書いていこーと思います!

zenn ブログと、ほぼ同じ内容になります。
https://zenn.dev/animalz/articles/c82f20acccd30f

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

今回やること(block_chain.py)


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

(後半予定)
1. マイニング
2. ブロックチェーン検証
3. ブロックチェーン作成
4. 実行

準備:インポート


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


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


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 を発行)


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 で感謝)


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. トランザクション検証関数


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. 実行


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), 『ブロックチェーンを作る!』, 秀和システム, 書籍

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

PV: 75
コメント投稿 ホーム