Tutoriel Python Blockchain
Tutoriel Python Blockchain
La blockchain est le buzz actuel qui domine les tendances du développement logiciel. Le
développement et la conception de Blockchain impliquent trois composants majeurs: le client, le
mineur et la blockchain. Ce tutoriel vise à vous donner une compréhension précise du processus
de création de votre propre blockchain.
Tout passionné de programmation qui souhaite suivre le rythme de la récente tendance du
développement de la Blockchain peut tirer parti de ce tutoriel. Si vous êtes un apprenant
intéressé à apprendre les bases du développement Blockchain, ce didacticiel répond
parfaitement à vos besoins.
Ce tutoriel est écrit en supposant que l'apprenant a une idée sur la programmation en Python et
une idée de base sur la Blockchain. Si vous êtes nouveau dans l'un de ces concepts, nous vous
suggérons de choisir des tutoriels basés sur ces concepts avant de vous plonger dans ce tutoriel.
Client
Le client est celui qui achètera des marchandises auprès d'autres vendeurs. Le client lui-même
peut devenir vendeur et acceptera de l'argent de tiers 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, tout 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.
# 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 -
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.
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
return collections.OrderedDict({
'sender': identity,
'recipient': self.recipient,
'value': self.value,
'time' : self.time})
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')
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.
Créer plusieurs transactions
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.
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 didacticiel.
À 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.
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.
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 -
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.
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 = ""
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 = ""
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
)
block0 = Block()
block0.previous_block_hash = None
Nonce = None
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é.
Enfin, nous créons une blockchain comme nous le verrons dans le chapitre suivant.
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.
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.
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.
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.
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)
À 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.
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é.
Étape 2
Le niveau de difficulté doit être supérieur ou égal à 1, nous nous en assurons avec la déclaration
d'assertion suivante -
Étape 3
Nous créons un prefix variable en utilisant le niveau de difficulté défini.
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.
Lorsque vous exécutez le code ci-dessus, vous verrez la sortie similaire à celle ci-dessous -
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.
last_transaction_index = 0
Nous allons maintenant demander à notre premier mineur d'ajouter un bloc à la blockchain.
block = Block()
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
Notez que le premier paramètre du minefunction est un objet binaire. Nous hachons maintenant
le bloc entier et créons un condensé dessus.
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
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.
dump_blockchain(TPCoins)
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.
ICHI.PRO
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é.
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 -
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 -
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
return collections.OrderedDict({
'sender': identity,
'recipient': self.recipient,
'value': self.value,
'time' : self.time})
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')
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.
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.
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.
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.
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 -
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 = ""
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 = ""
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
)
block0 = Block()
block0.previous_block_hash = None
Nonce = None
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é.
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.
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 -
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.
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.
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)
À 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.
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é.
Étape 2
Le niveau de difficulté doit être supérieur ou égal à 1, nous nous en assurons avec la déclaration
d'assertion suivante -
Étape 3
Nous créons un prefix variable en utilisant le niveau de difficulté défini.
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 -
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.
Lorsque vous exécutez le code ci-dessus, vous verrez la sortie similaire à celle ci-dessous -
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.
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
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
Notez que le premier paramètre du minefunction est un objet binaire. Nous hachons maintenant le
bloc entier et créons un condensé dessus.
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
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.
dump_blockchain(TPCoins)
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.