Blockchain Python - Guide rapide

Dans le tutoriel sur la blockchain, nous avons appris en détail la théorie derrière la blockchain. La blockchain est la pierre angulaire de la monnaie numérique Bitcoin la plus populaire au monde. Le didacticiel traitait en profondeur des subtilités de Bitcoin en expliquant pleinement l'architecture de la blockchain. La prochaine étape consiste à créer notre propre blockchain.

Satoshi Nakamoto a créé la première monnaie virtuelle au monde appelée Bitcoin. En regardant le succès de Bitcoin, beaucoup d'autres ont créé leurs propres monnaies virtuelles. Pour n'en nommer que quelques-uns - Litecoin, Zcash, etc.

Maintenant, vous pouvez également lancer votre propre devise. Appelons cela comme TPCoin (TutorialsPoint Coin). Vous écrirez une blockchain pour enregistrer toutes les transactions qui traitent de TPCoin. Le TPCoin peut être utilisé pour acheter des pizzas, des hamburgers, des salades, etc. Les possibilités sont infinies.

Dans ce tutoriel, laissez-nous comprendre comment construire un tel système et lancer votre propre monnaie numérique sur le marché.

Composants impliqués dans le développement de projets Blockchain

L'ensemble du développement du projet blockchain se compose de trois composants principaux -

  • Client
  • Miners
  • Blockchain

Client

Le client est celui qui achètera des marchandises auprès d'autres vendeurs. Le client lui-même peut devenir un vendeur et acceptera de l'argent d'autrui contre les marchandises qu'il fournit. Nous supposons ici que le client peut à la fois être un fournisseur et un destinataire de TPCoins. Ainsi, nous allons créer une classe de client dans notre code qui a la capacité d'envoyer et de recevoir de l'argent.

Mineur

Le mineur est celui qui récupère les transactions d'un pool de transactions et les assemble dans un bloc. Le mineur doit fournir une preuve de travail valide pour obtenir la récompense minière. Tout l'argent que le mineur perçoit à titre de redevance lui appartiendra. Il peut dépenser cet argent pour acheter des biens ou des services auprès d'autres fournisseurs enregistrés sur le réseau, comme le fait un client décrit ci-dessus.

Blockchain

Enfin, une Blockchain est une structure de données qui enchaîne tous les blocs extraits dans un ordre chronologique. Cette chaîne est immuable et donc résistante aux intempéries.

Vous pouvez suivre ce didacticiel en tapant le code présenté à chaque étape dans un nouveau bloc-notes Jupyter. Vous pouvez également télécharger l'intégralité du notebook Jupyter sur www.anaconda.com .

Dans le prochain chapitre, nous développerons un client qui utilise notre système blockchain.

Un client est une personne qui détient des TPCoins et qui les transige contre des biens / services d'autres fournisseurs sur le réseau, y compris le sien. Nous devrions définir unClientclasse à cet effet. Pour créer une identification unique au monde pour le client, nous utilisons PKI (Public Key Infrastructure). Dans ce chapitre, parlons-en en détail.

Le client doit pouvoir envoyer de l'argent de son portefeuille à une autre personne connue. De même, le client doit pouvoir accepter de l'argent d'un tiers. Pour dépenser de l'argent, le client créerait une transaction spécifiant le nom de l'expéditeur et le montant à payer. Pour recevoir de l'argent, le client fournira son identité au tiers - essentiellement un expéditeur de l'argent. Nous ne stockons pas le solde d'argent que le client détient dans son portefeuille. Lors d'une transaction, nous calculerons le solde réel pour nous assurer que le client dispose d'un solde suffisant pour effectuer le paiement.

Pour développer le Clientclasse et pour le reste du code du projet, nous devrons importer de nombreuses bibliothèques Python. Ceux-ci sont énumérés ci-dessous -

# 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

En plus des bibliothèques standard ci-dessus, nous allons signer nos transactions, créer le hachage des objets, etc. Pour cela, vous devrez importer les bibliothèques suivantes -

# 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

Dans le chapitre suivant, parlons de la classe client.

