Comment implémenter une structure de blockchain?
16 October 2017On a vu le rôle des Structures de Blockchain dans les systèmes de Consensus Décentralisé et comment ces structures évitent la falsification des données.
Aujourd’hui on va voir comment implémenter ces structures. Et à quoi ressemble le code.
On va prendre un moment loin des concepts et des algorithmes pour décrire un cas pratique. On va définir trois fonctions, trois briques de base: init
, append
et add
.
Cet article est le premier d’une série qui va décrire l’implémentation des 3 piliers de la Blockchain: Blockchain, P2P et Proof Of. Il est dispensable si vous avez déjà vu un des très bon exemples disponible en anglais comme Building Blockchain in Go ou Let’s Build the Tiniest Blockchain en Python.
Vous pouvez retrouver le projet sur github. C’est un projet éducationnel avec de nombreux commentaires. N’hésitez pas à partager vos feedbacks dans la page “Issues”.
Le code présenté est en Python, mais utilise des fonctionnalités familières de tout les dev. javascript / java / ruby / C / C#.
Init
On initialise une nouvelle instance de Blockchain:
J’omets les détails d’implémentation comme le format de la description ou le stockage sur le disque. Vous pouvez les retrouver dans le projet sur github.
Ce code initialise un dossier avec notre nouvelle Blockchain:
on crée un block initial, la genèse, qui a un parent “NUL”.
La fonction make_block
contient le coeur de la Structure de Blockchain:
hash_ = sha3(previous_hash_bytes, payload)
Cette ligne produit une empreinte cryptographique de l’état de la chaîne. Il repose sur l’empreinte de l’état précédent et l’opération en cours. C’est ce processus récursif qui nous protège de la falsification des données.
Démo avec Ouroboros:
On utilise le dossier /tmp/my-first-blockchain
pour stocker nos données:
› python main.py init \
--root /tmp/my-first-blockchain \
--payload "this is my genesis block"
e9838c2163a98514c45c7d2524446399e4e3c9f7a...
e9838c...
est l’empreinte du block que l’on vient de créer. Utilisez ce hash pour comparer la chaîne avec d’autre membres du réseau.
Dans le dossier /tmp/my-first-blockchain
vous pouvez voir:
La description:
› cat /tmp/my-first-blockchain/blockchain.desc
GENESIS: e9838c2163a98514c45c7d2524446399...
HEAD: e9838c2163a98514c45c7d2524446399e4e...
Elle contient une référence vers la tête de la chaîne et une référence vers la queue. Elles sont égales pour le moment.
Le premier Block:
› cat /tmp/my-first-blockchain/e9838c2163a98514c4....blck
00000000000000000000000000000000000000000...
this is my genesis block
Il contient une référence vers le block précédent. Ici des zéros pour signifier “RIEN”. Et la payload.
Noter que la blockchain ne force pas un format de payload. Du moment qu’on peut en calculer un hash cryptographique (l’empreinte), le système fonctionne.
Append
On ajoute un nouveau block:
On prépare un nouveau block en l’attachant au block en cours:
new_block = make_block(current_block_hash, payload)
Cette line montre la Chaîne: on attache chaque block au précédent.
Démo avec Ouroboros:
› python main.py append \
--root /tmp/my-first-blockchain \
"ALICE SENDS 1 ETHER TO CHUCK"
13ad91ad3ed5fbcefdd39801b3b7200eb54594e6c...
Encore une fois, Ouroboros affiche le hash du nouveau block qu’on peut partager avec le reste du réseau.
Ouroboros a mis à jour la description avec la nouvelle tête:
› cat /tmp/my-first-blockchain/blockchain.desc
GENESIS: e9838c2163a98514c45c7d2524446399...
HEAD: 13ad91ad3ed5fbcefdd39801b3b7200eb54...
Le nouveau block contient une référence vers le block précédent et la payload:
› cat /tmp/my-first-blockchain/13ad91ad3ed5fbcefd...blck
e9838c2163a98514c45c7d2524446399e4e3c9f7a...
ALICE SENDS 1 ETHER TO CHUCK
Add
C’est maintenant que la blockchain va briller! On va reproduire l’exemple sur la falsification des données.
Chuck envoie un mail à Bob:
from [email protected] to [email protected]
Salut Bob, Ajoute la payload suivante à ta blockchain: CHUCK SEND 1 ETHER TO BOB Le Hash: e7ed781fa5e07bf078cb825a51291491273665d458…
Bob utilise add
qui ajoute un nouveau block SI le hash proposé corresponds à celui qu’il a calculé:
› python main.py add \
--root /tmp/my-first-blockchain \
e7ed781fa5e07bf078cb825a51291491273665d458788... \
"CHUCK SEND 1 ETHER TO BOB"
e7ed781fa5e07bf078cb825a51291491273665d458...
Pas de problèmes, Chuck a envoyé un hash qui corresponds bien à l’état précédent de la chaîne de Bob et la payload.
Puis Alice envoye un mail:
from [email protected] to [email protected]
Salut Bob, Ajoute la payload suivante à ta blockchain: ALICE SEND 1 ETHER TO BOB Le Hash: 6647327c55df3a628086cfb64255c8daea8ddf5c18…
Bob fait un add
une fois de plus:
› python main.py add \
--root /tmp/my-first-blockchain \
6647327c55df3a628086cfb64255c8daea8ddf5c180c1... \
"ALICE SEND 1 ETHER TO BOB"
FAILED:
Traceback (most recent call last):
File "main.py", line 1, in <module>
from ouroboros import cli
...
raise HashDoNotMatchException()
ouroboros.blockchain.HashDoNotMatchException
Bob sait immédiatement que le hash fourni pas Alice ne corresponds pas à la combinaison de l’état précédent et de la payload. Il sait que leurs Blockchains ont divergées.
Grace a la structure de Blockchain ils détectés la tricherie d’un autre participant. Et pas eu besoin de partager tout l’historique. Tout est vérifié localement. Efficace.
La fonction add
est presque identique à append
. Elle vérifie le hash proposé pour s’assurer que les blockchain sont égales:
Finalement
Avec une cinquantaine de lignes de code et trois fonctions, on a vu les basiques pour implémenter une Blockchain! On a vu que c’est une liste chainée avec une fonction de hash cryptographique.
Nous voilà une étape plus proche du consensus distribué. Il nous manque deux composants: un protocol de réseaux P2P et un mécanisme de choix des blocks.
Abonnez-vous sur Twitter ou à notre mailing list, plus bas, pour recevoir les prochains articles!
Laurent Senta
I wrote software for large distributed systems, web applications, and even robots.
These days I focus on making developers, creators, and humans more productive through IPDX.co.