Atelier Ethereum #2 - Jouer avec la démocratie - [ Partie 2 : Une interface pour voter ]





  • Une fois Test-rpc et truffle installé, lancer la console et faire la commande truffle init dans un nouveau dossier que vous pouvez appeler Democracy

    Cela va peupler le dossier avec un contrat demo :

    Vous obtenez un index.html “par défault” :

    <!DOCTYPE html>
    <html>
    <head>
      <title>MetaCoin - Default Truffle App</title>
      <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
      <link href="./app.css" rel='stylesheet' type='text/css'>
      <script src="./app.js"></script>
    </head>
    <body>
      <h1>MetaCoin</h1>
      <h2>Example Truffle Dapp</h2>
      <h3>You have <span class="black"><span id="balance"></span> META</span></h3>
    
      <br>
      <h1>Send</h1>
      <br><label for="amount">Amount:</label><input type="text" id="amount" placeholder="e.g., 95"></input>
      <br><label for="receiver">To Address:</label><input type="text" id="receiver" placeholder="e.g., 0x93e66d9baea28c17d9fc393b53e3fbdd76899dae"></input>
      <br><br><button id="send" onclick="sendCoin()">Send MetaCoin</button>
      <br><br>
      <span id="status"></span>
    </body>
    </html>
    

    Virez ce qu’il y a dans body et ajoutez la librairie underscore :

    <!DOCTYPE html>
    <html>
    <head>
      <title>Democracy</title>
      <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
      <link href="./app.css" rel='stylesheet' type='text/css'>
      <script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.8.3/underscore-min.js"></script>
      <script src="./app.js"></script>
    </head>
    <body>
      <h1>Democracy</h1>
    </body>
    </html>
    

    Supprimez également le js dans App.js et le contrat metacoin.sol


    Lancez dans un terminal la commande testrpc :

    Ensuite vous pouvez lancer truffle via truffle serve :

    vous pouvez voir le résultat sur http://atelier.cryptofr.com/

    vous obtenez une belle page vide :

    L’intérêt ici est dans la console. Faites F12 ou click droit > inspecter pour ouvrir la console de votre navigateur.

    On peut voir que la connexion se fait bien en demandant web3.eth.coinbase :



  • Jouons avec la console et Web3 !

    Les comptes

    commande : web3.eth.accounts

    On voit bien l’ensemble des comptes générés par test RPC :

    Taille de bloc ?

    commande : web3.eth.blockNumber

    on remarque que le bloc est à zéro … ce qui est logique car sur notre réseau test, nous n’avons pas encore exécuté une seule transaction !

    Exécutons une transaction

    commande : web3.eth.sendTransaction({from: address ,to: address, value: en wei })

    Ici on envoie depuis l’adresse coinbase jusqu’à l’adresse du compte n°1 une somme de 50 ethers (convertis en Wei).

    Comme la blockchain testrpc incrémente d’un bloc pour chaque nouvelle transaction, on devrait être désormais au bloc 1. Ce qui est vérifié :



  • Arrêtez maintenant truffle puis :

    • ajoutez le contrat Democracy au dossier “contracts” en l’appelant Democracy.sol
    • modifiez truffle.json en remplaçant Metacoin par Democracy dans “deploy”

    Lancez ensuite de nouveau truffle, mais cette fois ci avec la commande truffle deploy

    Maintenant si on fait de nouveau truffle serve et que nous allons dans la console, on peut désormais accéder à l’objet Democracy.

    Si on fait Democracy.deployed(), on obtient les caractéristiques du contrat déployé :

    Derniers bouts de code avant la visualisation du contrat

    on va maintenant mettre en place les dernières briques pour notre application démocratie.

    Tout d’abord, dans /app/javascripts/app.js, ajoutez le code :

    var accounts;
    var accountID = 0
    
    function displayAccounts() {
        var dem = Democracy.deployed()
    
        Promise.map(accounts,
          function(index) {
            return dem.members(index)
          }).then(function(results) {
            document.getElementById("addresses").innerHTML = 
            accounts
            .map((x, i) => ('<button onclick="setChangeAccount(' + i + ')">' + i + '</button>' + ' : ' + x + ' is member : ' + results[i]) + (i == accountID ? '     <------ you are this guy' : ''))
            .join('<br>')
      })
    };
    
    function setChangeAccount(newAccount) {
      accountID = newAccount;
      account = accounts[accountID];
      displayAccounts();
    }
    
    window.onload = function() {
      web3.eth.getAccounts(function(err, accs) {
        if (err != null) {
          alert("There was an error fetching your accounts.");
          return;
        }
    
        if (accs.length == 0) {
          alert("Couldn't get any accounts! Make sure your Ethereum client is configured correctly.");
          return;
        }
    
        accounts = accs;
        account = accounts[accountID];
    
        displayAccounts();
    
        //refreshProposals();
      });
    }
    

    Ce code permet d’afficher tout les comptes qu’on a et de choisir un compte dans une page web.

    Ensuite dans le body du html (app/index.html), rajoutez :

    <code id="addresses"></code>

    Rechargez votre page (avec truffle serve lancé), vous devriez avoir une page qui ressemble à cela :



  • Simuler plusieurs votants

    Les numéros à côté des adresses sont des boutons pour dire quelle adresse (et donc quel votant) vous êtes sur la session en cours.

    Cela va nous permettre de simuler l’interaction entre plusieurs votants :

    Changeons la durée de vote

    Un peu de code frais

    On rajoute un input et un bouton pour changer le vote dans le html :

    <body>
      <code id="addresses"></code>
      <br>
      <h1>Democracy</h1>
      <br>
      <h3>Nouvelle durée de vote</h3>
      <input type="number" id="newVotingTimeField"></input>
      <button onclick="newVotingTime()">Ajouter</button>
    </body>
    

    Ensuite dans app.js, on ajoute la fonction qui va traiter cette nouvelle durée de vote :
    vous pouvez l’ajouter après la fonction setChangeAccount()

    function newVotingTime(){
        // on récupère le temps inscrit dans l'input
        var newVotingTime = document.getElementById("newVotingTimeField").value;
        // on récupère notre contrat déployé
        var dem = Democracy.deployed();
    
        dem.setVotingTime(newVotingTime, {from: account}).then( function(res){
            console.log('Done!');
            console.log('res :', res);
        })
        console.log("Transaction sent");
    }
    

    Trouver la durée en console

    On mets à jour notre page web Democracy et on ouvre la console (pour visualiser nos console.log() entre autre).

    Une première chose qui pourrait nous intéresser, c’est savoir quel est la durée actuelle de vote. Pour cela, on peut le rechercher directement dans la console :

    commandes :

    • var dem = Democracy.deployed()
    • dem.votingTimeInMinutes().then(function(res) {console.log(res.toString())})

    remarque : on a besoin de faire ‘toString()’ du résultat car, du à l’inconsistance des nombres en js, Ethereum utilise la librairie BigNumber

    On envoie !

    prérequis : vous devez être l’owner, donc le premier compte de la liste

    Vous pouvez maintenant mettre une durée dans l’input et l’envoyer dans notre contrat !

    Vous devriez obtenir ce genre de résultat en console :

    On vérifie bien que la nouvelle durée de vote est de 4 minutes :



  • Ajoutons de nouveaux membres

    Le but ici est d’ajouter des membres au votes (pour le moment tout le monde est à “false”)

    Comment çà il est pas frais mon code ???

    On rajoute, de la même façon que précédemment, un input pour ajouter un nouveau membre (on remplace VotingTime par Member) :

    <br>
    <h3>Nouveau Membre</h3>
    <input type="text" id="newMemberField"/>
    <button onClick="newMember()">Ajouter</button>
    

    et un même copié/collé dans app.js :

    function newMember(){
        var dem = Democracy.deployed();
        var newMember = document.getElementById("newMemberField").value;
    
        dem.addMember(newMember, {from: account}).then(function(res){
            console.log('Done!');
            console.log('res :', res);
        })
        console.log("Transaction sent");
    }
    

    On va maintenant rajouter l’owner, et tout ceux que l’on souhaite ajouter à notre vote :

    Après avoir rajouté les 4 premiers, on voit en actualisant la page que les 4 premières adresses sont désormais à true :



  • Ajouter une proposition

    Code

    Ajoutons le code pour récupérer toutes les propositions :

    function refreshProposals() {
        var dem = Democracy.deployed();
    
        dem.nbProposals().then(function(nbProposals) {
            var array = _.range(nbProposals)
            Promise.map(array,
                function(index) {
                    return dem.proposals(index)
                }).then(function(results) {
                document.getElementById("proposals").innerHTML =
                results
                .map((x,i) => (i + ":" + x))
                .join('<br>');
                console.log('refreshProposals Done!');
            })
        })
    };
    

    En même temps, enlevez le commentaire sur refreshProposals() dans la fonction onLoad (fin du code js).

    Du côté de index.html, rajoutez une simple balise :

    <br>
    <h3>Proposals</h3>
    <div id="proposals"></div>
    

    Test

    On mets à jour l’interface web, et on repart de nouveau dans la console pour ajouter une proposition :
    dem.addProposal("AcheterDeLaBiere", { from : account })

    La page nous afficher notre nouvelle proposition (pleine de sens, par ailleurs) :



  • @ffmad Bonsoir ffmad. Merci beaucoup pour ce tuto excellent. Je l’ai essayé et tout se passe à merveille sur testrpc. Cependant, quand je le test sur morden testnet, là c’est vraiment une autre paire de manche. D’abord, le déploiement ne fonctionne que si le compte n°0 “eth.coinbase” est débloqué. Ensuite le déploiement utilise du gaz à ce que j’ai vu. Et après avoir surmonter toutes les péripéties avec testnet, enfin la page web envoie une vraie transaction (vérifiée sur testnet.etherscan.io) mais la valeur du “temps du vote” ne change pas malgré que je suis sur le premier compte. J’ai cherché et j’ai remarqué que sur testrpc, Democracy.deployed().owner envoi bien l’adresse du compte 0 tandis que sur testnet la fonction envoie 0x. Avez vous une idée d’où peut venir cette erreur sur Testnet?

    Merci par avance pour votre aide
    Bien cordialement