今回はブロックチェーンのプログラムを
みていきたいと思います。

解説動画はこちら


 
今回は「ブロックチェーン」についてです。


ブロックチェーンとは

分散型台帳技術の一種であり、データを安全かつ
改ざん不可能な形で記録するための仕組みのことです。

連続するブロックで鎖のように構成されています
(参考:NTTデータ)

fig_02_01


最初のブロックは、ジェネシスブロックと呼ばれています。

各ブロックには次のような情報が格納されています。
・トランザクションデータ:取引の詳細情報
・タイムスタンプ:取引が行われた日時
・前のブロックのハッシュ:直前のブロックの暗号学的ハッシュ値
・現在のブロックのハッシュ:現在のブロックのデータから生成されたハッシュ値


ハッシュとは

取引情報やタイムスタンプなどから計算される数値のことです。
ハッシュ計算にはsha256(Secure Hash Algorithm 256-bit)などが使われています。

このハッシュ値を前のブロックの物と比較して
整合性をチェックしているので、改竄が難しくなっています。

ブロック1:データ + ハッシュ0(ジェネシスブロックのハッシュ)
ブロック2:データ + ハッシュ1
ブロック3:データ + ハッシュ2

チェーンの途中のブロックのデータを改竄すると
それ以降全てのハッシュ値を改竄しないといけないため
ものすごい難易度になります。


ブロックチェーンの簡単なプログラム

ブロックチェーンを作ってブロックを繋げるだけの
簡単なサンプルです。
import hashlib
import time

# ブロックを定義するクラス
class Block:
    def __init__(self, index, previous_hash, timestamp, data):
        self.index = index
        self.previous_hash = previous_hash
        self.timestamp = timestamp
        self.data = data
        self.hash = self.calculate_hash()

    def calculate_hash(self):
        sha = hashlib.sha256()
        sha.update((str(self.index) + str(self.previous_hash) + str(self.timestamp) + str(self.data)).encode('utf-8'))
        return sha.hexdigest()

# ブロックチェーンを定義するクラス
class Blockchain:
    def __init__(self):
        self.chain = [self.create_genesis_block()]

    def create_genesis_block(self):
        return Block(0, "0", int(time.time()), "Genesis Block")

    def get_latest_block(self):
        return self.chain[-1]

    def add_block(self, new_block):
        new_block.previous_hash = self.get_latest_block().hash
        new_block.hash = new_block.calculate_hash()
        self.chain.append(new_block)

# 最初のブロックチェーンの初期化
my_blockchain = Blockchain()

# 最初のブロックチェーンに新しいブロックを追加
my_blockchain.add_block(Block(1, "", int(time.time()), "Block 1 Data"))
my_blockchain.add_block(Block(2, "", int(time.time()), "Block 2 Data"))

# ブロックチェーンの内容を表示
for block in my_blockchain.chain:
    print(f"Index: {block.index}")
    print(f"Previous Hash: {block.previous_hash}")
    print(f"Timestamp: {block.timestamp}")
    print(f"Data: {block.data}")
    print(f"Hash: {block.hash}")
    print("-" * 30)
Index: 0
Previous Hash: 0
Timestamp: 1724488836
Data: Genesis Block
Hash: 042bf4db73e03d3047fe19aee7a9d5e4d95a446f8420f56704d2084f231f1350
------------------------------
Index: 1
Previous Hash: 042bf4db73e03d3047fe19aee7a9d5e4d95a446f8420f56704d2084f231f1350
Timestamp: 1724488836
Data: Block 1 Data
Hash: 3cff362cc92bcf78e7d78f0f01435ab18e17d0f543b57634953ee163b6d344f3
------------------------------
Index: 2
Previous Hash: 3cff362cc92bcf78e7d78f0f01435ab18e17d0f543b57634953ee163b6d344f3
Timestamp: 1724488836
Data: Block 2 Data
Hash: bbd7cdf536222d1b757061d459dd7c240dfef1eb311de3b1f5e1ca9f6dfae37e


ブロックの作成時にはHash値が計算され
ブロックには前のブロックのHash値も格納されています。


次は実際の取引っぽいデータでブロックを作り
ブロックチェーンの有効性も検証してみます。
import hashlib
import time
from typing import List

class Block:
    def __init__(self, index: int, previous_hash: str, timestamp: int, transactions: List[dict]):
        self.index = index
        self.previous_hash = previous_hash
        self.timestamp = timestamp
        self.transactions = transactions
        self.hash = self.calculate_hash()

    def calculate_hash(self):
        block_string = f"{self.index}{self.previous_hash}{self.timestamp}{self.transactions}"
        return hashlib.sha256(block_string.encode()).hexdigest()

