Home R&D Webnet Implémenter sa propre blockchain privée : Rédaction de smart-contracts avec Solidity et Truffle

Implémenter sa propre blockchain privée : Rédaction de smart-contracts avec Solidity et Truffle

  Oriane, Ingénieur R&D 5 min 4 mars 2019

Une fois notre blockchain privée déployée et notre super utilisateur créé, nous pouvons maintenant nous intéresser aux smart-contracts qu’il aura la charge de miner.

 

Fonctionnement général

On a vu précédemment qu’un smart contract était un programme autonome déployé dans la blockchain. De façon concrète, il s’agit d’une « classe » présentant des attributs et des méthodes qui définissent le mode de fonctionnement du programme, autrement dit, les termes du contrat.

Pour ce développement, nous avons utilisé le langage de programmation Solidity, dédié à l’implémentation de smart contracts sur Ethereum. Il s’agit d’un langage proche du JavaScript avec un typage statique. Après avoir rédigé notre contrat, on le compile afin d’obtenir un fichier JSON qui sera finalement exécuté par la blockchain. Un contrat « miné » dans la blockchain est une instance de cette classe-contrat.

Pour interagir avec une instance déployée dans la blockchain, on aura besoin de conserver l’adresse de cette instance (contract address) ainsi que du fichier JSON compilé.

Comme on ne peut jamais revenir sur un block miné (logique de base de la blockchain), une instance déployée dans la blockchain est définitive. Si une erreur est détectée dans la rédaction du contrat, elle ne peut donc pas être corrigée. Habituellement, on prévoit une méthode « suicide » dans les contrats afin de pouvoir les rendre inactifs en cas d’erreur. Puis on re-déploie toutes les instances avec la nouvelle version de Contract.json.

 

Exemple de contrat

contract ContractName{
    // attributs
    string public contractLabel 
    uint private contractValue
    ...
    // constructor
    constructor(string label, uint value) public {
        contractLabel = label
        contractValue = value
    }
    // methods
    function GetValue() public view returns (string value_){
        value_ = contractValue
    }
}
Example.sol

Dans cet exemple basique de contact Solidity, on peut voir : la syntaxe de typage, de niveau de visibilité (public/private), de déclaration de constructeur et de méthodes. Les méthodes sont également décrites par un mot clé précisant le type de transaction qu’elles doivent effectuer (lecture, édition, paiement). Ce mot-clé peut prendre 3 valeurs : « pure », « view », « payable ».

 

Cas de l’application de pronostics

Dans notre cas, nous souhaitions que le contrat permette de sauvegarder les pronostics posés par les utilisateurs sur les différents matchs. Puis, à l’annonce des résultats de chaque match, les Ether correspondant au nombre de points gagnés avec ce pronostic doivent être automatiquement transférés depuis le porte-monnaie du super utilisateur vers celui de tous les pronostiqueurs.

Nous avons donc choisi de rédiger un contrat par match dans lequel sont stockés tous les pronostics. A l’annonce des résultats de ce match, tous les pronostiqueurs seront rémunérés simultanément et le contrat deviendra inactif.

Statut d’un match

Pour gérer les interactions possibles avec ce contrat, nous avons mis en place un système de statuts qui évoluent au cours du cycle de vie d’un match et donne accès à différentes actions.

Un match est d’abord créé en amont puis lancé (au coup d’envoi). Il se termine ensuite à l’annonce des résultats et devient payé lorsque tous les utilisateurs ont reçu leurs gains.

Les méthodes permettant de passer d’une étape à la suivante sont exposées publiquement par le contrat mais ne produisent l’effet attendu QUE si le statut courant du match est cohérent. Autrement dit, on doit appeler la méthode « LaunchGame » au moment du coup d’envoi du match. Si la méthode est appelée à un autre moment, elle n’aura pas d’effet car le statut du match n’est pas « UpComing ».

On utilise la méthode « require » de Solidity pour tester la valeur du GameStatus. Elle stoppe l’exécution si la condition n’est pas vérifiée.

function LaunchGame() public {
    require(status == GameStatus.UpComing, "Game already launched");
    status = GameStatus.InProgress;
}

Ces méthodes sont appelées par l’application de paris en ligne développée en PHP via une API écrite également en PHP (Article à venir) qui est-elle même dépendante des événements officiels de la Coupe du Monde.

Sauvegarde des pronostics

Les pronostics sont sauvegardés au sein du contrat sous forme d’une table de hashage dont la clé est « adresse de l’utilisateur » et la valeur est un objet de type « Bet » représentant le pronostic. Cette table est un attribut interne de la class-contract « Game ».

Cette structure Bet contient donc les scores pronostiqués et le gagnant pronostiqué en cas de match nul ainsi que des attributs facilitant la gestion de ces pronostics : la date de création, modification et paiement, le statut du pronostic (déjà payé ou non). Le match passe au statut « Payed » si tous les pronostics qu’il contient ont ce statut.

struct Bet {
    // résultats pronostiqués
    uint score1;
    uint score2;
    uint winner;
    // reward
    BetStatus status;
    uint reward;
      // gestion
    uint creationDate; // timestamp
    uint lastUpdateDate;
    uint paimentDate;
 }

 

Les tables de hashage Solidity « mapping » ne sont pas itérables (pas de methode « contains » pour savoir si une clé est présente dans la table) donc on a également besoin d’une liste de clés.

// attributs de la class-contract Game
mapping (address => Bet) public bets; // table de hashage
address[] public betters; // liste de clés

 

En solidity, le timestamp courant est très facilement accessible avec le mot-clé « now »

creationDate = now;

 

Compiler le contrat

Notre class-contract de pronostic peut désormais être compilée sous forme d’un fichier JSON. Pour cela, nous avons utilisé Truffle, un framework de développement et de tests dédié à Ethereum.

Après installation de Truffle et création du projet, la commande suivante génère le fichier JSON de plusieurs milliers de lignes

>> truffle compile
Compiling .\contracts\Game.sol...
Writing artifacts to .\build\contracts

Ce fichier JSON compilé contient :

  • l’ »ABI » : l’interface binaire d’application, qui décrit les méthodes du contrat (entrées/sortie).
  • le « ByteCode » qui le code compréhensible par la machine virtuelle Ethereum.

Dans la partie suivante, nous verrons comment déployer ce smart-contract compilé dans une blockchain à l’aide d’une application Symfony.

Lire les articles similaires

Laisser un commentaire

Social Share Buttons and Icons powered by Ultimatelysocial