Introduction à Ethereum pour les développeurs Python, partie 1
Alors, vous avez entendu parler de ce truc qu'est Ethereum et vous êtes prêt à vous aventurer dans le terrier du lapin ? Cet article couvrira rapidement quelques notions de base de la blockchain, puis vous fera interagir avec un nœud Ethereum simulé – lecture de données de blocs, vérification des soldes de compte et envoi de transactions. Chemin faisant, nous soulignerons les différences entre les manières traditionnelles de créer des applications et ce nouveau paradigme décentralisé.
Prérequis (non stricts)
Cet article se veut accessible à un large éventail de développeurs. Nous utiliserons des outils Python, mais ils ne sont qu'un prétexte pour présenter les idées. Pas de problème si vous n'êtes pas un développeur Python. Je vais toutefois partir de quelques hypothèses sur ce que vous savez déjà, afin que nous puissions rapidement passer aux éléments spécifiques à Ethereum.
Hypothèses :
- Vous savez utiliser un terminal,
- Vous avez écrit quelques lignes de code Python,
- Python version 3.6 ou supérieure est installé sur votre machine (l'utilisation d'un environnement virtuelopens in a new tab est fortement encouragée), et
- vous avez utilisé
pip, le programme d'installation de paquets de Python. Encore une fois, si l'un de ces points ne s'applique pas à vous, ou si vous ne prévoyez pas de reproduire le code de cet article, vous devriez tout de même pouvoir suivre sans problème.
Les blockchains, en bref
Il y a de nombreuses façons de décrire Ethereum, mais au cœur de celui-ci se trouve une blockchain. Les blockchains sont constituées d'une série de blocs, alors commençons par là. En termes simples, chaque bloc de la blockchain Ethereum n'est qu'un ensemble de métadonnées et une liste de transactions. Au format JSON, cela ressemble à ceci :
1{2 "number": 1234567,3 "hash": "0xabc123...",4 "parentHash": "0xdef456...",5 ...,6 "transactions": [...]7}Chaque bloc possède une référence au bloc qui le précède ; le parentHash est simplement le hachage du bloc précédent.
Une blockchain est essentiellement une liste chaînée ; chaque bloc a une référence au bloc précédent.
Cette structure de données n'a rien de nouveau, mais les règles (c'est-à-dire les protocoles pair-à-pair) qui régissent le réseau le sont. Il n'y a pas d'autorité centrale ; le réseau de pairs doit collaborer pour maintenir le réseau, et rivaliser pour décider quelles transactions inclure dans le bloc suivant. Ainsi, lorsque vous voulez envoyer de l'argent à un ami, vous devez diffuser cette transaction sur le réseau, puis attendre qu'elle soit incluse dans un prochain bloc.
La seule façon pour la blockchain de vérifier que de l'argent a bien été envoyé d'un utilisateur à un autre est d'utiliser une devise native (c'est-à-dire, créée et régie par) de cette blockchain. Dans Ethereum, cette devise s'appelle l'ether, et la blockchain Ethereum contient le seul enregistrement officiel des soldes des comptes.
Un nouveau paradigme
Cette nouvelle pile technologique décentralisée a donné naissance à de nouveaux outils pour les développeurs. De tels outils existent dans de nombreux langages de programmation, mais nous allons les explorer à travers le prisme de Python. Pour le répéter : même si Python n'est pas votre langage de prédilection, vous ne devriez pas avoir de mal à suivre.
Les développeurs Python qui souhaitent interagir avec Ethereum se tourneront probablement vers Web3.pyopens in a new tab. Web3.py est une bibliothèque qui simplifie grandement la connexion à un nœud Ethereum, ainsi que l'envoi et la réception de données depuis celui-ci.
Les clients Ethereum peuvent être configurés pour être joignables par IPCopens in a new tab, HTTP ou Websockets, donc Web3.py devra refléter cette configuration. Web3.py désigne ces options de connexion sous le nom de fournisseurs. Il vous faudra choisir l'un des trois fournisseurs pour lier l'instance Web3.py à votre nœud.
Configurez le nœud Ethereum et Web3.py pour qu'ils communiquent via le même protocole, par exemple, l'IPC dans ce diagramme.
Une fois que Web3.py est correctement configuré, vous pouvez commencer à interagir avec la blockchain. Voici quelques exemples d'utilisation de Web3.py en guise d'aperçu de ce qui suit :
1# lire les données du bloc :2w3.eth.get_block('latest')34# envoyer une transaction :5w3.eth.send_transaction({'from': ..., 'to': ..., 'value': ...})Installation
Dans ce tutoriel, nous travaillerons uniquement dans un interpréteur Python. Nous ne créerons ni répertoires, ni fichiers, ni classes ou fonctions.
$ sont destinées à être exécutées dans le terminal. (Ne tapez pas le $, il indique simplement le début de la ligne.)Tout d'abord, installez IPythonopens in a new tab pour disposer d'un environnement convivial pour l'exploration. IPython offre, entre autres fonctionnalités, la complétion par tabulation, ce qui facilite grandement la découverte des possibilités de Web3.py.
pip install ipythonWeb3.py est publié sous le nom web3. Installez-le comme suit :
pip install web3Encore une chose : nous allons simuler une blockchain plus tard, ce qui requiert quelques dépendances supplémentaires. Vous pouvez les installer via :
pip install 'web3[tester]'Vous êtes fin prêt !
Remarque : Le package web3[tester] fonctionne jusqu'à Python 3.10.xx
Lancer un bac à sable
Ouvrez un nouvel environnement Python en exécutant ipython dans votre terminal. C'est comparable à l'exécution de python, mais avec beaucoup plus de fonctionnalités.
ipythonCela affichera quelques informations sur les versions de Python et de IPython que vous utilisez, puis vous devriez voir une invite de saisie :
1In [1]:Vous avez maintenant devant vous un shell Python interactif. Essentiellement, c'est un bac à sable dans lequel vous pouvez expérimenter. Si vous êtes arrivé jusqu’ici, il est temps d’importer Web3.py :
1In [1]: from web3 import Web3Présentation du module Web3
En plus d'être une passerelle vers Ethereum, le module Web3opens in a new tab offre quelques fonctions utilitaires. Explorons-en quelques-unes.
Dans une application Ethereum, vous aurez souvent besoin de convertir des dénominations de monnaie. Le module Web3 fournit quelques méthodes d'assistance à cet effet : from_weiopens in a new tab et to_weiopens in a new tab.
Note: Computers are notoriously bad at handling decimal math. To get around this, developers often store dollar amounts in cents. For example, an item with a price of $5.99 may be stored in the database as 599.
Un modèle similaire est utilisé lors du traitement des transactions en ether. Cependant, au lieu de deux décimales, l'ether en a 18 ! La plus petite dénomination d'ether s'appelle wei, c'est donc la valeur spécifiée lors de l'envoi de transactions.
1 ether = 1000000000000000000 wei
1 wei = 0,000000000000000001 ether
Essayez de convertir certaines valeurs depuis et vers le wei. Notez qu'il existe des noms pour la plupart des dénominationsopens in a new tab entre l'ether et le wei. L'un des plus connus est le gwei, car c'est souvent ainsi que les frais de transaction sont représentés.
1In [2]: Web3.to_wei(1, 'ether')2Out[2]: 100000000000000000034In [3]: Web3.from_wei(500000000, 'gwei')5Out[3]: Decimal('0.5')D'autres méthodes utilitaires du module Web3 comprennent des convertisseurs de format de données (par ex., toHexopens in a new tab), des assistants d'adresse (par ex., isAddressopens in a new tab), et des fonctions de hachage (par ex., keccakopens in a new tab). Beaucoup d'entre elles seront abordées plus tard dans la série. Pour afficher toutes les méthodes et propriétés disponibles, utilisez l'auto-complétion d'IPython en tapant Web3. et en appuyant deux fois sur la touche tabulation après le point.
Discuter avec la chaîne
Les méthodes de commodité sont très bien, mais passons à la blockchain. L'étape suivante consiste à configurer Web3.py pour qu'il communique avec un nœud Ethereum. Ici, nous avons la possibilité d'utiliser les fournisseurs IPC, HTTP ou Websocket.
Nous n'allons pas suivre cette voie, mais un exemple de flux de travail complet utilisant le fournisseur HTTP pourrait ressembler à ceci :
- Téléchargez un nœud Ethereum, par ex., Gethopens in a new tab.
- Démarrez Geth dans une fenêtre de terminal et attendez qu'il synchronise le réseau. Le port HTTP par défaut est
8545, mais il est configurable. - Indiquez à Web3.py de se connecter au nœud via HTTP, sur
localhost:8545.w3 = Web3(Web3.HTTPProvider('http://127.0.0.1:8545')) - Utilisez l'instance
w3pour interagir avec le nœud.
Bien que ce soit une façon « réelle » de le faire, le processus de synchronisation prend des heures et est inutile si vous voulez juste un environnement de développement. Web3.py expose un quatrième fournisseur à cet effet, l'EthereumTesterProvider. Ce fournisseur de test est relié à un nœud Ethereum simulé avec des autorisations assouplies et de la fausse monnaie pour s'exercer.
L'EthereumTesterProvider se connecte à un nœud simulé et est pratique pour des environnements de développement rapides.
Ce nœud simulé s'appelle eth-testeropens in a new tab et nous l'avons installé dans le cadre de la commande pip install web3[tester]. Configurer Web3.py pour utiliser ce fournisseur de test est aussi simple que :
1In [4]: w3 = Web3(Web3.EthereumTesterProvider())Vous êtes maintenant prêt à surfer sur la chaîne ! Personne ne dit ça. Je viens de l'inventer. Faisons un tour rapide.
Le tour rapide
Tout d'abord, une vérification de base :
1In [5]: w3.is_connected()2Out[5]: TrueÉtant donné que nous utilisons le fournisseur de test, ce test n'est pas très utile, mais s'il échoue, il y a de fortes chances que vous ayez mal saisi quelque chose lors de l'instanciation de la variable w3. Vérifiez que vous avez bien inclus les parenthèses intérieures, c'est-à-dire Web3.EthereumTesterProvider().
Arrêt n°1 : comptes
Par commodité, le fournisseur de test a créé des comptes et les a préchargés avec de l'ether de test.
D'abord, jetons un œil à la liste de ces comptes :
1In [6]: w3.eth.accounts2Out[6]: ['0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',3 '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',4 '0x6813Eb9362372EEF6200f3b1dbC3f819671cBA69', ...]Si vous exécutez cette commande, vous devriez voir une liste de dix chaînes de caractères qui commencent par 0x. Chacune est une adresse publique et est, à certains égards, analogue au numéro de compte d'un compte courant. Vous fourniriez cette adresse à quelqu'un qui voudrait vous envoyer de l'ether.
Comme mentionné, le fournisseur de test a préchargé chacun de ces comptes avec de l'ether de test. Voyons combien il y en a dans le premier compte :
1In [7]: w3.eth.get_balance(w3.eth.accounts[0])2Out[7]: 1000000000000000000000000Ça fait beaucoup de zéros ! Avant d'aller rire jusqu'à la fausse banque, rappelez-vous la leçon précédente sur les dénominations de devises. Les valeurs en ether sont représentées dans la plus petite dénomination, le wei. Convertissons cela en ether :
1In [8]: w3.from_wei(1000000000000000000000000, 'ether')2Out[8]: Decimal('1000000')Un million d'ethers de test... ce n'est pas si mal.
Arrêt n°2 : données des blocs
Jetons un coup d’œil à l’état de cette blockchain simulée :
1In [9]: w3.eth.get_block('latest')2Out[9]: AttributeDict({3 'number': 0,4 'hash': HexBytes('0x9469878...'),5 'parentHash': HexBytes('0x0000000...'),6 ...7 'transactions': []8})Beaucoup d'informations sont retournées à propos d'un bloc, mais il y a juste quelques points à souligner ici :
- Le numéro de bloc est zéro, peu importe depuis combien de temps vous avez configuré le fournisseur de test. Contrairement au véritable réseau Ethereum, qui ajoute un nouveau bloc toutes les 12 secondes environ, cette simulation attendra que vous lui donniez du travail à faire.
transactionsest une liste vide, pour la même raison : nous n’avons encore rien fait. Ce premier bloc est un bloc vide, juste pour démarrer la chaîne.- Notez que le
parentHashn'est qu'un ensemble d'octets vides. Cela signifie qu'il s'agit du premier bloc de la chaîne, également connu sous le nom de bloc de genèse.
Arrêt n°3 : transactions
Nous sommes bloqués au bloc zéro jusqu'à ce qu'il y ait une transaction en attente, alors créons-en une. Envoyez quelques ethers de test d'un compte à un autre :
1In [10]: tx_hash = w3.eth.send_transaction({2 'from': w3.eth.accounts[0],3 'to': w3.eth.accounts[1],4 'value': w3.to_wei(3, 'ether'),5 'gas': 210006})C'est généralement à ce moment-là que vous devez attendre plusieurs secondes que votre transaction soit incluse dans un nouveau bloc. Le processus complet se déroule comme suit :
- Soumettez une transaction et conservez le hachage de la transaction. Tant que le bloc contenant la transaction n'est pas créé et diffusé, la transaction est « en attente ».
tx_hash = w3.eth.send_transaction({ … }) - Attendez que la transaction soit incluse dans un bloc :
w3.eth.wait_for_transaction_receipt(tx_hash) - Poursuivre la logique de l'application. Pour afficher la transaction réussie :
w3.eth.get_transaction(tx_hash)
Notre environnement simulé ajoutera la transaction dans un nouveau bloc instantanément, de sorte que nous pouvons immédiatement voir la transaction :
1In [11]: w3.eth.get_transaction(tx_hash)2Out[11]: AttributeDict({3 'hash': HexBytes('0x15e9fb95dc39...'),4 'blockNumber': 1,5 'transactionIndex': 0,6 'from': '0x7E5F4552091A69125d5DfCb7b8C2659029395Bdf',7 'to': '0x2B5AD5c4795c026514f8317c7a215E218DcCD6cF',8 'value': 3000000000000000000,9 ...10})Afficher toutVous verrez ici quelques détails familiers : les champs from, to et value doivent correspondre aux entrées de notre appel send_transaction. L'autre élément rassurant est que cette transaction a été incluse comme première transaction ('transactionIndex': 0) dans le bloc numéro 1.
Nous pouvons également vérifier facilement le succès de cette transaction en consultant les soldes des deux comptes concernés. Trois ethers auraient dû passer de l'un à l'autre.
1In [12]: w3.eth.get_balance(w3.eth.accounts[0])2Out[12]: 99999699997900000000000034In [13]: w3.eth.get_balance(w3.eth.accounts[1])5Out[13]: 1000003000000000000000000Ce dernier semble bon ! Le solde est passé de 1 000 000 à 1 000 003 ethers. Mais qu'est-il arrivé au premier compte ? Il semble avoir perdu un peu plus de trois ethers. Hélas, rien dans la vie n'est gratuit, et l'utilisation du réseau public Ethereum exige que vous dédommagiez vos pairs pour leur rôle de soutien. De faibles frais de transaction ont été déduits du compte qui a soumis la transaction. Ces frais correspondent à la quantité de gaz brûlé (21 000 unités de gaz pour un transfert d'ETH) multipliée par des frais de base qui varient en fonction de l'activité du réseau, plus un pourboire qui va au validateur qui inclut la transaction dans un bloc.
En savoir plus sur le gaz
Et respirez
Cela fait un moment que nous y sommes, c'est donc le bon moment pour faire une pause. Le terrier du lapin se poursuit, et nous continuerons à l'explorer dans la deuxième partie de cette série. Quelques concepts à venir : la connexion à un nœud réel, les contrats intelligents et les jetons. Vous avez d'autres questions ? Faites-le moi savoir ! Vos commentaires influenceront la suite des événements. Les demandes sont les bienvenues via Twitteropens in a new tab.
Dernière mise à jour de la page : 6 février 2025