class Blockchain:
    def __init__(self):
        self.chain = [self.create_genesis_block()]

    def create_genesis_block(self):
        return Block(0, "0", int(time.time()), [{"sender": "genesis", "receiver": "network", "amount": 0}])

    def get_latest_block(self):
        return self.chain[-1]

    def add_block(self, transactions: List[dict]):
        latest_block = self.get_latest_block()
        new_block = Block(latest_block.index + 1, latest_block.hash, int(time.time()), transactions)
        self.chain.append(new_block)

    def is_chain_valid(self):
        for i in range(1, len(self.chain)):
            current_block = self.chain[i]
            previous_block = self.chain[i-1]
            print(f"current_block.hash : {current_block.hash} , current_block.calculate_hash : {current_block.calculate_hash()}")
            print(f"current_block.previous_hash : {current_block.previous_hash} , previous_block.hash : {previous_block.hash}")
            if current_block.hash != current_block.calculate_hash():
                return False
            if current_block.previous_hash != previous_block.hash:
                return False
        return True

# ブロックチェーンの初期化
my_blockchain = Blockchain()

# 取引の例
transactions1 = [
    {"sender": "Alice", "receiver": "Bob", "amount": 50},
    {"sender": "Bob", "receiver": "Charlie", "amount": 30}
]
my_blockchain.add_block(transactions1)

transactions2 = [
    {"sender": "Alice", "receiver": "Charlie", "amount": 20},
    {"sender": "Charlie", "receiver": "Bob", "amount": 10}
]
my_blockchain.add_block(transactions2)

# ブロックチェーンの内容を表示
for block in my_blockchain.chain:
    print(f"Index: {block.index}")
    print(f"Previous Hash: {block.previous_hash}")
    print(f"Timestamp: {block.timestamp}")
    print(f"Transactions: {block.transactions}")
    print(f"Hash: {block.hash}")
    print("-" * 30)

# ブロックチェーンの有効性を検証
print("Is blockchain valid?", my_blockchain.is_chain_valid())
Index: 0 Previous Hash: 0 Timestamp: 1724483719 Transactions: [{'sender': 'genesis', 'receiver': 'network', 'amount': 0}] Hash: ec68f33868e558eca7f3fd6260101430eb12e7e8eb9b328a18882ef6f3ed229c ------------------------------ Index: 1 Previous Hash: ec68f33868e558eca7f3fd6260101430eb12e7e8eb9b328a18882ef6f3ed229c Timestamp: 1724483719 Transactions: [{'sender': 'Alice', 'receiver': 'Bob', 'amount': 50}, {'sender': 'Bob', 'receiver': 'Charlie', 'amount': 30}] Hash: 3a39a53e1423ece90ce7418689a3593959f3041e5b5c5ae7ddf3f95ec9264d25 ------------------------------ Index: 2 Previous Hash: 3a39a53e1423ece90ce7418689a3593959f3041e5b5c5ae7ddf3f95ec9264d25 Timestamp: 1724483719 Transactions: [{'sender': 'Alice', 'receiver': 'Charlie', 'amount': 20}, {'sender': 'Charlie', 'receiver': 'Bob', 'amount': 10}] Hash: b4e7a335791d6b846fba35dece29095f8c2792cde02b6a012403ab6322cd1132 ------------------------------ current_block.hash : 3a39a53e1423ece90ce7418689a3593959f3041e5b5c5ae7ddf3f95ec9264d25 , current_block.calculate_hash : 3a39a53e1423ece90ce7418689a3593959f3041e5b5c5ae7ddf3f95ec9264d25 current_block.previous_hash : ec68f33868e558eca7f3fd6260101430eb12e7e8eb9b328a18882ef6f3ed229c , previous_block.hash : ec68f33868e558eca7f3fd6260101430eb12e7e8eb9b328a18882ef6f3ed229c current_block.hash : b4e7a335791d6b846fba35dece29095f8c2792cde02b6a012403ab6322cd1132 , current_block.calculate_hash : b4e7a335791d6b846fba35dece29095f8c2792cde02b6a012403ab6322cd1132 current_block.previous_hash : 3a39a53e1423ece90ce7418689a3593959f3041e5b5c5ae7ddf3f95ec9264d25 , previous_block.hash : 3a39a53e1423ece90ce7418689a3593959f3041e5b5c5ae7ddf3f95ec9264d25 Is blockchain valid? True

現在のブロックのハッシュと計算されたハッシュ値
現在のブロックにある前のハッシュ値と前のブロックのハッシュ値
で整合性を見ています。





暗号通貨のマイニングの仕組み

マイニング(採掘)とは、分散型ネットワークにて新しい取引を検証し
それをブロックチェーンに追加するプロセスのことです。

