Python-blockchain-quick-guide

提供:Dev Guides
移動先:案内検索

Pythonブロックチェーン-はじめに

ブロックチェーンのチュートリアルでは、ブロックチェーンの背後にある理論について詳しく学びました。 ブロックチェーンは、世界で最も人気のあるデジタル通貨ビットコインの背後にある基本的な構成要素です。 チュートリアルでは、ブロックチェーンアーキテクチャを完全に説明するビットコインの複雑さを深く扱いました。 次のステップは、独自のブロックチェーンを構築することです。

中本atは、ビットコインと呼ばれる世界で最初の仮想通貨を作成しました。 ビットコインの成功を見て、他の多くの人が独自の仮想通貨を作成しました。 いくつかの例を挙げます-ライトコイン、Zcashなど。

また、独自の通貨を開始することもできます。 これをTPCoin(finddevguides Coin)と呼びます。 TPCoinを扱うすべてのトランザクションを記録するブロックチェーンを作成します。 TPCoinは、ピザ、ハンバーガー、サラダなどの購入に使用できます。 ネットワークに参加し、サービスを提供する通貨としてTPCoinを受け入れ始める他のサービスプロバイダーが存在する場合があります。 可能性は無限大。

このチュートリアルでは、このようなシステムを構築し、市場で独自のデジタル通貨を立ち上げる方法を理解してみましょう。

ブロックチェーンプロジェクト開発に関与するコンポーネント

ブロックチェーンプロジェクト全体の開発は、3つの主要なコンポーネントで構成されています-

  • クライアント
  • 鉱夫
  • ブロックチェーン

クライアント

クライアントは、他のベンダーから商品を購入する人です。 クライアント自身がベンダーになる可能性があり、彼が供給する商品に対して他人からお金を受け入れます。 ここでは、クライアントがTPCoinsのサプライヤと受信者の両方になることができると想定しています。 したがって、コードを使用して、お金を送受信できるクライアントクラスを作成します。

マイナー

マイナーは、トランザクションプールからトランザクションを取得し、ブロックにまとめます。 鉱夫は、マイニング報酬を得るために有効な作業証明を提供する必要があります。 鉱夫が手数料として徴収するすべてのお金は、彼が保持するためのものです。 上記のクライアントが行うのと同じように、彼はそのお金をネットワーク上の他の登録ベンダーから商品やサービスを購入するために使うかもしれません。

ブロックチェーン

最後に、ブロックチェーンは、すべてのマイニングされたブロックを時系列でチェーンするデータ構造です。 このチェーンは不変であるため、気性に強いです。

新しいJupyterノートブックの各ステップで表示されるコードを入力して、このチュートリアルに従うことができます。 または、https://www.anaconda.com/[www.anaconda.com]からJupyterノートブック全体をダウンロードすることもできます。

次の章では、ブロックチェーンシステムを使用するクライアントを開発します。

Pythonブロックチェーン-クライアントの開発

クライアントとは、TPCoinsを保持し、自分自身を含むネットワーク上の他のベンダーからの商品/サービスのトランザクションを処理する人です。 この目的のために Client クラスを定義する必要があります。 クライアントに対してグローバルに一意のIDを作成するには、PKI(公開キー基盤)を使用します。 この章では、これについて詳しく説明します。

クライアントは自分の財布から別の既知の人にお金を送ることができるはずです。 同様に、クライアントは第三者からお金を受け取ることができるはずです。 お金を使うために、クライアントは送信者の名前と支払額を指定するトランザクションを作成します。 お金を受け取るために、クライアントは、本質的にお金の送り主である第三者に身元を提供します。 私たちは、クライアントが彼の財布に保持する残高を保存しません。 トランザクション中に、実際の残高を計算して、クライアントが支払いを行うのに十分な残高があることを確認します。

*Client* クラスを開発し、プロジェクトの残りのコードのために、多くのPythonライブラリをインポートする必要があります。 これらは以下にリストされています-
# import libraries
import hashlib
import random
import string
import json
import binascii
import numpy as np
import pandas as pd
import pylab as pl
import logging
import datetime
import collections

上記の標準ライブラリに加えて、トランザクションに署名したり、オブジェクトのハッシュを作成したりします。 このためには、次のライブラリをインポートする必要があります-

# following imports are required by PKI
import Crypto
import Crypto.Random
from Crypto.Hash import SHA
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5

次の章では、クライアントクラスについて説明します。

Pythonブロックチェーン-クライアントクラス

*Client* クラスは、組み込みPython *RSA* アルゴリズムを使用して *private* および *public* キーを生成します。 興味のある読者は、RSAの実装について*このチュートリアル*を参照できます。 オブジェクトの初期化中に、秘密キーと公開キーを作成し、それらの値をインスタンス変数に保存します。
self._private_key = RSA.generate(1024, random)
self._public_key = self._private_key.publickey()

秘密鍵を紛失しないでください。 記録を保持するために、生成された秘密キーは、セキュリティで保護された外部ストレージにコピーするか、単にそのASCII表現を紙に書き留めます。

生成された*公開*キーは、クライアントのIDとして使用されます。 このために、公開鍵のHEX表現を返す identity というプロパティを定義します。

@property
   def identity(self):
      return
binascii.hexlify(self._public_key.exportKey(format='DER'))
.decode('ascii')
*identity* は各クライアントに固有であり、一般に公開できます。 誰もがこの *identity* を使用して仮想通貨を送信でき、ウォレットに追加されます。
  • クライアント*クラスの完全なコードはここに示されています-
class Client:
   def __init__(self):
      random = Crypto.Random.new().read
      self._private_key = RSA.generate(1024, random)
      self._public_key = self._private_key.publickey()
      self._signer = PKCS1_v1_5.new(self._private_key)

   @property
   def identity(self):
      return
