Saviez-vous que le Bitcoin est construit sur une Blockchain ? Aujourd’hui, nous allons construire une Blockchain avec Python à partir de zéro.

Qu’est-ce que la blockchain ?

En 2008, le document Bitcoin a été publié par un individu ou un groupe inconnu nommé Satoshi Nakamoto. Le bitcoin est apparu comme une version peer-to-peer de l’argent électronique qui permettait des transactions sans passer par des institutions centralisées (banques). La plupart des gens ne savent pas que dans ce même article, Satoshi a défini une méthode distribuée de stockage des informations, aujourd’hui connue sous le nom de Blockchain.

Blockchain technology
La technologie Blockchain

Pour simplifier, la blockchain est un registre numérique partagé et immuable qui stocke les transactions sur un réseau décentralisé d’ordinateurs.

Nous pouvons diviser la blockchain en deux termes simples :

  • Bloc : Un espace où nous stockons les transactions
  • Chaîne : Un ensemble d’enregistrements liés

La blockchain est ainsi définie comme une chaîne de blocs liés, où chaque bloc stocke une transaction effectuée avec des paramètres spécifiques.

Chaque bloc est construit au-dessus d’un autre bloc, créant ainsi une chaîne de blocs irréversible. En d’autres termes, chaque bloc dépend d’un autre. Il s’agit d’un système robuste et immuable dans lequel toute personne disposant des autorisations nécessaires peut vérifier l’intégrité.

La blockchain présente un ensemble intéressant de caractéristiques :

  • Immutabilité de l’historique
  • Persistance de l’information
  • Pas d’erreurs dans les données stockées

De nombreux systèmes reposent actuellement sur la blockchain, tels que les crypto-monnaies, les transferts d’actifs (NFT) et peut-être, dans un avenir proche, le vote.

Il convient de mentionner qu’une Blockchain Python ne doit pas être un programme complexe avec des milliers de lignes de code. À la base, il s’agit d’une liste de transactions liées les unes aux autres.

Bien sûr, il s’agit d’une brève explication, mais si vous voulez un guide complet, nous avons produit un tutoriel complet sur la blockchain pour les débutants. Ne manquez pas de le consulter.

Sans plus attendre, construisons une blockchain simple avec Python.

Construire une blockchain avec Python

Avant de commencer, définissons ce que nous allons faire dans ce tutoriel :

  • Construire un système de blockchain simple écrit en Python
  • Utiliser notre Blockchain avec des transactions préétablies représentées sous forme de chaînes de caractères
  • Tester l’immutabilité de notre Blockchain

Nous n’allons pas utiliser JSON mais des listes Python. Cela nous permettra de simplifier le processus et de nous concentrer sur l’application des concepts clés d’une Blockchain.

Ce dont vous aurez besoin pour suivre ce tutoriel :

  • Compréhension des classes et des méthodes en Python
  • Utilisation de base de la ligne de commande

Création de la classe Blockchain

Ouvrez votre éditeur de code préféré et créez un fichier main.py. C’est avec ce fichier que nous allons travailler.

Maintenant, importez hashlib, un module qui nous permet de créer des messages cryptés à sens unique. Les techniques de cryptographie comme le hachage permettent à Blockchain de créer des transactions sécurisées.

Une fonction de hachage est un algorithme qui prend des données (généralement une chaîne codée) et renvoie un identifiant unique, souvent appelé “digest” ou “signature” Cette dernière partie est essentielle ; avec une fonction de hachage, une légère différence dans l’entrée produit un identifiant radicalement différent en sortie. Nous verrons cela plus tard.

Pour l’instant, il suffit d’importer le module intégré hashlib :

# fichier main.py
"""
Une blockchain simple en Python
"""

import hashlib

Ce module inclut la plupart des algorithmes de hachage dont vous aurez besoin. Gardez à l’esprit que nous utiliserons la fonction hashlib.sha256().

Maintenant, entrons dans le GeekCoinBlock, notre nom de blockchain totalement original.