le Client classe génère le private et public clés en utilisant le Python intégré RSAalgorithme. Le lecteur intéressé peut se référer àthis tutorialpour la mise en œuvre de RSA. Lors de l'initialisation de l'objet, nous créons des clés privées et publiques et stockons leurs valeurs dans la variable d'instance.

self._private_key = RSA.generate(1024, random)
self._public_key = self._private_key.publickey()

Notez que vous ne devez jamais perdre votre clé privée. Pour la tenue de registres, la clé privée générée peut être copiée sur un stockage externe sécurisé ou vous pouvez simplement écrire la représentation ASCII de celle-ci sur un morceau de papier.

Le généré publicLa clé sera utilisée comme identité du client. Pour cela, nous définissons une propriété appeléeidentity qui renvoie la représentation HEX de la clé publique.

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

le identityest unique à chaque client et peut être rendu public. N'importe qui pourrait vous envoyer de la monnaie virtuelle en utilisant ceidentity et il sera ajouté à votre portefeuille.

Le code complet du Client la classe est affichée ici -

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 de test

Maintenant, nous allons écrire du code qui illustrera comment utiliser le Client classe -

Dinesh = Client()
print (Dinesh.identity)

Le code ci-dessus crée une instance de Client et l'affecte à la variable Dinesh. Nous imprimons la clé publique deDinesh en appelant son identityméthode. La sortie est affichée ici -

30819f300d06092a864886f70d010101050003818d0030818902818100b547fafceeb131e07
0166a6b23fec473cce22c3f55c35ce535b31d4c74754fecd820aa94c1166643a49ea5f49f72
3181ff943eb3fdc5b2cb2db12d21c06c880ccf493e14dd3e93f3a9e175325790004954c34d3
c7bc2ccc9f0eb5332014937f9e49bca9b7856d351a553d9812367dc8f2ac734992a4e6a6ff6
6f347bd411d07f0203010001

Maintenant, nous allons passer à la création d'une transaction dans le chapitre suivant.

Dans ce chapitre, créons un Transactionclasse afin qu'un client puisse envoyer de l'argent à quelqu'un. Notez qu'un client peut être à la fois un expéditeur ou un destinataire de l'argent. Lorsque vous souhaitez recevoir de l'argent, un autre expéditeur crée une transaction et spécifie votrepublicadresse dedans. Nous définissons l'initialisation d'une classe de transaction comme suit -

def __init__(self, sender, recipient, value):
   self.sender = sender
   self.recipient = recipient
   self.value = value
   self.time = datetime.datetime.now()

le init La méthode prend trois paramètres - l'expéditeur public clé, le destinataire publicet le montant à envoyer. Ceux-ci sont stockés dans les variables d'instance pour être utilisés par d'autres méthodes. De plus, nous créons une autre variable pour stocker l'heure de la transaction.

Ensuite, nous écrivons une méthode utilitaire appelée to_dictqui combine les quatre variables d'instance mentionnées ci-dessus dans un objet dictionnaire. Il s'agit simplement de mettre toutes les informations de transaction accessibles via une seule variable.

Comme vous le savez dans le tutoriel précédent, le premier bloc de la blockchain est un Genesisbloquer. Le bloc Genesis contient la première transaction initiée par le créateur de la blockchain. L'identité de cette personne peut être gardée secrète comme dans le cas des Bitcoins. Ainsi, lorsque cette première transaction est créée, le créateur peut simplement envoyer son identité en tant queGenesis. Ainsi, lors de la création du dictionnaire, nous vérifions si l'expéditeur estGenesiset si c'est le cas, nous attribuons simplement une valeur de chaîne à la variable d'identité; sinon, nous attribuons l'identité de l'expéditeur auidentity variable.

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

Nous construisons le dictionnaire en utilisant la ligne de code suivante

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

L'ensemble du code pour le to_dict méthode est montrée ci-dessous -

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})