特にビットコインなどのProof of Work(PoW)ベースの
暗号通貨において重要な役割を果たしています。

コンセンサスアルゴリズムと呼ばれる
新しいブロックの追加に合意するための仕組みが備わっており
ビットコインなどではProof of Work (PoW)と呼ばれるものが使われています。

Proof of Work (PoW):
計算能力を競い合い、最初に問題を解いたノードが
ブロックを追加する権利を得るというものです。
計算には莫大なリソースが必要になります。


マイニングの基本的な仕組み

ここではすごい荒く説明です。

1.取引の収集と検証:
各取引が有効であることを確認するために
デジタル署名や残高の確認などの検証が行われる

2.ブロックの形成:
検証された取引は、一定数集まると1つのブロックにまとめられる
ブロックには、取引情報の他に、前のブロックのハッシュ値、タイムスタンプ
ナンス(nonce)という特別な値が含まれる。

3.ハッシュ計算とナンスの探索:
マイナーは、ブロックヘッダー(ブロックの要約情報)に
対してハッシュ関数を適用し、ハッシュ値を計算する

目的は、そのハッシュ値が特定の条件(例えば、ハッシュ値が一定の数の先頭ゼロを持つこと)
を満たすようにすること

ナンスはこの条件を満たすために調整される値で
マイナーはナンスを変化させながら何度もハッシュ計算を繰り返します。

4.ブロックの追加:
条件を満たすハッシュ値が見つかると、そのブロックが承認され
ブロックチェーンに追加される

このプロセスを「プルーフ・オブ・ワーク」と呼び
計算量の多さがブロックの正当性を保証する

5.報酬の獲得:
ブロックを成功裏に追加したマイナーには
暗号通貨の新規発行分(ブロック報酬)や取引手数料などの報酬が与えられる

ビットコインの場合、最初のブロック(ジェネシスブロック)以降
約4年ごとにブロック報酬は半減する仕組み(半減期)が導入されている



マイニングのコード

ハッシュ計算とナンスの探索部分を難易度を下げて
実験してみます。


ハッシュを計算する際に
先頭に0が難易度の数値分並ぶかどうかを目的にしています。
0が並ぶまで計算を続け、ヒットしたらハッシュを追加します。

難易度の数値を上げると時間が掛かるようになります。


import hashlib
import time

class Block:
    def __init__(self, index, previous_hash, timestamp, data, nonce=0):
        self.index = index
        self.previous_hash = previous_hash
        self.timestamp = timestamp
        self.data = data
        self.nonce = nonce
        self.hash = self.calculate_hash()

    def calculate_hash(self):
        value = (str(self.index) + str(self.previous_hash) + str(self.timestamp) +
                 str(self.data) + str(self.nonce)).encode()
        return hashlib.sha256(value).hexdigest()

    def mine_block(self, difficulty):
        target = '0' * difficulty
        while self.hash[:difficulty] != target:
            self.nonce += 1
            self.hash = self.calculate_hash()
        print(f"Block mined: {self.hash}")

class Blockchain:
    def __init__(self):
        self.chain = [self.create_genesis_block()]
        self.difficulty = 5  # 難易度

    def create_genesis_block(self):
        return Block(0, "0", time.time(), "Genesis Block")

    def get_latest_block(self):
        return self.chain[-1]

    def add_block(self, new_block):
        new_block.previous_hash = self.get_latest_block().hash
        new_block.mine_block(self.difficulty)
        self.chain.append(new_block)

# ブロックチェーンの初期化
blockchain = Blockchain()

# 新しいブロックを追加
print("Mining block 1...")
new_block = Block(1, "", time.time(), "Block 1 Data")
blockchain.add_block(new_block)

print("Mining block 2...")
new_block = Block(2, "", time.time(), "Block 2 Data")
blockchain.add_block(new_block)

print("Mining block 3...")
new_block = Block(3, "", time.time(), "Block 3 Data")
blockchain.add_block(new_block)
Mining block 1...
Block mined: 00000b1dcfcdb93abbe9d2656e7c36851aae271bfcd45aecb3ec1a0f43474228
Mining block 2...
Block mined: 0000083671360216d051d4ca6a2fef3fc783e311ec3540a484a24a86c85471cb
Mining block 3...
Block mined: 000001d4692c5f50c4e90b74ce7a0bf87839de5893667b424846b8df1c7e5db4


なんとなくではありますが
マイニングの大変さが分かるかと思います。



まとめ

ブロックチェーン技術は暗号通貨の取引や
透明性、セキュリティ、分散化の特性により
今後さらに多くの分野での活用が期待されています。

正当性の証明や、改竄防止関連の仕事が
増えてくると予想しているので
覚えておくと使う機会が来るかもしれません。

それでは