classe GeekCoinBlock :
    
    def __init__(self, previous_block_hash, transaction_list) :

        self.previous_block_hash = previous_block_hash
        self.transaction_list = transaction_list

        self.block_data = f"{' - '.join(transaction_list)} - {previous_block_hash}"
        self.block_hash = hashlib.sha256(self.block_data.encode()).hexdigest()

Je sais que cela peut donner lieu à un morceau de code encombrant. Décortiquons chaque partie dans la section suivante.

Explication du GeekCoinBlock

Tout d’abord, nous créons une classe nommée GeekCoinBlock, une enveloppe pour les objets qui auront certaines caractéristiques (attributs) et certains comportements (méthodes).

Ensuite, nous définissons la méthode __init__ (également appelée constructeur), qui est invoquée à chaque fois qu’un objet GeekCoinBlock est créé.

Cette méthode a trois paramètres :

  • self (l’instance de chaque objet)
  • previous_block_hash (une référence au bloc précédent)
  • transaction_list (une liste des transactions effectuées dans le bloc actuel).

Nous stockons le hachage précédent et la liste des transactions et créons une variable d’instance block_data sous la forme d’une chaîne de caractères. Cela ne se produit pas avec les vraies crypto-monnaies, dans lesquelles nous stockons ce type de données sous la forme d’un autre hachage, mais pour des raisons de simplicité, nous stockons chaque bloc de données sous la forme d’une chaîne de caractères.

Enfin, nous créons le block_hash, que d’autres blocs utiliseront pour continuer la chaîne. C’est ici que la hashlib devient pratique ; au lieu de créer une fonction de hachage personnalisée, nous pouvons utiliser la fonction pré-construite sha256 pour créer des blocs immuables.

Cette fonction reçoit des chaînes encodées (ou des octets) en tant que paramètres. C’est pourquoi nous utilisons la méthode block_data.encode(). Ensuite, nous appelons hexdigest() pour renvoyer les données encodées au format hexadécimal.

Je sais que tout cela peut vous sembler fastidieux, alors jouons avec hashlib dans un shell Python.

Dans [1]: import hashlib

Dans [2]: message = "Python est génial"

Dans [3]: h1 = hashlib.sha256(message.encode())

In <x>[4]</x>: h1
Out<x>[4]</x>: <sha256 ...="" object="" @="" 0x7efcd55bfbf0="">

In <x>[5]</x>: h1.hexdigest()
Out<x>[5]</x>: 'a40cf9cca ... 42ab97'

In [6]: h2 = hashlib.sha256(b "Python is not great")

Dans <x>[7]</x>: h2
Out<x>[7]</x>: <sha256 ...="" object="" @="" 0x7efcd55bfc90="">

In <x>[8]</x>: h2.hexdigest()
Out<x>[8]</x>: 'fefe510a6a ... 97e010c0ea34'</sha256></sha256>

Comme vous pouvez le constater, une légère modification de l’entrée, par exemple “Python is great” (Python est génial) à “Python is not great” (Python n’est pas génial), peut produire un hachage totalement différent. Tout cela est lié à l’intégrité de la blockchain. Si vous introduisez une petite modification dans une blockchain, son hachage changera radicalement. C’est la raison pour laquelle le dicton “Vous ne pouvez pas corrompre une blockchain” est vrai.

Utilisation de notre classe de blocs

Nous construirons une classe Blockchain complète plus tard, mais pour l’instant, utilisons notre classe Block pour créer une chaîne de blocs (Blockchain).

Dans le même fichier, créez quelques transactions composées de simples chaînes de caractères stockées dans des variables, par exemple :

classe GeekCoinBlock :
    ...

t1 = "Noah envoie 5 GC à Mark"
t2 = "Mark envoie 2.3 GC à James"
t3 = "James envoie 4.2 GC à Alisson"
t4 = "Alisson envoie 1,1 GC à Noah"