Enfin, nous signerons cet objet dictionnaire en utilisant la clé privée de l'expéditeur. Comme précédemment, nous utilisons la PKI intégrée avec l'algorithme SHA. La signature générée est décodée pour obtenir la représentation ASCII pour l'impression et la stocker dans notre blockchain. lesign_transaction le code de la méthode est affiché ici -

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')

Nous allons maintenant tester ceci Transaction classe.

Test de la classe de transaction

Pour cela, nous allons créer deux utilisateurs, appelés Dinesh et Ramesh. Dinesh enverra 5 TPCoins à Ramesh. Pour cela, nous créons les clients appelés Dinesh et Ramesh.

Dinesh = Client()
Ramesh = Client()

N'oubliez pas que lorsque vous instanciez un Client classe, le public anddes clés privées uniques au client seraient créées. Comme Dinesh envoie le paiement à Ramesh, il aura besoin de la clé publique de Ramesh qui est obtenue en utilisant la propriété d'identité du client.

Ainsi, nous allons créer l'instance de transaction en utilisant le code suivant -

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

Notez que le premier paramètre est l'expéditeur, le deuxième paramètre est la clé publique du destinataire et le troisième paramètre est le montant à transférer. lesign_transaction La méthode récupère la clé privée de l'expéditeur à partir du premier paramètre pour chanter la transaction.

Une fois l'objet de transaction créé, vous le signerez en appelant son sign_transactionméthode. Cette méthode renvoie la signature générée au format imprimable. Nous générons et imprimons la signature en utilisant les deux lignes de code suivantes -

signature = t.sign_transaction()
print (signature)

Lorsque vous exécutez le code ci-dessus, vous verrez la sortie similaire à celle-ci -

7c7e3c97629b218e9ec6e86b01f9abd8e361fd69e7d373c38420790b655b9abe3b575e343c7
13703ca1aee781acd7157a0624db3d57d7c2f1172730ee3f45af943338157f899965856f6b0
0e34db240b62673ad5a08c8e490f880b568efbc36035cae2e748f1d802d5e8e66298be826f5
c6363dc511222fb2416036ac04eb972

Maintenant que notre infrastructure de base de création d'un client et d'une transaction est prête, nous aurons maintenant plusieurs clients effectuant plusieurs transactions comme dans une situation réelle.

Les transactions effectuées par différents clients sont mises en file d'attente dans le système; les mineurs récupèrent les transactions de cette file d'attente et les ajoutent au bloc. Ils exploiteront ensuite le bloc et le mineur gagnant aurait le privilège d'ajouter le bloc à la blockchain et ainsi gagner de l'argent pour lui-même.

Nous décrirons ce processus de minage plus tard lorsque nous discuterons de la création de la blockchain. Avant d'écrire le code pour plusieurs transactions, ajoutons une petite fonction utilitaire pour imprimer le contenu d'une transaction donnée.

Affichage de la transaction

le display_transactionLa fonction accepte un seul paramètre de type transaction. L'objet dictionnaire dans la transaction reçue est copié dans une variable temporaire appeléedict et à l'aide des touches de dictionnaire, les différentes valeurs sont imprimées sur la console.

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 ('-----')

Ensuite, nous définissons une file d'attente de transactions pour stocker nos objets de transaction.

File d'attente de transaction

Pour créer une file d'attente, nous déclarons un global list variable appelée transactions comme suit -

transactions = []

Nous ajouterons simplement chaque transaction nouvellement créée à cette file d'attente. Veuillez noter que par souci de concision, nous n'implémenterons pas la logique de gestion des files d'attente dans ce tutoriel.

Création de plusieurs clients

Maintenant, nous allons commencer à créer des transactions. Premièrement, nous allons créer quatre clients qui s'enverront de l'argent pour obtenir divers services ou biens de tiers.

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

À ce stade, nous avons quatre clients appelés Dinesh, Ramesh, Seema et Vijay. Nous supposons actuellement que chacun de ces clients détient des TPCoins dans son portefeuille pour effectuer des transactions. L'identité de chacun de ces clients serait spécifiée à l'aide de la propriété d'identité de ces objets.

Création de la première transaction

Maintenant, nous lançons notre première transaction comme suit -

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