binascii.hexlify(self._public_key.exportKey(format='DER')).decode('ascii')

テストクライアント

次に、 Client クラスの使用方法を示すコードを記述します-

Dinesh = Client()
print (Dinesh.identity)

上記のコードは Client のインスタンスを作成し、変数 Dinesh に割り当てます。 identity メソッドを呼び出して、 Dinesh の公開キーを出力します。 出力はここに示されています-

30819f300d06092a864886f70d010101050003818d0030818902818100b547fafceeb131e07
0166a6b23fec473cce22c3f55c35ce535b31d4c74754fecd820aa94c1166643a49ea5f49f72
3181ff943eb3fdc5b2cb2db12d21c06c880ccf493e14dd3e93f3a9e175325790004954c34d3
c7bc2ccc9f0eb5332014937f9e49bca9b7856d351a553d9812367dc8f2ac734992a4e6a6ff6
6f347bd411d07f0203010001

次に、次の章でトランザクションを作成します。

Pythonブロックチェーン-トランザクションクラス

この章では、クライアントが誰かにお金を送ることができるように Transaction クラスを作成しましょう。 クライアントは、お金の送信者または受信者の両方になることができることに注意してください。 お金を受け取りたいときは、他の送信者がトランザクションを作成し、その中に*公開*アドレスを指定します。 私たちは次のようにトランザクションクラスの初期化を定義します-

def __init__(self, sender, recipient, value):
   self.sender = sender
   self.recipient = recipient
   self.value = value
   self.time = datetime.datetime.now()
*init* メソッドは、送信者の*公開*キー、受信者の*公開*キー、および送信金額の3つのパラメーターを取ります。 これらは、他のメソッドで使用するためにインスタンス変数に保存されます。 さらに、トランザクションの時間を保存するためのもう1つの変数を作成します。

次に、上記の4つのインスタンス変数すべてをディクショナリオブジェクトに結合する to_dict というユーティリティメソッドを記述します。 これは、1つの変数を介してトランザクション情報全体にアクセスできるようにするためです。

前のチュートリアルで知っているように、ブロックチェーンの最初のブロックは Genesis ブロックです。 Genesisブロックには、ブロックチェーンの作成者によって開始された最初のトランザクションが含まれます。 この人物の身元は、ビットコインの場合のように秘密にされる場合があります。 したがって、この最初のトランザクションが作成されると、作成者は自分のIDを Genesis として送信するだけです。 したがって、ディクショナリの作成中に、送信者が Genesis であるかどうかを確認し、そうであれば、単純にID変数に何らかの文字列値を割り当てます。それ以外の場合は、送信者のIDを identity 変数に割り当てます。

if self.sender == "Genesis":
   identity = "Genesis"
else:
   identity = self.sender.identity

次のコード行を使用して辞書を作成します

return collections.OrderedDict({
   'sender': identity,
   'recipient': self.recipient,
   'value': self.value,
   'time' : self.time})
*to_dict* メソッドのコード全体を以下に示します-
def to_dict(self):
   if self.sender == "Genesis":
      identity = "Genesis"
   else:
      identity = self.sender.identity

   return collections.OrderedDict({
      'sender': identity,
      'recipient': self.recipient,
      'value': self.value,
      'time' : self.time})

最後に、送信者の秘密鍵を使用してこの辞書オブジェクトに署名します。 前と同様に、SHAアルゴリズムを備えた組み込みのPKIを使用します。 生成された署名はデコードされ、ASCII表現を取得して印刷し、ブロックチェーンに保存します。 sign_transaction メソッドのコードはここに示されています-

def sign_transaction(self):
   private_key = self.sender._private_key
   signer = PKCS1_v1_5.new(private_key)
   h = SHA.new(str(self.to_dict()).encode('utf8'))
   return binascii.hexlify(signer.sign(h)).decode('ascii')

この Transaction クラスをテストします。

トランザクションクラスのテスト

この目的のために、 Dinesh および Ramesh という2人のユーザーを作成します。 Dineshは、5つのTPCoinsをRameshに送信します。 最初に、DineshおよびRameshというクライアントを作成します。

Dinesh = Client()
Ramesh = Client()
*Client* クラスをインスタンス化すると、クライアントに固有の* publicおよび *privateキーが作成されることに注意してください。 DineshはRameshに支払いを送信するため、クライアントのidentityプロパティを使用して取得したRameshの公開キーが必要になります。

したがって、次のコードを使用してトランザクションインスタンスを作成します-

t = Transaction(
   Dinesh,
   Ramesh.identity,
   5.0
)

最初のパラメーターは送信者であり、2番目のパラメーターは受信者の公開鍵であり、3番目のパラメーターは転送される金額であることに注意してください。* sign_transaction *メソッドは、トランザクションを歌うための最初のパラメーターから送信者の秘密鍵を取得します。

トランザクションオブジェクトを作成したら、 sign_transaction メソッドを呼び出して署名します。 このメソッドは、生成された署名を印刷可能な形式で返します。 次の2行のコードを使用して署名を生成および印刷します-

signature = t.sign_transaction()
print (signature)

上記のコードを実行すると、次のような出力が表示されます-

7c7e3c97629b218e9ec6e86b01f9abd8e361fd69e7d373c38420790b655b9abe3b575e343c7
13703ca1aee781acd7157a0624db3d57d7c2f1172730ee3f45af943338157f899965856f6b0
0e34db240b62673ad5a08c8e490f880b568efbc36035cae2e748f1d802d5e8e66298be826f5
c6363dc511222fb2416036ac04eb972

クライアントとトランザクションを作成する基本的なインフラストラクチャの準備ができたので、実際の状況と同様に、複数のクライアントが複数のトランザクションを実行します。

複数のトランザクションを作成する