Bien sûr, GC fait référence à GeekCoin

Maintenant, construisez le premier bloc de notre Blockchain en utilisant la classe GeekCoinBlock et imprimez ses attributs. Tenez compte du fait que le paramètre previous_hash du bloc genesis (premier bloc qui précède les autres blocs) sera toujours une chaîne arbitraire ou un hash, dans ce cas, “firstblock”

block1 = GeekCoinBlock('firstblock', [t1, t2])

print(f "Données du bloc 1 : {block1.block_data}")
print(f "Bloc 1 hash : {block1.block_hash}")

Ensuite, nous faisons la même chose avec le deuxième bloc, mais en passant le hash du premier bloc comme argument previous_hash .

block2 = GeekCoinBlock(block1.block_hash, [t3, t4])

print(f "Données du bloc 2 : {block2.block_data}")
print(f "Bloc 2 hash : {block2.block_hash}")

Exécutons et analysons la sortie que nous obtenons de ce morceau de code. Une fois de plus, tapez dans votre terminal :

❯ python main.py
Données du bloc 1 : Noah envoie 5 GC à Mark - Mark envoie 2.3 GC à James - firstblock
Bloc 1 hash : 01e4e15242a9601725f4a86ca01fbddaaec7105b442955bb0efcadbfc759806d
Données du bloc 2 : James envoie 4,2 GC à Alisson - Alisson envoie 1,1 GC à Noah - 01e4e15242a9601725f4a86ca01fbddaaec7105b442955bb0efcadbfc759806d
Bloc 2 hash : 448c4306caf7f6937b0307f92f27fbea3bb73b3470363dee5026a1209dadcfa8

Pour l’instant, vous ne voyez que du texte et quelques hachages de 64 caractères, mais cela reprend à peu près le mécanisme d’une blockchain.

Vous commencez par un bloc de genèse, la base de tous les autres blocs.

N’importe qui peut valider l’intégrité de la chaîne, et c’est pourquoi la blockchain est un système si sûr. Par exemple, si nous modifions légèrement le contenu d’une transaction, disons :

t2 = "Mark sends 2.3 GC to James" -> t2 = "Mark sends 3.2 GC to James" 

Nous constatons un changement radical dans le hachage des blocs.

Données du bloc 1 : Noah envoie 5 GC à Mark - Mark envoie 3,2 GC à James - premier bloc
Hachage du bloc 1 : 7a990bf1d70230bf2dad6160496c0b3046da7a17b1281fd1d4c63d4eac58e78c
Données du bloc 2 : James envoie 4,2 GC à Alisson - Alisson envoie 1,1 GC à Noah - 7a990bf1d70230bf2dad6160496c0b3046da7a17b1281fd1d4c63d4eac58e78c
Bloc 2 hash : 569b977306ce88b53e001dca7ba00c03a51c60d6df4650e7657dcd136f2da0ac

Vous pouvez voir le projet actuel sur ce repo GitHub.

Coder une blockchain

Il n’est pas très intelligent de baser l’intégrité de notre système sur des variables codées à la main, nous avons donc besoin d’une autre approche.

Nous avons les blocs. Il est temps de construire une classe qui les réunit en une Blockchain.

Commençons par supprimer nos transactions précédentes et nos objets blocs, puis utilisons le code ci-dessous.

# main.py

classe Blockchain :
    def __init__(self) :
        self.chain = []
        self.generate_genesis_block()

    def generate_genesis_block(self) :
        self.chain.append(GeekCoinBlock("0", ['Genesis Block']))
    
    def create_block_from_transaction(self, transaction_list) :
        previous_block_hash = self.last_block.block_hash
        self.chain.append(GeekCoinBlock(previous_block_hash, transaction_list))

    def display_chain(self) :
        for i in range(len(self.chain)) :
            print(f "Données {i 1} : {self.chain<x>[i]</x>.block_data}")
            print(f "Hash {i 1} : {self.chain<x>[i]</x>.block_hash}\n")

    @propriété
    def last_block(self) :
        return self.chain[-1]