Dans cette transaction, Dinesh envoie 5 TPCoins à Ramesh. Pour que la transaction réussisse, nous devrons nous assurer que Dinesh a suffisamment d'argent dans son portefeuille pour ce paiement. Notez que nous aurons besoin d'une transaction genesis pour démarrer la circulation de TPCoin dans le système. Vous écrirez le code de transaction pour cette transaction de genèse très rapidement au fur et à mesure que vous lirez.

Nous signerons cette transaction en utilisant la clé privée de Dinesh et l'ajouterons à la file d'attente des transactions comme suit -

t1.sign_transaction()
transactions.append(t1)

Après la première transaction effectuée par Dinesh, nous créerons plusieurs autres transactions entre différents clients que nous avons créées ci-dessus.

Ajouter plus de transactions

Nous allons maintenant créer plusieurs autres transactions, chaque transaction donnant quelques TPCoins à une autre partie. Quand quelqu'un dépense de l'argent, il n'est pas nécessaire qu'il doive vérifier les soldes suffisants dans ce portefeuille. De toute façon, le mineur validerait chaque transaction pour le solde de l'expéditeur lors du lancement de la transaction.

En cas de solde insuffisant, le mineur marquera cette transaction comme invalide et ne l'ajoutera pas à ce bloc.

Le code suivant crée et ajoute neuf autres transactions à notre file d'attente.

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)

Lorsque vous exécutez le code ci-dessus, vous aurez dix transactions dans la file d'attente pour que les mineurs créent leurs blocs.

Opérations de dumping

En tant que gestionnaire de blockchain, vous pouvez périodiquement souhaiter revoir le contenu de la file d'attente de transactions. Pour cela, vous pouvez utiliser ledisplay_transactionfonction que nous avons développée plus tôt. Pour vider toutes les transactions de la file d'attente, il suffit d'itérer la liste des transactions et pour chaque transaction référencée, appelez ledisplay_transaction fonction comme indiqué ici -

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

Les transactions sont séparées par une ligne pointillée pour les distinguer. Si vous exécutez le code ci-dessus, vous verrez la liste des transactions comme indiqué ci-dessous -

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
-----
--------------

Par souci de concision, je n'ai imprimé que les premières transactions de la liste. Dans le code ci-dessus, nous imprimons toutes les transactions commençant par la toute première transaction à l'exception de la transaction genesis qui n'a jamais été ajoutée à cette liste. Comme les transactions sont ajoutées périodiquement aux blocs, vous serez généralement intéressé à afficher uniquement la liste des transactions qui doivent encore être exploitées. Dans ce cas, vous devrez créer un fichier appropriéfor boucle pour parcourir les transactions qui ne sont pas encore minées.

Jusqu'à présent, vous avez appris à créer des clients, à les laisser entre eux et à maintenir une file d'attente des transactions en attente qui doivent être exploitées. Maintenant, vient la partie la plus importante de ce tutoriel et c'est la création d'une blockchain elle-même. Vous apprendrez cela dans la prochaine leçon.

Un bloc se compose d'un nombre variable de transactions. Pour simplifier, dans notre cas, nous supposerons que le bloc est constitué d'un nombre fixe de transactions, qui est de trois dans ce cas. Comme le bloc a besoin de stocker la liste de ces trois transactions, nous déclarerons une variable d'instance appeléeverified_transactions comme suit -

self.verified_transactions = []

Nous avons nommé cette variable comme verified_transactionspour indiquer que seules les transactions valides vérifiées seront ajoutées au bloc. Chaque bloc contient également la valeur de hachage du bloc précédent, de sorte que la chaîne de blocs devient immuable.

Pour stocker le hachage précédent, nous déclarons une variable d'instance comme suit -

self.previous_block_hash = ""

Enfin, nous déclarons une autre variable appelée Nonce pour stocker le nonce créé par le mineur pendant le processus d'extraction.

self.Nonce = ""

La définition complète du Block la classe est donnée ci-dessous -

class Block:
   def __init__(self):
      self.verified_transactions = []
      self.previous_block_hash = ""
      self.Nonce = ""