さまざまなクライアントによって行われたトランザクションは、システムのキューに入れられます。マイナーはこのキューからトランザクションを取得し、ブロックに追加します。 その後、彼らはブロックを採掘し、勝った採掘者はブロックをブロックチェーンに追加する特権を持ち、それによって自分のためにいくらかのお金を稼ぐでしょう。

このマイニングプロセスについては、後でブロックチェーンの作成について説明するときに説明します。 複数のトランザクションのコードを記述する前に、特定のトランザクションの内容を出力する小さなユーティリティ関数を追加しましょう。

トランザクションの表示

*display_transaction* 関数は、トランザクションタイプの単一のパラメーターを受け入れます。 受信したトランザクション内の辞書オブジェクトは *dict* という一時変数にコピーされ、辞書キーを使用して、さまざまな値がコンソールに出力されます。
def display_transaction(transaction):
   #for transaction in transactions:
   dict = transaction.to_dict()
   print ("sender: " + dict['sender'])
   print ('-----')
   print ("recipient: " + dict['recipient'])
   print ('-----')
   print ("value: " + str(dict['value']))
   print ('-----')
   print ("time: " + str(dict['time']))
   print ('-----')

次に、トランザクションオブジェクトを格納するためのトランザクションキューを定義します。

トランザクションキュー

キューを作成するには、次のように transactions と呼ばれるグローバル list 変数を宣言します-

transactions = []

新しく作成された各トランザクションをこのキューに追加するだけです。 簡潔にするため、このチュートリアルではキュー管理ロジックを実装しないことに注意してください。

複数のクライアントを作成する

ここで、トランザクションの作成を開始します。 最初に、他の人からさまざまなサービスや商品を入手するために互いにお金を送る4つのクライアントを作成します。

Dinesh = Client()
Ramesh = Client()
Seema = Client()
Vijay = Client()

この時点で、Dinesh、Ramesh、Seema、およびVijayという4つのクライアントがあります。 現在、これらの各クライアントは、取引のためにウォレットにTPCoinを保持していると想定しています。 これらの各クライアントのIDは、これらのオブジェクトのidentityプロパティを使用して指定されます。

最初のトランザクションの作成

今、私たちは次のように最初のトランザクションを開始します-

t1 = Transaction(
   Dinesh,
   Ramesh.identity,
   15.0
)

このトランザクションでは、Dineshは5つのTPCoinsをRameshに送信します。 取引を成功させるには、Dineshがこの支払いのために財布に十分なお金があることを確認する必要があります。 システムでTPCoinの循環を開始するには、ジェネシストランザクションが必要であることに注意してください。 この創世記トランザクションのトランザクションコードは、読み進めながらすぐに記述します。

Dineshの秘密鍵を使用してこのトランザクションに署名し、次のようにトランザクションキューに追加します-

t1.sign_transaction()
transactions.append(t1)

Dineshが最初に行ったトランザクションの後、上記で作成したさまざまなクライアント間にさらにいくつかのトランザクションを作成します。

トランザクションを追加する

ここでさらにいくつかのトランザクションを作成し、各トランザクションがいくつかのTPCoinを別のパーティに渡します。 誰かがお金を使うとき、彼はこの財布の十分な残高をチェックする必要はありません。 とにかくマイナーは、トランザクションを開始する間に送信者が持っている残高の各トランザクションを検証します。

残高が不足している場合、マイナーはこのトランザクションを無効としてマークし、このブロックに追加しません。

次のコードは、さらに9つのトランザクションを作成してキューに追加します。

t2 = Transaction(
   Dinesh,
   Seema.identity,
   6.0
)
t2.sign_transaction()
transactions.append(t2)
t3 = Transaction(
   Ramesh,
   Vijay.identity,
   2.0
)
t3.sign_transaction()
transactions.append(t3)
t4 = Transaction(
   Seema,
   Ramesh.identity,
   4.0
)
t4.sign_transaction()
transactions.append(t4)
t5 = Transaction(
   Vijay,
   Seema.identity,
   7.0
)
t5.sign_transaction()
transactions.append(t5)
t6 = Transaction(
   Ramesh,
   Seema.identity,
   3.0
)
t6.sign_transaction()
transactions.append(t6)
t7 = Transaction(
   Seema,
   Dinesh.identity,
   8.0
)
t7.sign_transaction()
transactions.append(t7)
t8 = Transaction(
   Seema,
   Ramesh.identity,
   1.0
)
t8.sign_transaction()
transactions.append(t8)
t9 = Transaction(
   Vijay,
   Dinesh.identity,
   5.0
)
t9.sign_transaction()
transactions.append(t9)
t10 = Transaction(
   Vijay,
   Ramesh.identity,
   3.0
)
t10.sign_transaction()
transactions.append(t10)

上記のコードを実行すると、鉱夫がブロックを作成するためのキューに10個のトランザクションができます。

トランザクションのダンプ

ブロックチェーンマネージャーとして、定期的にトランザクションキューの内容を確認することができます。 この目的のために、前に開発した display_transaction 関数を使用できます。 キュー内のすべてのトランザクションをダンプするには、トランザクションリストを繰り返し、参照された各トランザクションに対して、ここに示すように display_transaction 関数を呼び出します-

for transaction in transactions:
   display_transaction (transaction)
   print ('--------------')

トランザクションは区別のために破線で区切られています。 上記のコードを実行すると、トランザクションリストが以下のように表示されます-