Il s’agit là encore d’un énorme morceau de code. Décomposons chaque partie :

  • self.chain – La liste dans laquelle tous les blocs sont enregistrés. Nous pouvons accéder à chaque bloc via des index de liste.
  • generate_genesis_block – Ajoute la genèse ou le premier bloc à la chaîne. Le hachage précédent du bloc est “0”, et la liste des transactions est simplement “Genesis Block”
  • create_block_from_transaction – Ceci nous permet d’ajouter des blocs à la chaîne avec seulement une liste de transactions. Il serait très ennuyeux de créer un bloc manuellement à chaque fois que nous voulons enregistrer une transaction
  • display_chain – Imprime la chaîne de blocs avec une boucle for
  • last_block – Une propriété qui nous permet d’accéder au dernier élément de la chaîne. Nous l’avons utilisé dans la méthode create_block_from_transaction.

Testons cette blockchain.

# main.py

import hashlib

classe GeekCoinBlock :
    ...


classe Blockchain :
    ...

t1 = "George envoie 3,1 GC à Joe"
t2 = "Joe envoie 2,5 CG à Adam"
t3 = "Adam envoie 1,2 CG à Bob"
t4 = "Bob envoie 0,5 GC à Charlie"
t5 = "Charlie envoie 0,2 GC à David"
t6 = "David envoie 0,1 GC à Eric"

myblockchain = Blockchain()

myblockchain.create_block_from_transaction([t1, t2])
myblockchain.create_block_from_transaction([t3, t4])
myblockchain.create_block_from_transaction([t5, t6])

myblockchain.display_chain()

Maintenant, exécutez le fichier main.py .

Données 1 : Bloc Genesis - 0
Hash 1: 39331a6a2ea1cf31a5014b2a7c9e8dfad82df0b0666e81ce04cf8173cc5aed3e

Données 2 : George envoie 3,1 GC à Joe - Joe envoie 2,5 GC à Adam - 39331a6a2ea1cf31a5014b2a7c9e8dfad82df0b0666e81ce04cf8173cc5aed3e
Hash 2: 98cf363aecb33989aea0425a3c1287268bd86f63851bc08c0734a31db08506d5

Données 3 : Adam envoie 1,2 GC à Bob - Bob envoie 0,5 GC à Charlie - 98cf363aecb33989aea0425a3c1287268bd86f63851bc08c0734a31db08506d5
Hash 3: 6f1cfcc3082488b97db8fdf8ed33f9ac7519be3e285a37a6fcc2f1904f373589

Données 4 : Charlie envoie 0,2 GC à David - David envoie 0,1 GC à Eric - 6f1cfcc3082488b97db8fdf8ed33f9ac7519be3e285a37a6fcc2f1904f373589
Hash 4: 869df2f03c9860767d35b30a46233fbeea89a3000ae5019d1491e3829d1ab929

Félicitations ! 🙌 Vous venez de créer une Blockchain Python simple à partir de zéro.

Vous pouvez maintenant renforcer l’immutabilité de la Blockchain en utilisant des getters et setters et mettre en œuvre d’autres fonctionnalités comme la preuve de travail, le minage, ou tout autre concept que nous avons expliqué dans l’article sur les principes fondamentaux du minage de Bitcoin.

Conclusion

La blockchain est la technologie qui sous-tend le Bitcoin, l’Ethereum et toutes les autres crypto-monnaies existantes. Dans cet article, vous avez appris à créer une Blockchain avec Python en utilisant des algorithmes de hachage comme sha256, des classes et des objets.

Votre défi est de créer un système de minage, et pourquoi ne pas l’implémenter avec une API REST en utilisant des frameworks comme Django ou Flask ?

De nombreuses personnes font fortune grâce aux crypto-monnaies. Imaginez ce que vous pourriez faire si vous en créiez une par vous-même. 🤑

Continuez à coder ! 👨‍💻