Un Projet de Vote sur la Blockchain Ethereum (1/2) : Première Fonctionnalité

  • posté le
  • par ESENS

Depuis que j’ai commencé à m'intéresser à Ethereum et ses 'Smart Contracts', j’ai découvert un nouveau monde qui se construit et qui se prépare à remplacer tout ce que l’on connaît. Sans parler de tendance, un nouveau paradigme apparaît avec ses opportunités et c’est la chose à retenir quand on a dépassé tout le bruit qui peut entourer la blockchain.

Aujourd’hui nous allons développer le Smart Contract d’une Application Décentralisée (ou ÐApp). On utilisera la blockchain Ethereum pour implémenter un système de vote transparent et infalsifiable. Cela peut paraître simple, mais une bonne implémentation est loin de l’être.

Si vous n’êtes pas familier avec les concepts de la blockchain, n’hésitez pas à regarder cette vidéo que je trouve très intéressante.

Et si vous avez besoin d’une introduction à Ethereum et Solidity, essayez le tutoriel de CryptoZombies qui est vraiment génial pour apprendre ce nouveau langage et ses subtilités.

Accrochez vos ceintures, on est prêt à partir !

Qu'est-ce qui fait qu’une Ðapp est une Ðapp ?

La Ðapp que nous allons développer permettra aux utilisateurs de créer et de participer à des scrutins avec n’importe qui dans le monde. Mais à quoi ça ressemble ?

  - Les Smart Contracts de la dapp ne sont contrôlés par aucune autorité centrale (même pas nous).

  - Il n’y a pas de “backend”, toutes les transactions données sont envoyées directement avec la blockchain et les mineurs les exécutent sur le smart contract impliqué.

  - Les Smart Contracts définissent les règles appliquées sur les données et les échanges de monnaie et personne ne peut les modifier.

  - Le code des Smart Contracts est publique, auditable et vérifiable.

  - Le site web de la Ðapp doit être composé uniquement de fichiers statiques et ne reposer que sur la blockchain en tant que base de données.


Développement du Smart Contract

Lorsque l’on développe des Smart contracts, il faut s’assurer qu’il n’y a pas de faille dans les méthodes exposées car toute transaction minée ne peut plus être modifiée ou annulée.

De plus, chaque opération a un coût pour l’utilisateur. Cela peut paraître déroutant, mais c’est bien dans ce mécanisme que réside la force d’Ethereum. Celle-ci introduit une unité de puissance de calcul pour chaque appel de contrat. Cette unité permet de mesurer l’effort de calcul et d’espace de stockage que les mineurs devront délivrer aux utilisateurs pour traiter leurs transactions. Il faut donc faire très attention au code de notre smart contract pour ne pas vider les portefeuilles de nos utilisateurs avec des fonctions inutilement gourmandes en ressources. N'hésitez pas à vérifier la complexité algorithmique et d’espace de vos algorithmes.

En multipliant le coût en gaz de la complexité de la transaction avec les frais du mineur, vous obtenez la rémunération du mineur.

Mais alors en quoi est-ce une force pour Ethereum ? Et bien tout d’abord, chaque transactions coûtant de “l’argent”, le gaz est donc un rempart concret aux attaques par déni de service. Le réseau Ethereum ne risque donc pas de tomber. Deuxième effet direct, les mineurs sont rémunérés pour mettre à disposition de la puissance de calcul.

Pour plus de détail, jetez un oeil à cet article.

Voilà pourquoi je vous conseille de bien tester votre contrat avant de l’uploader sur Ethereum. Il serait même judicieux de déployer votre smart contrat sur un réseau de test comme Ropsten qui vous permettra d’utiliser votre smart contrat dans les mêmes conditions que le réseau principal d’Ethereum.

Nous utiliserons le Truffle Framework pour développer la logique et tester notre Ðapp.

Truffle Framework

Assurez vous d’avoir installé NodeJS sur votre machine, et installez Truffle :

[sudo] npm install -g truffle

Créez un répertoire de travail et réinitialisez le projet

$ cd blockchain
$ truffle init
Downloading...
Unpacking...
Setting up...
Unbox successful. Sweet!
Commands: 
    Compile:        truffle compile 
    Migrate:        truffle migrate 
    Test contracts: truffle test

Ensuite si nous exécutons ' truffle test', plusieurs choses vont se dérouler :

-  Truffle compilera tous les smart contracts dans 'contracts' avec 'solc'.

-  Les Smart contracts seront déployés sur une blockchain locale éphémère.

-  Tous les tests dans les fichiers 'test/*.sol' seront lancés.

-  Tous les tests dans les fichiers 'test/*.js' seront lancés par Mocha.

Etant donné qu’aucun test n’est défini, les tests termineront en succès 0/0.

Fonctionnalités de la Ðapp

Avant de se lancer dans le code, nous allons définir ce que l’application est censée faire.