sender:
30819f300d06092a864886f70d010101050003818d0030818902818100bb064c99c49214
4a9f463480273aba93ac1db1f0da3cb9f3c1f9d058cf499fd8e54d244da0a8dd6ddd329e
c86794b04d773eb4841c9f935ea4d9ccc2821c7a1082d23b6c928d59863407f52fa05d8b
47e5157f8fe56c2ce3279c657f9c6a80500073b0be8093f748aef667c03e64f04f84d311
c4d866c12d79d3fc3034563dfb0203010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100be93b516b28c6e
674abe7abdb11ce0fdf5bb728b75216b73f37a6432e4b402b3ad8139b8c0ba541a72c8ad
d126b6e1a1308fb98b727beb63c6060356bb177bb7d54b54dbe87aee7353d0a6baa93977
04de625d1836d3f42c7ee5683f6703259592cc24b09699376807f28fe0e00ff882974484
d805f874260dfc2d1627473b910203010001
-----
value: 15.0
-----
time: 2019-01-14 16:18:01.859915
-----
--------------
sender:
30819f300d06092a864886f70d010101050003818d0030818902818100bb064c99c49214
4a9f463480273aba93ac1db1f0da3cb9f3c1f9d058cf499fd8e54d244da0a8dd6ddd329e
c86794b04d773eb4841c9f935ea4d9ccc2821c7a1082d23b6c928d59863407f52fa05d8b
47e5157f8fe56c2ce3279c657f9c6a80500073b0be8093f748aef667c03e64f04f84d311
c4d866c12d79d3fc3034563dfb0203010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100a070c82b34ae14
3cbe59b3a2afde7186e9d5bc274955d8112d87a00256a35369acc4d0edfe65e8f9dc93fb
d9ee74b9e7ea12334da38c8c9900e6ced1c4ce93f86e06611e656521a1eab561892b7db0
961b4f212d1fd5b5e49ae09cf8c603a068f9b723aa8a651032ff6f24e5de00387e4d0623
75799742a359b8f22c5362e5650203010001
-----
value: 6.0
-----
time: 2019-01-14 16:18:01.860966
-----
--------------
sender:
30819f300d06092a864886f70d010101050003818d0030818902818100be93b516b28c6e
674abe7abdb11ce0fdf5bb728b75216b73f37a6432e4b402b3ad8139b8c0ba541a72c8ad
d126b6e1a1308fb98b727beb63c6060356bb177bb7d54b54dbe87aee7353d0a6baa93977
04de625d1836d3f42c7ee5683f6703259592cc24b09699376807f28fe0e00ff882974484
d805f874260dfc2d1627473b910203010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100cba097c0854876
f41338c62598c658f545182cfa4acebce147aedf328181f9c4930f14498fd03c0af6b0cc
e25be99452a81df4fa30a53eddbb7bb7b203adf8764a0ccd9db6913a576d68d642d8fd47
452590137869c25d9ff83d68ebe6d616056a8425b85b52e69715b8b85ae807b84638d8f0
0e321b65e4c33acaf6469e18e30203010001
-----
value: 2.0
-----
time: 2019-01-14 16:18:01.861958
-----
--------------

簡潔にするために、リストの最初のいくつかのトランザクションのみを印刷しました。 上記のコードでは、このリストに追加されなかったGenesisトランザクションを除き、最初のトランザクションから始まるすべてのトランザクションを出力します。 トランザクションは定期的にブロックに追加されるため、通常、まだマイニングされていないトランザクションのリストのみを表示することに関心があります。 その場合、適切な for ループを作成して、まだマイニングされていないトランザクションを繰り返す必要があります。

これまで、クライアントを作成し、クライアント間でそれらを許可し、マイニングされる保留中のトランザクションのキューを維持する方法を学習しました。 さて、このチュートリアルの最も重要な部分は、ブロックチェーン自体の作成です。 これについては、次のレッスンで学習します。

Pythonブロックチェーン-ブロッククラス

ブロックは、さまざまな数のトランザクションで構成されます。 簡単にするために、このケースでは、ブロックが固定数のトランザクション(この場合は3)で構成されていると仮定します。 ブロックはこれらの3つのトランザクションのリストを保存する必要があるため、次のように verified_transactions と呼ばれるインスタンス変数を宣言します-

self.verified_transactions = []

この変数に verified_transactions という名前を付けて、検証済みの有効なトランザクションのみがブロックに追加されることを示しています。 各ブロックは前のブロックのハッシュ値も保持するため、ブロックのチェーンは不変になります。

前のハッシュを保存するには、次のようにインスタンス変数を宣言します-

self.previous_block_hash = ""

最後に、マイニングプロセス中にマイナーによって作成されたナンスを格納するための Nonce という変数をもう1つ宣言します。

self.Nonce = ""
  • ブロック*クラスの完全な定義は以下のとおりです-
class Block:
   def __init__(self):
      self.verified_transactions = []
      self.previous_block_hash = ""
      self.Nonce = ""

各ブロックには前のブロックのハッシュの値が必要なので、次のように last_block_hash というグローバル変数を宣言します-

last_block_hash = ""

次に、ブロックチェーンの最初のブロックを作成しましょう。

Pythonブロックチェーン-ジェネシスブロックの作成

TPCoinsの発信者は、既知のクライアント Dinesh に500 TPCoinsを最初に提供すると想定しています。 このために、彼は最初にディネシュのインスタンスを作成します-

Dinesh = Client()

次に、ジェネシストランザクションを作成し、500 TPCoinsをDineshのパブリックアドレスに送信します。

t0 = Transaction (
   "Genesis",
   Dinesh.identity,
   500.0
)

ここで、 Block クラスのインスタンスを作成し、 block0 と呼びます。

block0 = Block()

これはブロックチェーンに保存される最初のトランザクションであるため、 previous_block_hash および Nonce インスタンス変数を None に初期化します。

block0.previous_block_hash = None
Nonce = None

次に、ブロック内に保持されている verified_transactions リストに上記のt0トランザクションを追加します-

block0.verified_transactions.append (t0)

