ブロックチェーンの作り方。 パート1-作成、保存、同期、表示、マイニング、および証拠に基づく作業

すべての人に良い! ここで、私たちが学ぶべき完全に新しい方向、つまりブロックチェーンをゆっくりと探求し始め、 Pythonコースの一部として興味深いことが判明しました。 実際、私たちはあなたと共有したいものを。









Coinbaseアカウントのウォレット履歴から、最初のビットコインを取得したときに、2012年の登録ギフトとしての取引を見つけることができます。 当時のビットコインは約6.50ドルでした。 これらの0.1 BTCを保存しておけば、この記事を書いている時点では、すでに500ドル以上かかっていたでしょう。 誰かが興味を持っているなら、ビットコインが2000ドルの価値があるときにそれらを売りました。 だから、現在の550ドルではなく200ドルしか受け取っていません。 急ぐ必要はありません。



ビットコインの存在は知っていましたが、特に興味はありませんでした。 $ / BTCレートの最高値と最低値を見てきました。 私は人々が彼に未来があると言うのを見ました、そして、私はその完全な無意味についての記事を見ました。 しかし、私は個人的な意見を持っていませんでした-私はちょうど側から見ました。

同じように、私はほとんどブロックチェーンに従わなかった。 しかし最近、私の父は、CNBCとブルームバーグが午前中に見ているが、しばしばブロックチェーンについて話していることを何度も言及しており、彼はそれが何であるか分かりません。



そして、私は突然、このトピックについてもう少し深く理解する必要があることに気付きました。 そして、彼は「研究」から始めました-彼は彼らの本質を説明するインターネットで膨大な数の記事を読みました。 良いものもあれば、悪いものもあり、深いものもあり、非常に表面的なものもありました。



読書は十分ではありませんでした。確かに知っていることが1つあるとしたら、その読書はプログラミングが説明する100分の1を説明しません。 そして、私はあなた自身のローカルブロックチェーンを書く価値があることに気付きました。



私が説明する基本ブロックチェーンと「プロフェッショナル」ブロックチェーンには大きな違いがあることに留意してください。 このチェーンは暗号通貨を作成しません。 ブロックチェーンは、販売して物理的なお金と交換できるコインの生産を必要としません。

ブロックチェーンは、情報の保存と確認に使用されます。 コインはノードが検証に参加することを奨励しますが、ノードが存在する必要はありません。



私はいくつかの理由で投稿を書いています:1)それを読んだ人がブロックチェーンについてもっと学ぶことができるように。 2)コードを書くだけでなく、コードを説明することで理解を深めることができます。

この投稿では、ブロックチェーンデータを保存し、初期ブロックを生成し、ノードをローカルブロックチェーンデータと同期し、ブロックチェーン(後で他のノードと同期するために使用される)を表示し、有効な新しいブロックをマイニングして作成する方法を示します。 最初の投稿には他のノードはありません。 ウォレット、ピア、重要なデータはありません。 それらについては後で説明します。



一言で言えば



詳細に触れてコードを読みたくない場合、またはブロックチェーンを明確な言語で説明する記事を頼りにこの投稿に出会った場合は、それらがどのように機能するかを簡単に要約してみます。



最高レベルでは、ブロックチェーンは、ブロックチェーンに参加している全員がデータを保存、表示、確認、および削除できないデータベースです。



下位レベルでは、特定のブロックチェーンで許可されている限り、これらのブロックのデータは何でもかまいません。 たとえば、ビットコインブロックチェーンのデータは、アカウント間のビットコイントランザクションのみです。 Ethereumブロックチェーンは、同様のEtherトランザクションとコードの実行に使用されるトランザクションの両方を許可します。



ブロックが作成されてブロックチェーンに結合される前に、ブロックチェーンで作業しているほとんどの人がそれを確認します-それらはノードと呼ばれます。 真のブロックチェーンは、ほとんどのノードで確認されている膨大な数のブロックで構成されるチェーンです。 したがって、ノードが前のブロックのデータを変更しようとすると、新しいブロックは無効になり、ノードは誤ったブロックのデータを信頼しなくなります。