Comme chaque bloc a besoin de la valeur du hachage du bloc précédent, nous déclarons une variable globale appelée last_block_hash comme suit -

last_block_hash = ""

Créons maintenant notre premier bloc dans la blockchain.

Nous supposons que l'auteur des TPCoins donne initialement 500 TPCoins à un client connu Dinesh. Pour cela, il crée d'abord une instance Dinesh -

Dinesh = Client()

Nous créons ensuite une transaction genesis et envoyons 500 TPCoins à l'adresse publique de Dinesh.

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

Maintenant, nous créons une instance de Block classe et appelle-le block0.

block0 = Block()

Nous initialisons le previous_block_hash et Nonce variables d'instance à None, car il s'agit de la toute première transaction à être stockée dans notre blockchain.

block0.previous_block_hash = None
Nonce = None

Ensuite, nous ajouterons la transaction t0 ci-dessus au verified_transactions liste maintenue dans le bloc -

block0.verified_transactions.append (t0)

À ce stade, le bloc est complètement initialisé et est prêt à être ajouté à notre blockchain. Nous allons créer la blockchain à cet effet. Avant d'ajouter le bloc à la blockchain, nous allons hacher le bloc et stocker sa valeur dans la variable globale appeléelast_block_hashque nous avons déclaré précédemment. Cette valeur sera utilisée par le prochain mineur de son bloc.

Nous utilisons les deux lignes de codage suivantes pour hacher le bloc et stocker la valeur de résumé.

digest = hash (block0)
last_block_hash = digest

Enfin, nous créons une blockchain comme nous le verrons dans le chapitre suivant.

Une blockchain contient une liste de blocs enchaînés les uns aux autres. Pour stocker la liste entière, nous allons créer une variable de liste appelée TPCoins -

TPCoins = []

Nous écrirons également une méthode utilitaire appelée dump_blockchainpour vider le contenu de la blockchain entière. Nous imprimons d'abord la longueur de la blockchain afin de savoir combien de blocs sont actuellement présents dans la blockchain.

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

Notez qu'avec le temps, le nombre de blocs dans la blockchain serait extraordinairement élevé pour l'impression. Ainsi, lorsque vous imprimez le contenu de la blockchain, vous devrez peut-être décider de la plage que vous souhaitez examiner. Dans le code ci-dessous, nous avons imprimé la blockchain entière car nous n'ajouterions pas trop de blocs dans la démo actuelle.

Pour parcourir la chaîne, nous avons mis en place un for boucle comme suit -

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

Chaque bloc référencé est copié dans une variable temporaire appelée block_temp.

Nous imprimons le numéro de bloc comme en-tête pour chaque bloc. Notez que les nombres commenceraient par zéro, le premier bloc est un bloc de genèse numéroté zéro.

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