この時点で、ブロックは完全に初期化され、ブロックチェーンに追加する準備ができています。 この目的のためにブロックチェーンを作成します。 ブロックをブロックチェーンに追加する前に、ブロックをハッシュし、その値を以前に宣言した last_block_hash と呼ばれるグローバル変数に保存します。 この値は、ブロック内の次のマイナーによって使用されます。

次の2行のコーディングを使用して、ブロックをハッシュし、ダイジェスト値を保存します。

digest = hash (block0)
last_block_hash = digest

最後に、次の章で見るようにブロックチェーンを作成します。

Pythonによるブロックチェーンの作成

ブロックチェーンには、相互にチェーンされたブロックのリストが含まれます。 リスト全体を保存するには、TPCoinsというリスト変数を作成します-

TPCoins = []

また、ブロックチェーン全体の内容をダンプするための dump_blockchain と呼ばれるユーティリティメソッドを作成します。 最初にブロックチェーンの長さを出力し、ブロックチェーンに現在いくつのブロックが存在するかを確認します。

def dump_blockchain (self):
   print ("Number of blocks in the chain: " + str(len (self)))

時間が経つにつれて、ブロックチェーン内のブロックの数が印刷のために非常に多くなることに注意してください。 したがって、ブロックチェーンの内容を印刷するときは、調査する範囲を決定する必要があります。 以下のコードでは、現在のデモでブロックを追加しすぎないように、ブロックチェーン全体を印刷しています。

チェーンを反復処理するには、次のように for ループを設定します-

for x in range (len(TPCoins)):
   block_temp = TPCoins[x]

参照される各ブロックは、 block_temp という一時変数にコピーされます。

各ブロックの見出しとしてブロック番号を印刷します。 番号はゼロから始まり、最初のブロックはゼロの番号が付けられたジェネシスブロックであることに注意してください。

print ("block # " + str(x))

各ブロック内で、3つのトランザクションのリスト(genesisブロックを除く)を verified_transactions と呼ばれる変数に保存しました。 このリストを for ループで繰り返し、取得した各アイテムに対して、 display_transaction 関数を呼び出してトランザクションの詳細を表示します。

for transaction in block_temp.verified_transactions:
   display_transaction (transaction)

関数定義全体は以下に示されています-

def dump_blockchain (self):
   print ("Number of blocks in the chain: " + str(len (self)))
   for x in range (len(TPCoins)):
      block_temp = TPCoins[x]
      print ("block # " + str(x))
      for transaction in block_temp.verified_transactions:
         display_transaction (transaction)
         print ('--------------')
      print ('=====================================')

ここでは、コード内のブロックとトランザクションを区切るために、コード内の適切なポイントにセパレーターを挿入していることに注意してください。

ブロックを保存するためのブロックチェーンを作成したので、次のタスクはブロックを作成し、ブロックチェーンへの追加を開始することです。 この目的のために、前の手順で既に作成したジェネシスブロックを追加します。

Pythonブロックチェーン-ジェネシスブロックの追加

ブロックチェーンにブロックを追加するには、作成したブロックを TPCoins リストに追加します。

TPCoins.append (block0)

システム内の残りのブロックとは異なり、ジェネシスブロックには、TPCoinsシステムの発信者によって開始されるトランザクションが1つしか含まれていないことに注意してください。 次に、グローバル関数 dump_blockchain を呼び出して、ブロックチェーンの内容をダンプします-

dump_blockchain(TPCoins)

この機能を実行すると、次の出力が表示されます-

Number of blocks in the chain: 1
block # 0
sender: Genesis
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100ed272b52ccb539
e2cd779c6cc10ed1dfadf5d97c6ab6de90ed0372b2655626fb79f62d0e01081c163b0864
cc68d426bbe9438e8566303bb77414d4bfcaa3468ab7febac099294de10273a816f7047d
4087b4bafa11f141544d48e2f10b842cab91faf33153900c7bf6c08c9e47a7df8aa7e60d
c9e0798fb2ba3484bbdad2e4430203010001
-----
value: 500.0
-----
time: 2019-01-14 16:18:02.042739
-----
--------------
=====================================

この時点で、ブロックチェーンシステムを使用する準備が整いました。 関心のあるクライアントがマイニング機能を提供することで、マイナーになれるようにします。

Pythonブロックチェーン-マイナーの作成

マイニングを有効にするには、マイニング機能を開発する必要があります。 マイニング機能では、特定のメッセージ文字列でダ​​イジェストを生成し、作業の証拠を提供する必要があります。 この章でこれについて議論しましょう。

メッセージダイジェスト機能

特定のメッセージのダイジェストを作成するための sha256 というユーティリティ関数を作成します-

def sha256(message):
return hashlib.sha256(message.encode('ascii')).hexdigest()
*sha256* 関数は *message* をパラメーターとして受け取り、ASCIIにエンコードし、16進数のダイジェストを生成して、呼び出し元に値を返します。

マイニング機能

現在、独自のマイニング戦略を実装する mine 関数を開発しています。 この場合の戦略は、特定の数の1がプレフィックスとして付加された特定のメッセージにハッシュを生成することです。 与えられた1の数は、難易度として指定された mine 関数のパラメーターとして指定されます。

たとえば、難易度2を指定した場合、特定のメッセージで生成されるハッシュは、11xxxxxxxxのように2つの1で始まる必要があります。 難易度が3の場合、生成されるハッシュは111xxxxxxxxのように3つの1で始まる必要があります。 これらの要件を考慮して、次に示す手順でマイニング機能を開発します。

ステップ1

マイニング機能は、メッセージと難易度の2つのパラメーターを取ります。

def mine(message, difficulty=1):

ステップ2

難易度は1以上である必要があり、次のアサート文でこれを保証します-

assert difficulty >= 1

ステップ3

設定された難易度を使用して prefix 変数を作成します。

prefix = '1' * difficulty

