Build your first BlockChain DAPP with Ganache and Solidity

Voting Dapp

Build your first BlockChain DAPP with Ganache and Solidity

We will be going to build a very simple Dapp with 6 steps follow:

1 - Environment setup

mkdir voteDapp
npm init
npm install web3@0.20.1 solc@0.4.22 ganache-cli

# Start ganache by default with port 8989 
./node_modules/.bin/ganache-cli -h 192.168.1.114 -p 8989

2 - Write a solid contract

pragma solidity ^0.4.22;

contract Voting{

    bytes32[] public candidateList;
    mapping(bytes32=>uint8) public votingMap;

    constructor(bytes32[] candidateListName) public{
        candidateList = candidateListName;
    }

    function validateCandidate(bytes32 candidateListName) internal view returns(bool){
        for(uint8 i=0 ; i<candidateList.length ; i++){
            if(candidateListName == candidateList[i]){
                return true;
            }
        }
        return false;
    }

    function vote(bytes32 candidateListName) public{
        require(validateCandidate(candidateListName));
        votingMap[candidateListName] += 1;
    }

    function totalVoters(bytes32 candidateListName) public view returns(uint8){
        require(validateCandidate(candidateListName));
        return votingMap[candidateListName];
    }   
}

3 - Connect to local ganache and deploy contract

// Start node, enter the following code to deploy the contract

var Web3 = require('web3');

// Load solc to compile the solidity contract, please note that it is consistent with the contract version
var solc = require('solc');

var web3 = new Web3(new 

Web3.providers.HttpProvider("http://192.168.1.114:8989"));

web3.isConnected();

// Read the solidity file, using synchronous reading as a string type
var sourceCode = fs.readFileSync("Voting.sol").toString();

// solc compiles solidity files
var compileCode = solc.compile(sourceCode);

// Get the contents of abi and bin from the compilation result
var abi = JSON.parse(compileCode.contracts[":Voting"].interface);
var byteCode = compileCode.contracts[":Voting"].bytecode;

// Deployment contract
var VotingContract = web3.eth.contract(abi);
var deployObj = {from:web3.eth.accounts[0],data:byteCode,gas:3000000};
var votingInstance = VotingContract.new(["Bob","Alice","Jerry"],deployObj);

// Check the contract address to verify whether the deployment is successful
votingInstance.address;

4 - Call contract function from Client

// Vote for Bob
votingInstance.vote("Bob",{from:web3.eth.accounts[0]});
votingInstance.vote.sendTransaction("Bob",{from:web3.eth.accounts[0]});

// Check Bob's votes
votingInstance.totalVoters("Bob");
votingInstance.totalVoters.call("Bob");

5 - Front-end page layout, add the following code to the index.html file

<!DOCTYPE html>
<html>
    <head>
        <title>Voting Dapp</title>
        <link href="http://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" type="text/css"/>
    </head>
    <body class="container">
        <h1>Simple Voting Dapp</h1>
        <div class="table-responsive">
            <table class="table table-bordered">
                <thead>
                    <tr>
                        <th>Candidate</th>
                        <th>Voting count</th>
                    </tr>
                </thead>
                <tbody>
                    <tr>
                        <td>Alice</td>
                        <td id="candidate-1"></td>
                    </tr>
                    <tr>
                        <td>Bob</td>
                        <td id="candidate-2"></td>
                    </tr>
                    <tr>
                        <td>Jerry</td>
                        <td id="candidate-3"></td>
                    </tr>
                </tbody>
            </table>
        </div>
        <input type="text" id="candidate"/>
        <a href="#" onclick="voteForCandidate()" class="btn btn-primary">Voting</a>
    </body>
    <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/web3@0.20.1/dist/web3.min.js"></script>
    <script src="./index.js"></script>
</html>

6 - Add the following content to the index.js file in the same directory as index.html

var web3 = new Web3(new Web3.providers.HttpProvider("http://192.168.1.114:8989"));

var abi = JSON.parse('[{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"votingMap","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"candidateListName","type":"bytes32"}],"name":"totalVoters","outputs":[{"name":"","type":"uint8"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"candidateListName","type":"bytes32"}],"name":"vote","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"candidateList","outputs":[{"name":"","type":"bytes32"}],"payable":false,"stateMutability":"view","type":"function"},{"inputs":[{"name":"candidateListName","type":"bytes32[]"}],"payable":false,"stateMutability":"nonpayable","type":"constructor"}]');

// Change contractAddr to your contract address
var contractAddr = "0x08c19cb41678b41609d51662e3c0691998f640f8";
var VotingContract = web3.eth.contract(abi);
var contractInstance = VotingContract.at(contractAddr);
var candidates = {"Alice":"candidate-1","Bob":"candidate-2","Jerry":"candidate-3"};

function voteForCandidate(){
    let candidateName = $("#candidate").val();
    contractInstance.vote(candidateName,{from:web3.eth.accounts[0]},function(err,res){
        if(err){
            console.log("Error:",err);
        }else{
            let count = contractInstance.totalVoters(candidateName).toString();
            $("#"+candidates[candidateName]).html(count);
        }
    });
}

$(document).ready(function(){
    var candidateList = Object.keys(candidates);
    for(let i=0 ; i<candidateList.length ; i++){
        let name = candidateList[i];
        let count = contractInstance.totalVoters(name).toString();
        $("#"+candidates[name]).html(count);
    }
}
);

Result:

da421730ceb004625f5e704a6fcb63bb.png