これが混乱している場合でも心配しないでください。 自分でこれを掘り下げるのに少し時間がかかり、そのような投稿を書くのにもっと時間がかかりました。そのため、私の妹(ブロックチェーンについて何も知らない)でさえ理解できます。



コードを学習する場合は、Githubのパート1スレッドをご覧ください。 質問、コメント、修正、および賞賛(特に良いことをしたい場合)を自由に送信するか、Twitterに投稿してください。



ステップ1-クラスとファイル



最初のステップは、ノードの起動時にブロックを処理するクラスを作成することです。 このクラスにBlockという名前を付けます。 正直なところ、あなたは多くのことをする必要はありません。 __init__関数では、必要なすべての情報が既に辞書に表示されていると信じています。 本番ブロックチェーンの場合、これは最も賢明な決定ではありませんが、コードを書くのは私だけなので、例として適しています。 また、ブロックの重要な情報をディクショナリにパックするメソッドを作成します。その後、ブロックを端末に出力するときに、ブロックの情報を表示するより便利な方法を紹介します。



class Block(object): def __init__(self, dictionary): ''' We're looking for index, timestamp, data, prev_hash, nonce ''' for k, v in dictionary.items(): setattr(self, k, v) if not hasattr(self, 'hash'): #in creating the first block, needs to be removed in future self.hash = self.create_self_hash() def __dict__(self): info = {} info['index'] = str(self.index) info['timestamp'] = str(self.timestamp) info['prev_hash'] = str(self.prev_hash) info['hash'] = str(self.hash) info['data'] = str(self.data) return info def __str__(self): return "Block<prev_hash: %s,hash: %s>" % (self.prev_hash, self.hash)
      
      





最初のブロックを作成するには、次の簡単なコードを実行します。



 def create_first_block(): # index zero and arbitrary previous hash block_data = {} block_data['index'] = 0 block_data['timestamp'] = date.datetime.now() block_data['data'] = 'First block data' block_data['prev_hash'] = None block = Block(block_data) return block
      
      





素晴らしい。 このパートの最後の質問は、ファイルシステムのどこにデータを保存するかです。 これは、ノードが切断されたときにブロックのローカルデータを失いたくない場合に必要です。

Etherium Mistフォルダースキームをある程度模倣して、データフォルダーに「chaindata」という名前を付けます。 各ブロックには、インデックスで名前が付けられた個別のファイルが割り当てられます。 ブロックが順番にリストされるように、ファイル名の先頭に十分なゼロが含まれていることを確認する必要があります。



上記のコードを考えると、最初のブロックを作成するために次を書く必要があります:



 #check if chaindata folder exists. chaindata_dir = 'chaindata' if not os.path.exists(chaindata_dir): #make chaindata dir os.mkdir(chaindata_dir) #check if dir is empty from just creation, or empty before if os.listdir(chaindata_dir) == []: #create first block first_block = create_first_block() first_block.self_save()
      
      





手順2-ローカルでのブロックチェーン同期



マイニング、データの解釈、またはチェーンの新しいデータの送信/作成を開始する前に、ノードを同期する必要があります。 私たちの場合、他のノードはないので、ローカルファイルからブロックを読み取ることについてのみ話します。 将来的には、同期の一部はファイルからの読み取りだけでなく、ノードが実行されていない間に生成されたブロックを収集するためのピアとの通信にもなります。



 def sync(): node_blocks = [] #We're assuming that the folder and at least initial block exists chaindata_dir = 'chaindata' if os.path.exists(chaindata_dir): for filename in os.listdir(chaindata_dir): if filename.endswith('.json'): #.DS_Store sometimes screws things up filepath = '%s/%s' % (chaindata_dir, filename) with open(filepath, 'r') as block_file: block_info = json.load(block_file) block_object = Block(block_info) #since we can init a Block object with just a dict node_blocks.append(block_object) return node_blocks
      
      





これまでのところ、シンプルで美しい。 ファイルから行を読み込んでデータ構造に読み込むには、過度に複雑なコードは必要ありません。 これが機能している間。 しかし、さまざまなノードの通信機能について書いている今後の投稿では、この同期機能はさらに複雑になります。