難易度が2の場合、プレフィックスは「11」になり、難易度が3の場合、プレフィックスは「111」になります。 生成されたメッセージのダイジェストにこのプレフィックスが存在するかどうかを確認します。 メッセージ自体をダイジェストするには、次の2行のコードを使用します-

for i in range(1000):
   digest = sha256(str(hash(message)) + str(i))

各反復でメッセージハッシュに新しい番号 i を追加し続け、結合されたメッセージに新しいダイジェストを生成します。 sha256 関数への入力が反復ごとに変わると、 digest 値も変わります。 この digest 値に上記の prefix が設定されているかどうかを確認します。

if digest.startswith(prefix):

条件が満たされた場合、 for ループを終了し、呼び出し元に digest 値を返します。

*mine* コード全体がここに表示されます-
def mine(message, difficulty=1):
   assert difficulty >= 1
   prefix = '1' * difficulty
   for i in range(1000):
      digest = sha256(str(hash(message)) + str(i))
      if digest.startswith(prefix):
         print ("after " + str(i) + " iterations found nonce: "+ digest)
      return digest

理解するために、ダイジェスト値と、関数から戻る前に条件を満たすためにかかった反復回数を出力する print ステートメントを追加しました。

マイニング機能のテスト

私たちのマイニング機能をテストするには、単に次のステートメントを実行します-

mine ("test message", 2)

上記のコードを実行すると、次のような出力が表示されます-

after 138 iterations found nonce:
11008a740eb2fa6bf8d55baecda42a41993ca65ce66b2d3889477e6bfad1484c

生成されたダイジェストは「11」で始まることに注意してください。 難易度を3に変更すると、生成されたダイジェストは「111」で始まります。もちろん、おそらくより多くの反復が必要になります。 ご覧のとおり、処理能力の高いマイナーは、特定のメッセージをより早くマイニングできます。 これが、採掘者が収入を得るために互いに競争する方法です。

これで、ブロックチェーンにさらにブロックを追加する準備が整いました。 次の章でこれを学びましょう。

Pythonブロックチェーン-ブロックの追加

各マイナーは、以前に作成されたトランザクションプールからトランザクションを取得します。 既にマイニングされたメッセージの数を追跡するには、グローバル変数を作成する必要があります-

last_transaction_index = 0

最初のマイナーがブロックをブロックチェーンに追加します。

最初のブロックの追加

新しいブロックを追加するには、まず Block クラスのインスタンスを作成します。

block = Block()

キューから上位3つのトランザクションを選択します-

for i in range(3):
   temp_transaction = transactions[last_transaction_index]
   # validate transaction

トランザクションをブロックに追加する前に、マイナーはトランザクションの有効性を検証します。 トランザクションの妥当性は、送信者の公開キーを使用してマイナーによって生成されたハッシュに対して送信者によって提供されたハッシュが等しいかどうかをテストすることにより検証されます。 また、マイナーは、送信者が現在のトランザクションの支払いに十分な残高があることを確認します。

簡潔にするため、この機能はチュートリアルに含めていません。 トランザクションが検証されたら、それを block インスタンスの verified_transactions リストに追加します。

block.verified_transactions.append (temp_transaction)

次のマイナーがキュー内の後続のトランザクションを取得できるように、最後のトランザクションインデックスをインクリメントします。

last_transaction_index += 1

ブロックに正確に3つのトランザクションを追加します。 これが完了したら、 Block クラスの残りのインスタンス変数を初期化します。 最初に最後のブロックのハッシュを追加します。

block.previous_block_hash = last_block_hash

次に、難易度2のブロックをマイニングします。

block.Nonce = mine (block, 2)
*mine* 関数の最初のパラメーターはバイナリオブジェクトであることに注意してください。 ブロック全体をハッシュし、ダイジェストを作成します。
digest = hash (block)

最後に、作成したブロックをブロックチェーンに追加し、次のブロックで使用するためにグローバル変数 last_block_hash を再初期化します。

ブロックを追加するためのコード全体を以下に示します-

block = Block()
for i in range(3):
   temp_transaction = transactions[last_transaction_index]
   # validate transaction
   # if valid
   block.verified_transactions.append (temp_transaction)
   last_transaction_index += 1

block.previous_block_hash = last_block_hash
block.Nonce = mine (block, 2)
digest = hash (block)
TPCoins.append (block)
last_block_hash = digest

ブロックを追加する

ブロックチェーンにさらに2つのブロックを追加します。 次の2つのブロックを追加するためのコードは以下のとおりです-

# Miner 2 adds a block
block = Block()

for i in range(3):
   temp_transaction = transactions[last_transaction_index]
   # validate transaction
   # if valid
   block.verified_transactions.append (temp_transaction)
   last_transaction_index += 1
block.previous_block_hash = last_block_hash
block.Nonce = mine (block, 2)digest = hash (block)
TPCoins.append (block)last_block_hash = digest
# Miner 3 adds a block
block = Block()

for i in range(3):
   temp_transaction = transactions[last_transaction_index]
   #display_transaction (temp_transaction)
   # validate transaction
   # if valid
   block.verified_transactions.append (temp_transaction)
   last_transaction_index += 1

block.previous_block_hash = last_block_hash
block.Nonce = mine (block, 2)
digest = hash (block)

TPCoins.append (block)
last_block_hash = digest

これらの2つのブロックを追加すると、Nonceを見つけるためにかかった反復回数も表示されます。 この時点で、ブロックチェーンはジェネシスブロックを含む合計4つのブロックで構成されています。

ブロックチェーン全体のダンプ

次のステートメントを使用して、ブロックチェーン全体の内容を確認できます-

dump_blockchain(TPCoins)

次のような出力が表示されます-