Les fonctionnalités principales seront :

  - Jean peut créer un scrutin

  - Jean peut ajouter des propositions à un scrutin

  - Jean peut soumettre un vote

  - Jean peut suivre les résultats d’un scrutin


Cas d’erreurs

Les cas d’erreurs que le smart contracts devra gérer sont les suivants :

  - Jean ne peut pas rajouter de proposition à un scrutin qu’il n’a pas créé

  - Jean ne peut soumettre un vote dans un scrutin qu’une seule fois


Opérations du contrat

  createScrutin (_name)

Créer un scrutin avec le nom spécifié.

  createProposal(_scrutinId, _description)

Ajouter une proposition à un scrutin donné.

  submitVote(_propositionId)

Soumettre un vote sur une proposition.

Les événements suivants seront également disponibles :

  event VoteSubmitted(uint _scrutinId, uint _propositionId, uint _counter);
  event ScrutinCreated(uint _scrutinId, bytes32 _name, address _scrutinOwner);
  event ProposalCreated(uint _propositionId, uint _scrutinId, bytes32 _description);

Vous devriez avoir un contrat minimal qui ressemble à ceci :

Tout cela devra être implémenté de la manière la plus simple, efficace et la moins onéreuse possible car chaque transaction coûte du gas. Nous essayerons de faire une implémentation légère.

Tests du contrat

Le grand avantage des Smart Contracts face à des contrats traditionnels est qu’ils sont testables comme n’importe quel code.

C’est comme si un avocat pouvait simuler 1000 procès en 30 secondes pour s’assurer que son contrat n’ait aucune faille.

Le Test Driven Development est donc tout indiqué pour nous. Créons donc un fichier

  test/TestVote.js

Vous aurez remarqué que j’ai décidé de faire des tests en javascript car je trouve qu’ils couvrent plus de fonctionnalités que les tests en solidity qui ne permettent que de tester le code interne du smart contract.

En effet le test en javascript se placera au même niveau que l’application que nous écrirons plus tard pour interagir avec le contrat. Si le test passe, il y’a de grandes chances que l’implémentation de l’application frontend se passe sans encombre.

On parle donc de test d’intégration et plus précisément de Narrow Testing car les tests du smart contract s'effectueront sur un contrat fraîchement déployé sur le client de truffle, c’est la notion de clean-room.

Cependant si vous voulez également tester le contrat en solidity pour faire des test unitaire et ainsi renforcer la couverture de test, n’hésitez pas à regarder la documentation.

Création d’un scrutin

Nous avons donc initié la suite de tests pour le contrat de Vote et spécifié un premier test. Celui-ci vérifie que si l’on appelle la méthode 'createScrutin()' du contrat, un scrutin sera bel et bien créé et qu’un événement 'ScrutinCreated' sera envoyé.

Lançons maintenant ce test :

  truffle test
  Contract: Vote
    1) should emit a ScrutinCreated event when createScrutin
    > No events were emitted
  0 passing (130ms)  
  1 failing
  1) Contract: Vote
       should emit a ScrutinCreated event when createScrutin:
       Error: VM Exception while processing transaction: revert

Le test a donc échoué sur la transaction, ce qui est tout à fait normal car nous n’avons pas encore implémenté la fonction.

Repassons donc maintenant sur le smart contract afin de faire passer le test.

Et relançons les tests :

  truffle test
  Contract: Vote
    ✓ should emit a ScrutinCreated event when createScrutin (57ms)
  1 passing (141ms)

Bravo, notre première fonctionnalité est correctement implémentée !

Nous avons introduit une struct nommée Scrutin et une liste de celle-ci afin de stocker tous les scrutins dans notre contrat :

struct Scrutin {
       string name;
       address scrutinOwner;
       bool isStarted;
}
Scrutin[] public scrutins;

Et enfin dans la méthode 'createScrutin()' nous initialisons un nouveau scrutin avec le nom spécifié, nous ajoutons celui-ci à la liste des scrutins du contrats et enfin nous émettons un événement de création de contrat.

Vous aurez également remarqué que je ne mets pas à disposition de méthode pour retrouver un scrutin par son identifiant mais que j’utilise un événement pour renvoyer l’objet créé. J’aime utiliser cette méthode car du côté de l’application frontend, je peux récupérer tous les événements émis depuis la création du smart contract et récupérer ainsi tous les scrutins créés. J’utiliserai ce mécanisme tout au long du développement de ce smart contract...

Rendez-vous la semaine prochaine pour la deuxième partie de cet article dans lequel nous verrons comment ajouter une proposition à un scrutin et enfin, soumettre un vote !

Pour lire la suite de cet article, c'est par ici !

Article rédigé par Anthony M. | Retrouvez tous nos articles sur le Blog ESENS


Vous êtes à la recherche d'un nouveau challenge ? Rejoignez l'équipe ESENS en postulant à nos offres d'emploi !

Actualité récente

VOIR TOUTE NOTRE ACTUALITE