簡易ブロックチェーンの実装

ブロックチェーンの実装関連の記事で面白いものを見つけました

python3でブロックチェーンを作ってみる

この記事ではブロックチェーンを簡易化して実装するというものなんですが
今回はこの記事のコードを少し改良することを目指します

・固定のdifficultyを設定して、繰り返しhashを求める
・モジュールのインポートについて改良(記事のインポート方法では危険性がある)

先に、記事の内容でプログラミングをしてみたほうがいいかもしれません。
どこを改善したのかがわかりやすくなると思います。

では行きましょう

[code language=”python” title=”cryptocurrency_block.py”]
import hashlib as hasher

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

def hash_block(self):
sha = hasher.sha256()
sha.update((str(self.index) + str(self.timestamp) + str(self.data) + str(self.previous_hash) + str(self.nonce)).encode(‘utf-8’))
block_digest = sha.hexdigest()

while block_digest[0:5] != "00000":
self.nonce += 1
sha.update((str(self.index) + str(self.timestamp) + str(self.data) + str(self.previous_hash) + str(self.nonce)).encode(‘utf-8’))
block_digest = sha.hexdigest()

return block_digest

[/code]

ポイントは「nonce」が追加されたことです。
データ内容はそのままで、nonceだけをインクリメントしてゆき
digestが閾値よりも小さくなるまでnonceを変えてhash計算を繰り返します。

今回はblock_digestの頭5桁に0が連続して並ばないと、ブロックとして認めないというものにしてみました。
次回以降は、このdifficultyを時間を測定しながら動的に変えてみようと思います。

nonceを追加したことによって、他のファイルもやや変更する必要があります。
こんな感じです

[code language=”python” title=”cryptocurrency_genesis.py”]
# original module
import cryptocurrency_block as cb
# standard module
import datetime as date

def create_genesis_block():
# make genesis block -> index0

return cb.Block(0, date.datetime.now(), "Genesis Block", "0", 0)
[/code]

 

[code language=”python” title=”cryptocurrency_new_block.py”]
# original module
import cryptocurrency_block as cb
# standard module
import datetime as date

def next_block(last_block):
this_index = last_block.index + 1
this_timestamp = date.datetime.now()
this_data = "Hey! I’m block" + str(this_index)
this_hash = last_block.hash

this_nonce = 0

return cb.Block(this_index, this_timestamp, this_data, this_hash, this_nonce)
[/code]

 

[code language=”python” title=”cryptocurrency_blockchain.py”]
import cryptocurrency_genesis as cg
import cryptocurrency_new_block as cnb

blockchain = [cg.create_genesis_block()]
previous_block = blockchain[0]

num_of_blocks_to_add = 10

for i in range(0, num_of_blocks_to_add):
blocks_to_add = cnb.next_block(previous_block)
blockchain.append(blocks_to_add)
previous_block = blocks_to_add

print("Block {} has been added to the blockchain!".format(blocks_to_add.index))
print("Hash: {}\n".format(blocks_to_add.hash))

[/code]

という感じです。
変更点としてはnonceを入れたことによる対応くらいです

それとひとつ重要なのが、モジュールのimportで

import *

の構文を使っていないことです。
*を使ってimportするとそのまま呼び出すことができるので確かに便利ではあるのですが、複雑なプログラムになってくると、同じ名前のオブジェクトと重なってしまったり、いわゆるネームスペースの重複のようなことが起こってしまいます。

今回は簡易的なプログラミングということで使いやすさを重視されてのことだと思いますが、ちょっと拡張性のことを考えると僕が書いたような構文にしてimportするのがベターかと思います。

 

ちなみにこのプログラムを動かすと

Block 1 has been added to the blockchain!
Hash: 00000dcbf1b3ff54698ed1d27daa569bc5c28e6ba1185ca7dc72a6bc8f90098d

Block 2 has been added to the blockchain!
Hash: 000004e6beeca353fde81edd709ea2a2860ed9782d86770eb3c1d82ce5766bf4

Block 3 has been added to the blockchain!
Hash: 000008460aa6a5ccba6ddac56041b441ace38a30fc08dcfd85964f952e75cd13

Block 4 has been added to the blockchain!
Hash: 0000000683b6037c6dc33a9c584aade2a6fe4bff89659b9c1579ee3fbac0740d

Block 5 has been added to the blockchain!
Hash: 00000a00b1f5c6d19787ea36723bb41653f44c8f5037e54684e7d09e646a3600

Block 6 has been added to the blockchain!
Hash: 00000ff4ce3ca01bef12837d87b8afad159e89880bd44bafb5052f1e56a2f483

Block 7 has been added to the blockchain!
Hash: 0000045fde4023f99e06ebee9327abcd120302b217c444b38f1ee2e0e217114c

Block 8 has been added to the blockchain!
Hash: 000002c4407d6fe1d0a46085dd1fdc3ea3f60f12deaff1807713f09a195471a4

Block 9 has been added to the blockchain!
Hash: 00000a0dd1da07dfd3daee0a2ec5f835f58ff01885f7ac287eb1b970d8f9c35f

Block 10 has been added to the blockchain!
Hash: 000002cc4d7a5545e770b7e4b51c3bd9912dfcaa9fffc745a5a01ba2fb153fb8

[Finished in 100.0s]

 

と帰ってきます。
ちゃんと頭5桁が0になっていて、それなりの時間がかかっていますね。

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です