Number of blocks in the chain: 4
block # 0
sender: Genesis
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100ed272b52ccb539e2cd779
c6cc10ed1dfadf5d97c6ab6de90ed0372b2655626fb79f62d0e01081c163b0864cc68d426bbe943
8e8566303bb77414d4bfcaa3468ab7febac099294de10273a816f7047d4087b4bafa11f141544d4
8e2f10b842cab91faf33153900c7bf6c08c9e47a7df8aa7e60dc9e0798fb2ba3484bbdad2e44302
03010001
-----
value: 500.0
-----
time: 2019-01-14 16:18:02.042739
-----
--------------
=====================================
block # 1
sender:
30819f300d06092a864886f70d010101050003818d0030818902818100bb064c99c492144a9f463
480273aba93ac1db1f0da3cb9f3c1f9d058cf499fd8e54d244da0a8dd6ddd329ec86794b04d773e
b4841c9f935ea4d9ccc2821c7a1082d23b6c928d59863407f52fa05d8b47e5157f8fe56c2ce3279
c657f9c6a80500073b0be8093f748aef667c03e64f04f84d311c4d866c12d79d3fc3034563dfb02
03010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100be93b516b28c6e674abe7
abdb11ce0fdf5bb728b75216b73f37a6432e4b402b3ad8139b8c0ba541a72c8add126b6e1a1308f
b98b727beb63c6060356bb177bb7d54b54dbe87aee7353d0a6baa9397704de625d1836d3f42c7ee
5683f6703259592cc24b09699376807f28fe0e00ff882974484d805f874260dfc2d1627473b9102
03010001
-----
value: 15.0
-----
time: 2019-01-14 16:18:01.859915
-----
--------------
sender:
30819f300d06092a864886f70d010101050003818d0030818902818100bb064c99c492144a9f463
480273aba93ac1db1f0da3cb9f3c1f9d058cf499fd8e54d244da0a8dd6ddd329ec86794b04d773e
b4841c9f935ea4d9ccc2821c7a1082d23b6c928d59863407f52fa05d8b47e5157f8fe56c2ce3279
c657f9c6a80500073b0be8093f748aef667c03e64f04f84d311c4d866c12d79d3fc3034563dfb02
03010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100a070c82b34ae143cbe59b
3a2afde7186e9d5bc274955d8112d87a00256a35369acc4d0edfe65e8f9dc93fbd9ee74b9e7ea12
334da38c8c9900e6ced1c4ce93f86e06611e656521a1eab561892b7db0961b4f212d1fd5b5e49ae
09cf8c603a068f9b723aa8a651032ff6f24e5de00387e4d062375799742a359b8f22c5362e56502
03010001
-----
value: 6.0
-----
time: 2019-01-14 16:18:01.860966
-----
--------------
sender:
30819f300d06092a864886f70d010101050003818d0030818902818100be93b516b28c6e674abe7
abdb11ce0fdf5bb728b75216b73f37a6432e4b402b3ad8139b8c0ba541a72c8add126b6e1a1308f
b98b727beb63c6060356bb177bb7d54b54dbe87aee7353d0a6baa9397704de625d1836d3f42c7ee
5683f6703259592cc24b09699376807f28fe0e00ff882974484d805f874260dfc2d1627473b9102
03010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100cba097c0854876f41338c
62598c658f545182cfa4acebce147aedf328181f9c4930f14498fd03c0af6b0cce25be99452a81d
f4fa30a53eddbb7bb7b203adf8764a0ccd9db6913a576d68d642d8fd47452590137869c25d9ff83
d68ebe6d616056a8425b85b52e69715b8b85ae807b84638d8f00e321b65e4c33acaf6469e18e302
03010001
-----
value: 2.0
-----
time: 2019-01-14 16:18:01.861958
-----
--------------
=====================================
block # 2
sender:
30819f300d06092a864886f70d010101050003818d0030818902818100a070c82b34ae143cbe59b
3a2afde7186e9d5bc274955d8112d87a00256a35369acc4d0edfe65e8f9dc93fbd9ee74b9e7ea12
334da38c8c9900e6ced1c4ce93f86e06611e656521a1eab561892b7db0961b4f212d1fd5b5e49ae
09cf8c603a068f9b723aa8a651032ff6f24e5de00387e4d062375799742a359b8f22c5362e56502
03010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100be93b516b28c6e674abe7
abdb11ce0fdf5bb728b75216b73f37a6432e4b402b3ad8139b8c0ba541a72c8add126b6e1a1308f
b98b727beb63c6060356bb177bb7d54b54dbe87aee7353d0a6baa9397704de625d1836d3f42c7ee
5683f6703259592cc24b09699376807f28fe0e00ff882974484d805f874260dfc2d1627473b9102
03010001
-----
value: 4.0
-----
time: 2019-01-14 16:18:01.862946
-----
--------------
sender:
30819f300d06092a864886f70d010101050003818d0030818902818100cba097c0854876f41338c
62598c658f545182cfa4acebce147aedf328181f9c4930f14498fd03c0af6b0cce25be99452a81d
f4fa30a53eddbb7bb7b203adf8764a0ccd9db6913a576d68d642d8fd47452590137869c25d9ff83
d68ebe6d616056a8425b85b52e69715b8b85ae807b84638d8f00e321b65e4c33acaf6469e18e302
03010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100a070c82b34ae143cbe59b
3a2afde7186e9d5bc274955d8112d87a00256a35369acc4d0edfe65e8f9dc93fbd9ee74b9e7ea12
334da38c8c9900e6ced1c4ce93f86e06611e656521a1eab561892b7db0961b4f212d1fd5b5e49ae
09cf8c603a068f9b723aa8a651032ff6f24e5de00387e4d062375799742a359b8f22c5362e56502
03010001
-----
value: 7.0
-----
time: 2019-01-14 16:18:01.863932
-----
--------------
sender:
30819f300d06092a864886f70d010101050003818d0030818902818100be93b516b28c6e674abe7
abdb11ce0fdf5bb728b75216b73f37a6432e4b402b3ad8139b8c0ba541a72c8add126b6e1a1308f
b98b727beb63c6060356bb177bb7d54b54dbe87aee7353d0a6baa9397704de625d1836d3f42c7ee
5683f6703259592cc24b09699376807f28fe0e00ff882974484d805f874260dfc2d1627473b9102
03010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100a070c82b34ae143cbe59b
3a2afde7186e9d5bc274955d8112d87a00256a35369acc4d0edfe65e8f9dc93fbd9ee74b9e7ea12
334da38c8c9900e6ced1c4ce93f86e06611e656521a1eab561892b7db0961b4f212d1fd5b5e49ae
09cf8c603a068f9b723aa8a651032ff6f24e5de00387e4d062375799742a359b8f22c5362e56502
03010001
-----
value: 3.0
-----
time: 2019-01-14 16:18:01.865099
-----
--------------
=====================================
block # 3
sender:
30819f300d06092a864886f70d010101050003818d0030818902818100a070c82b34ae143cbe59b
3a2afde7186e9d5bc274955d8112d87a00256a35369acc4d0edfe65e8f9dc93fbd9ee74b9e7ea12
334da38c8c9900e6ced1c4ce93f86e06611e656521a1eab561892b7db0961b4f212d1fd5b5e49ae
09cf8c603a068f9b723aa8a651032ff6f24e5de00387e4d062375799742a359b8f22c5362e56502
03010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100bb064c99c492144a9f463
480273aba93ac1db1f0da3cb9f3c1f9d058cf499fd8e54d244da0a8dd6ddd329ec86794b04d773e
b4841c9f935ea4d9ccc2821c7a1082d23b6c928d59863407f52fa05d8b47e5157f8fe56c2ce3279
c657f9c6a80500073b0be8093f748aef667c03e64f04f84d311c4d866c12d79d3fc3034563dfb02
03010001
-----
value: 8.0
-----
time: 2019-01-14 16:18:01.866219
-----
--------------
sender:
30819f300d06092a864886f70d010101050003818d0030818902818100a070c82b34ae143cbe59b
3a2afde7186e9d5bc274955d8112d87a00256a35369acc4d0edfe65e8f9dc93fbd9ee74b9e7ea12
334da38c8c9900e6ced1c4ce93f86e06611e656521a1eab561892b7db0961b4f212d1fd5b5e49ae
09cf8c603a068f9b723aa8a651032ff6f24e5de00387e4d062375799742a359b8f22c5362e56502
03010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100be93b516b28c6e674abe7
abdb11ce0fdf5bb728b75216b73f37a6432e4b402b3ad8139b8c0ba541a72c8add126b6e1a1308f
b98b727beb63c6060356bb177bb7d54b54dbe87aee7353d0a6baa9397704de625d1836d3f42c7ee
5683f6703259592cc24b09699376807f28fe0e00ff882974484d805f874260dfc2d1627473b9102
03010001
-----
value: 1.0
-----
time: 2019-01-14 16:18:01.867223
-----
--------------
sender:
30819f300d06092a864886f70d010101050003818d0030818902818100cba097c0854876f41338c
62598c658f545182cfa4acebce147aedf328181f9c4930f14498fd03c0af6b0cce25be99452a81d
f4fa30a53eddbb7bb7b203adf8764a0ccd9db6913a576d68d642d8fd47452590137869c25d9ff83
d68ebe6d616056a8425b85b52e69715b8b85ae807b84638d8f00e321b65e4c33acaf6469e18e302
03010001
-----
recipient:
30819f300d06092a864886f70d010101050003818d0030818902818100bb064c99c492144a9f463
480273aba93ac1db1f0da3cb9f3c1f9d058cf499fd8e54d244da0a8dd6ddd329ec86794b04d773e
b4841c9f935ea4d9ccc2821c7a1082d23b6c928d59863407f52fa05d8b47e5157f8fe56c2ce3279
c657f9c6a80500073b0be8093f748aef667c03e64f04f84d311c4d866c12d79d3fc3034563dfb02
03010001
-----
value: 5.0
-----
time: 2019-01-14 16:18:01.868241
-----
--------------
=====================================

