いまや知らない人はいない仮想通貨、別名暗号通貨(cryptocurrency)。
ドル円とは比べ物にならないほどの殺人的なボラティリティを見せているけれど、しばらくすれば落ち着いてくるんだろうか。
はっきりいって今の相場と税率でレバレッジ15倍とか正気の沙汰とは思えない。樹海の中に宝探しに行くようなものだ。
今回の記事の本題はその仮想通貨の仕組みについて。
投資にも興味はあるが、仮想通貨の仕組み自体にも興味がある。
仮想通貨の仕組みを知れば投資先の選択にも参考になるんじゃないかなと思うし、なにより以前から技術的に面白そうだと思っていた。
その仮想通貨の基盤となる技術がブロックチェーンというもので、これを理解しないことには始まらない。ということでファーストステップとしてブロックチェーンを理解するためにコードを写経してみた。
写経するのはid:mizchi氏の記事
コード自体はjavascriptで書かれているものを、アレンジを加えつつpython(python3.5)に書き直してみる。
(そっくりなタイトルを見てわかる通りまあただの写経。)
大元のソースはこれnaivechain/main.js at master · lhartikk/naivechain · GitHub
ザックリとした説明
- ブロックチェーンとはその名の通りブロックを鎖状に繋げたもの
- ブロックとは ①自身のID番号(ハッシュ値) ②前のブロックのID番号 ③その他(取引履歴など)の情報 を持つもの*1
ID番号は計算によって出てくるものなんだけど、計算するにあたって前のブロックのID番号や自身のブロックの情報を使うことになる。
なので途中のブロックの情報を書き換えるとそれ以降に続いているブロックのID番号が計算と合わなくなってしまう。これがブロックの書き換えができないと言われている大きな理由。
コード
blockchain.pyというファイル名で保存
import hashlib
import time
from datetime import datetime
class Block:
def __init__(self, index, previous_hash, data, timestamp, this_hash):
self.index = index
self.previous_hash = previous_hash
self.data = data
self.timestamp = timestamp
self.this_hash = this_hash
def equal(self, block):
if not self.index == block.index:
return False
elif not self.previous_hash == block.previous_hash:
return False
elif not self.data == block.data:
return False
elif not self.timestamp == block.timestamp:
return False
elif not self.this_hash == block.this_hash:
return False
return True
class Blockchain:
def __init__(self):
self.blockchain = [self.get_initial_block()]
def get_initial_block(self):
return Block(0,
"0",
"my genesis block!!",
1465154705,
"816534932c2b7154836da6afc367695e6337db8a921823784c14378abed4f7d7")
def get_length(self):
return len(self.blockchain)
def get_latest_block(self):
return self.blockchain[-1]
def generate_next_block(self, block_data):
previous_block = self.get_latest_block()
next_index = previous_block.index + 1
next_timestamp = int(time.mktime(datetime.now().timetuple()))
next_hash = calculate_hash(next_index, previous_block.this_hash, block_data, next_timestamp)
return Block(next_index, previous_block.this_hash, block_data, next_timestamp, next_hash)
def is_valid_new_block(self, new_block, previous_block):
if previous_block.index + 1 != new_block.index:
return False
elif previous_block.this_hash != new_block.previous_hash:
return False
elif calculate_hash_for_block(new_block) != new_block.this_hash:
return False
return True
def is_valid_chain(self):
if not self.blockchain[0].equal(self.get_initial_block()):
return False
else:
tmp_block = self.blockchain[0]
for i in range(1,self.get_length()):
if not self.is_valid_new_block(self.blockchain[i], tmp_block):
return False
else:
tmp_block = self.blockchain[i]
return True
def add_block(self, new_block):
if self.is_valid_new_block(new_block, self.get_latest_block()):
self.blockchain.append(new_block)
else:
raise ValueError("add block error!")
def calculate_hash(index, previous_hash, data, timestamp):
string = str(index) + previous_hash + data + str(timestamp)
return hashlib.sha256(string.encode('utf-8')).hexdigest()
def calculate_hash_for_block(block):
return calculate_hash(block.index, block.previous_hash, block.data, block.timestamp)
簡単に動かしてみる
同じフォルダ内で呼び出して使う
from blockchain import *
blockchain = Blockchain()
new_block = blockchain.generate_next_block("Hello World!")
try:
blockchain.add_block(new_block)
except ValueError as e:
print(e)
new_block = blockchain.generate_next_block("hoge")
try:
blockchain.add_block(new_block)
except ValueError as e:
print(e)
競合ブロックを作って追加するテスト
先ほどの続きに書く
もし何かの手違いで新しいブロックを生成するタイミングが被ってしまうとどうなるか、その時は同じ「前のブロックチェーンのID番号」を持ったブロックができてしまう。そのようなブロックを追加する場合はエラーが出て弾かれるようにしたい。*2
競合ブロックを作ってみて、2つ目のブロックが追加できないことを確認する
block1 = blockchain.generate_next_block("original block")
block2 = blockchain.generate_next_block("second block")
try:
blockchain.add_block(block1)
except ValueError as e:
print(e)
try:
blockchain.add_block(block2)
print("競合テストNG")
except ValueError as e:
print("競合テストOK!")
競合テストOK!
途中のブロックを書き換えるテスト
途中のブロックのデータを書き換えて、ブロックチェーンが不適切だと判定されることを確認する
print("-----Block data------")
for i in range(blockchain.get_length()):
print(blockchain.blockchain[i].data)
blockchain.blockchain[2].data = "invalid message!!!!"
print("-----Block data (changed)------")
for i in range(blockchain.get_length()):
print(blockchain.blockchain[i].data)
if not blockchain.is_valid_chain():
print("書き換えテストOK!")
else:
print("書き換えテストNG")
-----Block data------
my genesis block!!
Hello World!
hoge
original block
-----Block data (changed)------
my genesis block!!
Hello World!
invalid message!!!!
original block
書き換えテストOK!
おわり
ブロックチェーンについてはなんとなくわかった(気がする)。でもまだ、マイニングとは具体的になにをしてるんだ、どういう仕組みで仮想通貨の安全性が保たれるんだ、ビットコインと色々なアルトコインは技術的にどこが違うのか、みたいなところまでは全然わかってないのでそれはこれからの課題。