ステップ3-ブロックチェーンの表示



これでブロックチェーンがメモリ内にあるため、ブラウザにチェーンを表示したいと思います。 これを今すぐ行うには2つの理由があります。 まず、ブラウザで変更が行われたことを確認する必要があります。 第二に、私は将来ブラウザを使用して、ブロックチェーンに関連する操作を表示および実行します。 たとえば、トランザクションの送信やウォレットの管理。



これにはFlaskを使用します-エントリのしきい値が低く、目的に適していると判断しました。



以下は、jsonブロックチェーンを表示するためのコードです。 スペースを節約するために、インポートを無視します。



 node = Flask(__name__) node_blocks = sync.sync() #inital blocks that are synced @node.route('/blockchain.json', methods=['GET']) def blockchain(): ''' Shoots back the blockchain, which in our case, is a json list of hashes with the block information which is: index timestamp data hash prev_hash ''' node_blocks = sync.sync() #regrab the nodes if they've changed # Convert our blocks into dictionaries # so we can send them as json objects later python_blocks = [] for block in node_blocks: python_blocks.append(block.__dict__()) json_blocks = json.dumps(python_blocks) return json_blocks if __name__ == '__main__': node.run()
      
      





このコードを実行し、localhost:3000 / blockchain.jsonに移動すると、現在のブロックが表示されます。



ステップ4-「マイニング」、ブロック作成とも呼ばれる



これでブロックの生成のみが可能になりましたが、保存および配布する必要があるデータがさらにある場合は、これを新しいブロックに含める方法が必要です。 問題は、新しいブロックを作成して前のブロックに接続する方法です。



サトシは、これをビットコインのホワイトペーパーで次のように説明しています。 「タイムスタンプサーバー」は「ホスト」と呼ばれることに注意してください。



「タイムスタンプサーバーを使用してソリューションの説明を始めましょう。 彼の仕事は、タイムスタンプを置くデータブロックをハッシュし、このハッシュを公然と公開することです...タイムスタンプは、特定のデータが存在し、そのためブロックハッシュに陥ったことを示しています。 各ハッシュには以前のタイムスタンプが含まれます。これは、次のリンクが以前のすべてを強化するチェーンの構築方法です。



説明の下に添付されている画像のスクリーンショット:







セクションの主なアイデアは、必要に応じてブロックを接続することです。ブロックの作成時間、前のブロックのハッシュ、ブロック自体の情報など、新しいブロックに関する情報のハッシュを作成します。 このすべての情報をブロックの「ヘッダー」と呼びます。 したがって、ブロックの前にあるすべてのハッシュをカウントし、シーケンスを確認することにより、ブロックの正当性を確認できます。



この場合、作成するヘッダーは、文字列の値を1つの巨大な文字列に結合します。 次のデータを含めました。



  1. ブロックがどのアカウントであるかを示すインデックス。
  2. 前のブロックのハッシュ。
  3. データは単なるランダムな行です。 ビットコインの場合、マークルルートと呼ばれ、トランザクション情報が含まれます。
  4. このブロックのマイニングタイムスタンプ。


 def generate_header(index, prev_hash, data, timestamp): return str(index) + prev_hash + data + str(timestamp)
      
      





1つのポイントを説明します-ヘッダーを作成するために情報行を組み合わせる必要はありません。 要件は、誰もがブロックヘッダーとその中の前のブロックのハッシュを生成する方法を知っていることです。 これは、全員が新しいブロックのハッシュの正確性を検証し、2つのブロック間の接続を確認できるようにするために行われます。



ビットコインヘッダーは 、文字列の連結よりもはるかに複雑です。 ハッシュはデータと時間のハッシュを使用し、データがメモリ内でどのように配置されるかに関係しています。 しかし、私たちの場合、文字列を組み合わせるだけで十分です。



これでヘッダーができ、ハッシュの有効性を計算できます。 Bitcoinメソッドとは異なるメソッドを使用しますが、それでもsha256関数を介してブロックヘッダーを実行します。



 def calculate_hash(index, prev_hash, data, timestamp, nonce): header_string = generate_header(index, prev_hash, data, timestamp, nonce) sha = hashlib.sha256() sha.update(header_string) return sha.hexdigest()
      
      