Pythonブロックチェーン-範囲と結論

このチュートリアルでは、Pythonでブロックチェーンプロジェクトを構築する方法を学びました。 このプロジェクトにさらに機能を追加する必要がある多くの領域があります。

たとえば、トランザクションキューを管理するための関数を作成する必要があります。 トランザクションがマイニングされ、マイニングされたブロックがシステムに受け入れられた後、トランザクションを保存する必要はありません。

また、鉱夫は確かに最高の手数料で取引を引き受けることを好むでしょう。 同時に、低料金または無料のトランザクションが永久に飢えないようにする必要があります。

キューを管理するためのアルゴリズムを開発する必要があります。 また、現在のチュートリアルには、クライアントインターフェイスコードは含まれていません。 通常のクライアントと鉱夫の両方のためにこれを開発する必要があります。 本格的なブロックチェーンプロジェクトでは、さらに数行のコードが実行されるため、このチュートリアルの範囲を超えています。 興味のある読者は、https://bitcoin.org/en/download [bitcoin source]をダウンロードして、さらに調査することができます。

結論

この鮮明なチュートリアルにより、独自のブロックチェーンプロジェクトの作成を開始できます。

本格的なブロックチェーンプロジェクト開発については、https://bitcoin.org/en/download [bitcoin source]から詳細を学ぶことができます。

大規模な商業プロジェクトまたは非商業プロジェクトの場合は、https://www.ethereum.org/[Ethereum]-すぐに使用できるブロックチェーンアプリプラットフォームの使用を検討できます。