Dans chaque bloc, nous avons stocké une liste de trois transactions (à l'exception du bloc genesis) dans une variable appelée verified_transactions. Nous itérons cette liste dans unfor boucle et pour chaque élément récupéré, nous appelons display_transaction fonction pour afficher les détails de la transaction.

for transaction in block_temp.verified_transactions:
   display_transaction (transaction)

La définition complète de la fonction est présentée ci-dessous -

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 ('=====================================')

Notez qu'ici nous avons inséré les séparateurs aux points appropriés dans le code pour délimiter les blocs et les transactions qu'il contient.

Comme nous avons maintenant créé une blockchain pour stocker des blocs, notre tâche suivante est de créer des blocs et de commencer à les ajouter à la blockchain. Pour cela, nous ajouterons un bloc de genèse que vous avez déjà créé à l'étape précédente.

L'ajout d'un bloc à la blockchain implique l'ajout du bloc créé à notre TPCoins liste.

TPCoins.append (block0)

Notez que contrairement au reste des blocs du système, le bloc genesis ne contient qu'une seule transaction qui est initiée par l'expéditeur du système TPCoins. Maintenant, vous allez vider le contenu de la blockchain en appelant notre fonction globaledump_blockchain -

dump_blockchain(TPCoins)

Lorsque vous exécutez cette fonction, vous verrez la sortie suivante -

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
-----
--------------
=====================================

À ce stade, le système blockchain est prêt à être utilisé. Nous allons maintenant permettre aux clients intéressés de devenir des mineurs en leur fournissant une fonctionnalité de minage.

Pour permettre l'exploitation minière, nous devons développer une fonction minière. La fonctionnalité d'exploration de données doit générer un résumé sur une chaîne de message donnée et fournir une preuve de travail. Discutons-en dans ce chapitre.

Fonction de résumé de message

Nous écrirons une fonction utilitaire appelée sha256 pour créer un condensé sur un message donné -

def sha256(message):
return hashlib.sha256(message.encode('ascii')).hexdigest()

le sha256 fonction prend un message en tant que paramètre, l'encode en ASCII, génère un condensé hexadécimal et renvoie la valeur à l'appelant.

Fonction minière

Nous développons maintenant le minefonction qui met en œuvre notre propre stratégie minière. Notre stratégie dans ce cas serait de générer un hachage sur le message donné qui est préfixé avec un nombre donné de 1. Le nombre donné de 1 est spécifié comme paramètre pourmine fonction spécifiée comme niveau de difficulté.

Par exemple, si vous spécifiez un niveau de difficulté de 2, le hachage généré sur un message donné doit commencer par deux 1 - comme 11xxxxxxxx. Si le niveau de difficulté est 3, le hachage généré doit commencer par trois 1 - comme 111xxxxxxxx. Compte tenu de ces exigences, nous allons maintenant développer la fonction d'extraction comme indiqué dans les étapes ci-dessous.

Étape 1

La fonction d'exploration de données prend deux paramètres - le message et le niveau de difficulté.

def mine(message, difficulty=1):

Étape 2

Le niveau de difficulté doit être supérieur ou égal à 1, nous nous en assurons avec la déclaration d'assertion suivante -

assert difficulty >= 1

Étape 3

Nous créons un prefix variable en utilisant le niveau de difficulté défini.

prefix = '1' * difficulty

Notez que si le niveau de difficulté est 2, le préfixe sera «11» et si le niveau de difficulté est 3, le préfixe sera «111», et ainsi de suite. Nous vérifierons si ce préfixe existe dans le résumé généré du message. Pour digérer le message lui-même, nous utilisons les deux lignes de code suivantes -

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

Nous continuons d'ajouter un nouveau numéro iau hachage du message à chaque itération et générer un nouveau condensé sur le message combiné. En tant qu'entrée dusha256 fonction change à chaque itération, le digestla valeur changerait également. Nous vérifions si celadigest la valeur a dépassé prefix.

if digest.startswith(prefix):

Si la condition est remplie, nous mettrons fin au for boucle et retourne le digest valeur pour l'appelant.

L'ensemble mine le code est affiché ici -

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

Pour votre compréhension, nous avons ajouté le print instruction qui imprime la valeur de résumé et le nombre d'itérations nécessaires pour remplir la condition avant de revenir de la fonction.

Test de la fonction minière

Pour tester notre fonction d'exploration de données, exécutez simplement l'instruction suivante -

mine ("test message", 2)

Lorsque vous exécutez le code ci-dessus, vous verrez la sortie similaire à celle ci-dessous -

after 138 iterations found nonce:
11008a740eb2fa6bf8d55baecda42a41993ca65ce66b2d3889477e6bfad1484c

Notez que le résumé généré commence par «11». Si vous changez le niveau de difficulté à 3, le résumé généré commencera par «111», et bien sûr, il nécessitera probablement plus d'itérations. Comme vous pouvez le voir, un mineur avec plus de puissance de traitement pourra extraire un message donné plus tôt. C'est ainsi que les mineurs se font concurrence pour gagner leurs revenus.

Maintenant, nous sommes prêts à ajouter plus de blocs à notre blockchain. Apprenons cela dans notre prochain chapitre.

Chaque mineur récupérera les transactions d'un pool de transactions précédemment créé. Pour suivre le nombre de messages déjà extraits, nous devons créer une variable globale -

last_transaction_index = 0

Nous allons maintenant demander à notre premier mineur d'ajouter un bloc à la blockchain.

Ajout du premier bloc

Pour ajouter un nouveau bloc, nous créons d'abord une instance du Block classe.

block = Block()

Nous récupérons les 3 principales transactions de la file d'attente -

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

Avant d'ajouter la transaction au bloc, le mineur vérifiera la validité de la transaction. La validité de la transaction est vérifiée en testant l'égalité du hachage fourni par l'expéditeur par rapport au hachage généré par le mineur à l'aide de la clé publique de l'expéditeur. En outre, le mineur vérifiera que l'expéditeur dispose d'un solde suffisant pour payer la transaction en cours.

Par souci de concision, nous n'avons pas inclus cette fonctionnalité dans le didacticiel. Une fois la transaction validée, nous l'ajoutons auverified_transactions liste dans le block exemple.

block.verified_transactions.append (temp_transaction)

Nous incrémentons le dernier index de transaction afin que le prochain mineur récupère les transactions suivantes dans la file d'attente.

last_transaction_index += 1

Nous ajoutons exactement trois transactions au bloc. Une fois cela fait, nous initialiserons le reste des variables d'instance duBlockclasse. Nous ajoutons d'abord le hachage du dernier bloc.

block.previous_block_hash = last_block_hash

Ensuite, nous exploitons le bloc avec un niveau de difficulté de 2.

block.Nonce = mine (block, 2)

Notez que le premier paramètre du minefunction est un objet binaire. Nous hachons maintenant le bloc entier et créons un condensé dessus.

digest = hash (block)

Enfin, nous ajoutons le bloc créé à la blockchain et réinitialisons la variable globale last_block_hash pour l'utilisation dans le bloc suivant.

Le code complet pour ajouter le bloc est montré ci-dessous -

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

Ajouter plus de blocs

Nous allons maintenant ajouter deux blocs supplémentaires à notre blockchain. Le code pour ajouter les deux blocs suivants est donné ci-dessous -

# 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

Lorsque vous ajoutez ces deux blocs, vous verrez également le nombre d'itérations nécessaires pour trouver le Nonce. À ce stade, notre blockchain se compose au total de 4 blocs, y compris le bloc de genèse.

Décharger la blockchain entière

Vous pouvez vérifier le contenu de l'ensemble de la blockchain en utilisant la déclaration suivante -

dump_blockchain(TPCoins)

Vous verriez la sortie similaire à celle illustrée ci-dessous -

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
-----
--------------
=====================================

Dans ce tutoriel, nous avons appris à construire un projet blockchain en Python. Il existe de nombreux domaines dans lesquels vous devez ajouter des fonctionnalités supplémentaires à ce projet.

Par exemple, vous devrez écrire des fonctions pour gérer la file d'attente des transactions. Une fois les transactions minées et le bloc miné accepté par le système, elles n'ont plus besoin d'être stockées.

En outre, les mineurs préféreraient certainement récupérer les transactions avec les frais les plus élevés. Dans le même temps, vous devrez vous assurer que les transactions avec des frais faibles ou sans frais ne mourront pas de faim.

Vous devrez développer des algorithmes pour gérer la file d'attente. En outre, le didacticiel actuel n'inclut pas le code de l'interface client. Vous devrez développer cela pour les clients normaux et les mineurs. Le projet de blockchain à part entière se heurterait à plusieurs autres lignes de code et dépasse le cadre de ce didacticiel. Le lecteur intéressé peut télécharger la source Bitcoin pour une étude plus approfondie.

Conclusions

Ce didacticiel précis devrait vous aider à créer votre propre projet de blockchain.

Pour le développement de projets blockchain à part entière, vous pouvez en apprendre davantage sur la source Bitcoin .

Pour les projets commerciaux ou non commerciaux plus importants, vous pouvez envisager d'utiliser Ethereum - une plate-forme d'application blockchain prête à l'emploi.