ブロックをマイニングするには、上記の関数を使用してハッシュを取得し、それを新しいブロックに入れて、このブロックをchaindataディレクトリに保存します。



 node_blocks = sync.sync() def mine(last_block): index = int(last_block.index) + 1 timestamp = date.datetime.now() data = "I block #%s" % (int(last_block.index) + 1) #random string for now, not transactions prev_hash = last_block.hash block_hash = calculate_hash(index, prev_hash, data, timestamp) block_data = {} block_data['index'] = int(last_block.index) + 1 block_data['timestamp'] = date.datetime.now() block_data['data'] = "I block #%s" % last_block.index block_data['prev_hash'] = last_block.hash block_data['hash'] = block_hash return Block(block_data) def save_block(block): chaindata_dir = 'chaindata' filename = '%s/%s.json' % (chaindata_dir, block.index) with open(filename, 'w') as block_file: print new_block.__dict__() json.dump(block.__dict__(), block_file) if __name__ == '__main__': last_block = node_blocks[-1] new_block = mine(last_block) save_block(new_block)
      
      





できた! しかし、このタイプのブロック作成では、最速のCPUを持っている人なら誰でも、他のノードが正しいと考える最長のチェーンを作成できます。 次のブロックに進む前に、ブロックの作成速度を落として確認する方法が必要です。



ステップ5-仕事の証明



速度を落とすために、私はビットコインのようなProof of Workを使用します。 所有権の証明は 、コンセンサスを得るためにブロックチェーンで使用される別の方法ですが、この場合、作業を利用します。



これを行う方法は、ブロックハッシュの構造の要件を確立することです。 ビットコインと同様に、次のハッシュに進む前に、ハッシュが特定の数のゼロで始まることを確認する必要があります。 このために、ヘッダーに追加情報を追加する必要があります-ランダムにソートされた番号(nonce)。



 def generate_header(index, prev_hash, data, timestamp, nonce): return str(index) + prev_hash + data + str(timestamp) + str(nonce)
      
      





マイニング機能はハッシュを作成するように構成されていますが、ブロックハッシュに十分なゼロが含まれていない場合は、ノンス値を増やし、新しいヘッダーを作成し、新しいハッシュを計算して、十分なゼロがあるかどうかを確認します。



 NUM_ZEROS = 4 def mine(last_block): index = int(last_block.index) + 1 timestamp = date.datetime.now() data = "I block #%s" % (int(last_block.index) + 1) #random string for now, not transactions prev_hash = last_block.hash nonce = 0 block_hash = calculate_hash(index, prev_hash, data, timestamp, nonce) while str(block_hash[0:NUM_ZEROS]) != '0' * NUM_ZEROS: nonce += 1 block_hash = calculate_hash(index, prev_hash, data, timestamp, nonce) block_data = {} block_data['index'] = int(last_block.index) + 1 block_data['timestamp'] = date.datetime.now() block_data['data'] = "I block #%s" % last_block.index block_data['prev_hash'] = last_block.hash block_data['hash'] = block_hash block_data['nonce'] = nonce return Block(block_data)
      
      





素晴らしい。 新しいブロックには有効なナンスが含まれているため、他のノードはハッシュを確認できます。 新しいブロックを生成、保存し、残りに配布できます。



おわりに



それだけです! これまで。 ブロックチェーンには、まだ説明していない多くの質問と機能があります。



たとえば、他のノードの使用方法は? ブロックに含まれるノードはどのようにデータを送信しますか? 巨大なデータ文字列以外のデータを保存する他の方法はありますか?

これらの質問に対する回答は、私自身が回答を見つけ次第、この一連の投稿の次の部分で見つけることができます。 コンテンツのリクエストは、Twitter、投稿のコメント、またはフィードバックフォームで私に書くことができます!



ブロックチェーンに関する質問を明確にし、投稿の編集を手伝ってくれた妹のサラに感謝します!



終わり



コメントや質問は、いつものように、ここと開いたドアで歓迎されています。



All Articles