Ethereum for web developers

I have been learning about Ethereum blockchain platform for some time and the more I learn, the more exciting it looks. There are lots of resources (articles, videos, platform documentation) about Ethereum, it’s easy to get overwhelmed. But, many of them are outdated understandably because the platform is still evolving at a rapid pace. It took me some time to piece together and get a complete picture of what Ethereum is and how it works. Talking to developers in meetup groups and other online communities, it feels like there are many people who would like to get their hands dirty with this new technology but have the same issue. This article is my attempt at explaining Ethereum from a web developer’s point of view.

If you are a web developer, you know how a webapp with it’s client server architecture works at a very high level.

You have your web application hosted on a hosting provider like AWS, Heroku or a VPS. All the clients interact with this one central application. Clients can be a browser, another api consuming your service etc. When a client makes a request to the server, the server does it’s magic, talks to the database and/or cache, reads/writes/updates the database and serves the client.

This architecture works very well most of the times. However, there are certain applications where it would be really helpful if that database was publicly and securely accessible by everyone and you don’t have to rely on this webapp owner for your data.

For example, let’s look at eBay. If you are a power seller who has earned hundreds of good reviews and for some reason eBay suspends your account. That would be very bad and could severely impact your business. What would be really nice is the ability for you take all your reviews and ratings and move to another platform (say eBay Competitor). eBay does provide a service by being the trusted third party between buyers and sellers. But then, they also take a commission off each sale. What if there was a way to eliminate eBay altogether from the transaction between buyer and seller so you save on commission and also you have access to all your data? This is where decentralized applications come in to picture. Ethereum makes it very easy to build Dapps (decentralized applications).

This is how an Ethereum Dapp looks at a high level:

If you notice, every client (browser) communicates with it’s own instance of the application. There is no central server to which all clients connect to. This means, every person who wants to interact with a dapp (Decentralized Application) will need a full copy of the blockchain running on their computer/phone etc. That means, before you can use an application, you have to download the entire blockchain and then start using the application. This might sound ridiculous at first but it has the advantage of not relying on a single central server which might disappear tomorrow.

In reality, you don’t need to spend lot of your hard disk and RAM downloading the entire blockchain. There are a few workarounds/optimizations to keep the application decentralized yet make the interaction quick and easy.

Now, what exactly is this blockchain? It has:

  1. Database: Every few transactions that occur in the Ethereum network are packaged in to blocks and each block is linked to the next block. This linked series of blocks which holds all the transaction data is the blockchain. If we go back to the eBay example, every transaction between buyers and sellers, whether it is a sale, refund or dispute would all be recorded on the blockchain and is available for everyone to see. To make sure all the nodes in the network have same copy of the data and to insure no invalid data gets written to this database, Ethereum uses an algorithm called Proof of Work (http://ethereum.stackexchange.com/questions/14/what-proof-of-work-function-does-ethereum-use)
  2. Code: The database aspect of blockchain just stores the data. But where is all the logic to buy, sell, cancel, refund etc. In Ethereum world, you write the application code (called contract) in a language called Solidity. You then use the solidity compiler to compile it to Ethereum Byte Code and then deploy that byte code to the blockchain. There are few other alternates to Solidity but Solidity is by far the most popular language for contract development.

So basically, the blockchain stores your data, stores the code and also runs the code in the EVM (Ethereum Virtual Machine).

To build web based dapps, Ethereum comes with a handy javascript library called web3.js which connects to your blockchain node. So you can just include this library in your famous js framework like reactjs, angularjs etc and start building.

Another big and most important feature is the financial capabilities of the platform. What if I tell you, as soon as you start using a dapp, you get an in built bank account? Actually, not one bank account, but you can create as many bank accounts as you like in a fraction of second? These bank accounts are called wallets where you store money (Ether - the currency used in the Ethereum ecosystem) and transact.

There are lot of details about the inner workings of the blockchain I left out deliberately because I wanted to concentrate on mostly comparing the blockchain based Dapp with a centalized webapp. Hope this post accomplishes that and gives a good high level idea of what Ethereum is and how it can be used to build decentralized applications.

[I have written a 3 part guided tutorial on building a full stack dapp here:Part1Part2Part3]

I have also created a more complex course to build a decentralized eBay on Ethereum & IPFS.

Further Reading:

Thanks @raineorshine@alwaysbcoding@kinjalmurthy for feedback on the article.

=====================================================

Full Stack Hello World Voting Ethereum Dapp Tutorial — Part 1

In my previous post, I explained the high level architecture of Ethereum platform comparing it to a web application. As a developer, the best way to learn any new technology is by diving in and building toy applications. In this post, let’s build a simple ‘Hello World!’ application which is a Voting application.

The application is extremely simple, all it does is initialize a set of contestants, let anyone vote for the candidates and display the total votes received by each candidate. The goal is not to just code an application but to learn the process of compiling, deploying and interacting with it.

I have deliberately avoided using any dapp frameworks to build this application because the frameworks abstract away lot of the details and you fail to understand the internals of the system. Also, when you do use a framework, you will have more appreciation for all the heavy lifting the framework does for you!

In lot of ways, this article is a continuation of the previous post. If you are new to the world of Ethereum, I recommend reading it before continuing.

The goal of this exercise is to:

  1. Set up the development environment.
  2. Learn the process of writing a contract, compiling it and deploying it in your development environment.
  3. Interact with the contract on the blockchain through a nodejs console.
  4. Interact with the contract through a simple web page to display the vote counts and vote for candidates through the page.

The entire application set up and build was done on a fresh installation of ubuntu 16.04 xenial. I have set up and tested the application on macos as well.

This is how I would visualize this application we are going to build.

1. Setting up the development environment

Instead of developing the app against the live blockchain, we will use an in- memory blockchain (think of it as a blockchain simulator) called ganache. In Part 2 of the tutorial, we will interact with the real blockchain. Below are the steps to install ganache, web3js and start the test blockchain on a linux operating system. The exact same instructions work on macos as well. For windows, you can follow the instructions here (Thanks Prateesh!).

Note: This tutorial currently works with web3js version 0.20.2. I will update the tutorial once web3js 1.0 stable is released

Notice that the ganache-cli creates 10 test accounts to play with automatically. These accounts come preloaded with 100 (fake) ethers.

2. Simple voting contract

We are going to use the solidity programming language to write our contract. If you are familiar with object oriented programming, learning to write solidity contracts should be a breeze. We will write a contract (think of contract as a class in your favorite OOP language) called Voting with a constructor which initializes an array of candidates. We will write 2 methods, one to return the total votes a candidate has received and another method to increment vote count for a candidate.

Note: The constructor is invoked once and only once when you deploy the contract to the blockchain. Unlike in the web world where every deploy of your code overwrites the old code, deployed code in the blockchain is immutable. i.e, If you update your contract and deploy again, the old contract will still be in the blockchain untouched along with all the data stored in it, the new deployment will create a new instance of the contract.

Below is the voting contract code with inline comment explanation:

Text Box

pragma solidity ^0.4.18;
// We have to specify what version of compiler this code will compile with

contract Voting {
  /* mapping field below is equivalent to an associative array or hash.
  The key of the mapping is candidate name stored as type bytes32 and value is
  an unsigned integer to store the vote count
  */
  
  mapping (bytes32 => uint8) public votesReceived;
  
  /* Solidity doesn't let you pass in an array of strings in the constructor (yet).
  We will use an array of bytes32 instead to store the list of candidates
  */
  
  bytes32[] public candidateList;

  /* This is the constructor which will be called once when you
  deploy the contract to the blockchain. When we deploy the contract,
  we will pass an array of candidates who will be contesting in the election
  */
  function Voting(bytes32[] candidateNames) public {
    candidateList = candidateNames;
  }

  // This function returns the total votes a candidate has received so far
  function totalVotesFor(bytes32 candidate) view public returns (uint8) {
    require(validCandidate(candidate));
    return votesReceived[candidate];
  }

  // This function increments the vote count for the specified candidate. This
  // is equivalent to casting a vote
  function voteForCandidate(bytes32 candidate) public {
    require(validCandidate(candidate));
    votesReceived[candidate] += 1;
  }

  function validCandidate(bytes32 candidate) view public returns (bool) {
    for(uint i = 0; i < candidateList.length; i++) {
      if (candidateList[i] == candidate) {
        return true;
      }
    }
    return false;
  }
}

Copy the above code to a file named Voting.sol in the hello_world_voting directory. Now let’s compile the code and deploy it to ganache blockchain.

To compile the solidity code, we will first install npm module called solc

mahesh@projectblockchain:~/hello_world_voting$ npm install solc

We will use this library within a node console to compile our contract. Remember from the previous article, web3js is a library which lets you interact with the blockchain through RPC. We will use that library to deploy our application and interact with it.

First, run the ‘node’ command in your terminal to get in to the node console and initialize the solc and web3 objects. All the code snippets below need to be typed in the node console.

mahesh@projectblockchain:~/hello_world_voting$ node
> Web3 = require('web3')
> web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));

To make sure web3 object is initialized and can communicate with the blockchain, let’s query all the accounts in the blockchain. You should see a result like below:

> web3.eth.accounts
['0x9c02f5c68e02390a3ab81f63341edc1ba5dbb39e',
'0x7d920be073e92a590dc47e4ccea2f28db3f218cc',
'0xf8a9c7c65c4d1c0c21b06c06ee5da80bd8f074a9',
'0x9d8ee8c3d4f8b1e08803da274bdaff80c2204fc6',
'0x26bb5d139aa7bdb1380af0e1e8f98147ef4c406a',
'0x622e557aad13c36459fac83240f25ae91882127c',
'0xbf8b1630d5640e272f33653e83092ce33d302fd2',
'0xe37a3157cb3081ea7a96ba9f9e942c72cf7ad87b',
'0x175dae81345f36775db285d368f0b1d49f61b2f8',
'0xc26bda5f3370bdd46e7c84bdb909aead4d8f35f3']

To compile the contract, load the code from Voting.sol in to a string variable and compile it.

> code = fs.readFileSync('Voting.sol').toString()
> solc = require('solc')
> compiledCode = solc.compile(code)

When you compile the code successfully and print the ‘contract’ object (just type compiledCode in the node console to see the contents), there are two important fields you will notice which are important to understand:

  1. compiledCode.contracts[‘:Voting’].bytecode: This is the bytecode you get when the source code in Voting.sol is compiled. This is the code which will be deployed to the blockchain.
  2. compiledCode.contracts[‘:Voting’].interface: This is an interface or template of the contract (called abi) which tells the contract user what methods are available in the contract. Whenever you have to interact with the contract in the future, you will need this abi definition. You can read more details about ABI here

Let’s now deploy the contract. You first create a contract object (VotingContract below) which is used to deploy and initiate contracts in the blockchain.

> abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface)
> VotingContract = web3.eth.contract(abiDefinition)
> byteCode = compiledCode.contracts[':Voting'].bytecode
> deployedContract = VotingContract.new(['Rama','Nick','Jose'],{data: byteCode, from: web3.eth.accounts[0], gas: 4700000})
> deployedContract.address
> contractInstance = VotingContract.at(deployedContract.address)

VotingContract.new above deploys the contract to the blockchain. The first argument is an array of candidates who are competing in the election which is pretty straightforward. Let’s see what are all in the hash in the second argument:

  1. data: This is the compiled bytecode which we deploy to the blockchain.
  2. from: The blockchain has to keep track of who deployed the contract. In this case, we are just picking the first account we get back from calling web3.eth.accounts to be the owner of this contract (who will deploy it to the blockchain). Remember that web3.eth.accounts returns an array of 10 test accounts ganache created when we started the test blockchain. In the live blockchain, you can not just use any account. You have to own that account and unlock it before transacting. You are asked for a passphrase while creating an account and that is what you use to prove your ownership of that account. Ganache by default unlocks all the 10 accounts for convenience.
  3. gas: It costs money to interact with the blockchain. This money goes to miners who do all the work to include your code in the blockchain. You have to specify how much money you are willing to pay to get your code included in the blockchain and you do that by setting the value of ‘gas’. The ether balance in your ‘from’ account will be used to buy gas. The price of gas is set by the network.

We have now deployed the contract and have an instance of the contract (variable contractInstance above) which we can use to interact with the contract. There are hundreds of thousands of contracts deployed on the blockchain. So, how do you identify your contract in that blockchain? Answer: deployedContract.address. When you have to interact with your contract, you need this deployed address and abi definition we talked about earlier.

3. Interact with the contract in the nodejs console

> contractInstance.totalVotesFor.call('Rama')
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }
> contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]})
'0xdedc7ae544c3dde74ab5a0b07422c5a51b5240603d31074f5b75c0ebc786bf53'
> contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]})
'0x02c054d238038d68b65d55770fabfca592a5cf6590229ab91bbe7cd72da46de9'
> contractInstance.voteForCandidate('Rama', {from: web3.eth.accounts[0]})
'0x3da069a09577514f2baaa11bc3015a16edf26aad28dffbcd126bde2e71f2b76f'
> contractInstance.totalVotesFor.call('Rama').toLocaleString()
'3'

Try the above commands in your node console and you should see the vote count increment. Every time you vote for a candidate, you get back a transaction id: Example: ‘0xdedc7ae544c3dde74ab5a0b07422c5a51b5240603d31074f5b75c0ebc786bf53’ above). This transaction id is the proof that this transaction occurred and you can refer back to this at any time in the future. This transaction is immutable. This immutability is one of the big advantages of blockchains such as Ethereum. In future tutorials, we will build applications leveraging this immutability.

4. Webpage to connect to the blockchain and vote

Now that most of the work is done, all we have to do now is create a simple html file with candidate names and invoke the voting commands (which we already tried and tested in the nodejs console) in a js file. Below you can find the html code and the js file. Drop both of them in the hello_world_voting directory and open the index.html in your browser.

Text Box

<!DOCTYPE html>
<html>
<head>
  <title>Hello World DApp</title>
  <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
  <link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'>
</head>
<body class="container">
  <h1>A Simple Hello World Voting Application</h1>
  <div class="table-responsive">
    <table class="table table-bordered">
      <thead>
        <tr>
          <th>Candidate</th>
          <th>Votes</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Rama</td>
          <td id="candidate-1"></td>
        </tr>
        <tr>
          <td>Nick</td>
          <td id="candidate-2"></td>
        </tr>
        <tr>
          <td>Jose</td>
          <td id="candidate-3"></td>
        </tr>
      </tbody>
    </table>
  </div>
  <input type="text" id="candidate" />
  <a href="#" onclick="voteForCandidate()" class="btn btn-primary">Vote</a>
</body>
<script src="https://cdn.rawgit.com/ethereum/web3.js/develop/dist/web3.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
<script src="./index.js"></script>
</html>

Text Box

web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
abi = JSON.parse('[{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"totalVotesFor","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"validCandidate","outputs":[{"name":"","type":"bool"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"bytes32"}],"name":"votesReceived","outputs":[{"name":"","type":"uint8"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"x","type":"bytes32"}],"name":"bytes32ToString","outputs":[{"name":"","type":"string"}],"payable":false,"type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"candidateList","outputs":[{"name":"","type":"bytes32"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"candidate","type":"bytes32"}],"name":"voteForCandidate","outputs":[],"payable":false,"type":"function"},{"constant":true,"inputs":[],"name":"contractOwner","outputs":[{"name":"","type":"address"}],"payable":false,"type":"function"},{"inputs":[{"name":"candidateNames","type":"bytes32[]"}],"payable":false,"type":"constructor"}]')
VotingContract = web3.eth.contract(abi);
// In your nodejs console, execute contractInstance.address to get the address at which the contract is deployed and change the line below to use your deployed address
contractInstance = VotingContract.at('0x2a9c1d265d06d47e8f7b00ffa987c9185aecf672');
candidates = {"Rama": "candidate-1", "Nick": "candidate-2", "Jose": "candidate-3"}

function voteForCandidate() {
  candidateName = $("#candidate").val();
  contractInstance.voteForCandidate(candidateName, {from: web3.eth.accounts[0]}, function() {
    let div_id = candidates[candidateName];
    $("#" + div_id).html(contractInstance.totalVotesFor.call(candidateName).toString());
  });
}

$(document).ready(function() {
  candidateNames = Object.keys(candidates);
  for (var i = 0; i < candidateNames.length; i++) {
    let name = candidateNames[i];
    let val = contractInstance.totalVotesFor.call(name).toString()
    $("#" + candidates[name]).html(val);
  }
});
If you remember, we said earlier we will need the abi and the address to interact with any contract. You can see above in the index.js file how they are used to interact with the contract.This is what you should see when you open the index.html file in your browser.

If you are able to enter the candidate name in the text box and vote and see the vote count increment, you have successfully created your first application! Congratulations! To summarize, you set up your dev environment, coded a simple contract, compiled and deployed the contract on the blockchain and interacted with it via nodejs console and then through a webpage. Now would be a good time to pat yourself on the back if you haven’t already :)

In part 2, we will deploy this contract to the public test network so the entire world can see it and vote for a candidate. We will also get more sophisticated and use the truffle framework for development (and not have to use the nodejs console to manage the entire process). Hope this tutorial helped you get a practical idea on how to get started with developing decentralized application on the Ethereum platform.

As always thanks Raine Rupert Revere for corrections/edits of this post.

If you run into issues getting the application working, feel free to DM me on twitter @zastrinlab

======================================================

Full Stack Hello World Voting Ethereum Dapp Tutorial — Part 2

In part 1 of this tutorial, we built a simple voting application in our development environment using ganache. Now, let’s get this application on the real blockchain. Ethereum has a few public test blockchains and one main blockchain.

  1. Testnet: There are a few test blockchains such as Ropsten, Rinkeby, Kovan. Think of these as a QA or a staging server, they are used for testing purposes only. All the Ether you use on these networks is fake.
  2. Mainnet (also called Homestead): This is the blockchain which the entire world transacts on for real. There is real value to the Ether you use on this network.

In this tutorial, we will accomplish the following:

  1. Install geth — the client software used to download the blockchain and run the Ethereum node on your local machine.
  2. Install the Ethereum dapp framework called Truffle which will be used for compiling and deploying our contract.
  3. Make small updates to our Voting application to make it work using truffle.
  4. Compile and deploy the contract to the Rinkeby testnet.
  5. Interact with the contract through truffle console and then through a webpage.

1. Install geth and sync the blockchain

I have installed and tested everything on MacOS and Ubuntu. Installation is pretty straightforward:

On Mac:

mahesh@projectblockchain:~$ brew tap ethereum/ethereum
mahesh@projectblockchain:~$ brew install ethereum

On Ubuntu:

mahesh@projectblockchain:~$ sudo apt-get install software-properties-common
mahesh@projectblockchain:~$ sudo add-apt-repository -y ppa:ethereum/ethereum
mahesh@projectblockchain:~$ sudo apt-get update
mahesh@projectblockchain:~$ sudo apt-get install ethereum

You can find installation instructions for various platforms here: https://github.com/ethereum/go-ethereum/wiki/Building-Ethereum

Once you have installed geth, run the below command in your command line console:

mahesh@projectblockchain:~$ geth --rinkeby --syncmode "fast" --rpc --rpcapi db,eth,net,web3,personal --cache=1024  --rpcport 8545 --rpcaddr 127.0.0.1 --rpccorsdomain "*"

This will start the Ethereum node, connect to other peer nodes and start downloading the blockchain. The time it takes to download the blockchain depends on various factors like your internet connection speed, RAM on your computer, type of hard drive etc. It took me 30–45 minutes on a machine which has 8GB RAM and 50Mbps connection.

In the console where you have geth running, you will see the output like below. Look for the block number which is in bold. When your blockchain is fully sync’d, the block number you see will be close to the block number on this page: https://rinkeby.etherscan.io/

I0130 22:18:15.116332 core/blockchain.go:1064] imported   32 blocks,    49 txs (  6.256 Mg) in 185.716ms (33.688 Mg/s). #445097 [e1199364… / bce20913…]
I0130 22:18:20.267142 core/blockchain.go:1064] imported    1 blocks,     1 txs (  0.239 Mg) in  11.379ms (20.963 Mg/s). #445097 [b4d77c46…]
I0130 22:18:21.059414 core/blockchain.go:1064] imported    1 blocks,     0 txs (  0.000 Mg) in   7.807ms ( 0.000 Mg/s). #445098 [f990e694…]
I0130 22:18:34.367485 core/blockchain.go:1064] imported    1 blocks,     0 txs (  0.000 Mg) in   4.599ms ( 0.000 Mg/s). #445099 [86b4f29a…]
I0130 22:18:42.953523 core/blockchain.go:1064] imported    1 blocks,     2 txs (  0.294 Mg) in   9.149ms (32.136 Mg/s). #445100 [3572f223…]

2. Install the Truffle Framework

Install truffle using npm. The truffle version being used in this tutorial is 3.1.1.

npm install -g truffle

*Depending on your system setup, you might have to add a sudo at the beginning.

3. Set up the voting contract

First step is to set up the truffle project:

mahesh@projectblockchain:~$ mkdir voting
mahesh@projectblockchain:~$ cd voting
mahesh@projectblockchain:~/voting$ npm install -g webpack
mahesh@projectblockchain:~/voting$ truffle unbox webpack
mahesh@projectblockchain:~/voting$ ls
README.md contracts node_modules test webpack.config.js truffle.js
app migrations package.json
mahesh@projectblockchain:~/voting$ ls app/
index.html javascripts stylesheets
mahesh@projectblockchain:~/voting$ ls contracts/
ConvertLib.sol MetaCoin.sol Migrations.sol
mahesh@projectblockchain:~/voting$ ls migrations/
1_initial_migration.js 2_deploy_contracts.js

As you can see above, truffle creates the necessary files and directories required to run a full stack dapp. Truffle also creates a sample application to get you started (we won’t be using it in this tutorial). You can safely delete the ConvertLib.sol and MetaCoin.sol files in the contracts directory for this project.

It is important to understand the contents of the migrations directory. These migration files are used to deploy the contracts to the blockchain. (If you remember, in the previous post, we used VotingContract.new to deploy the contract to the blockchain, we don’t need to do that anymore). The very first migration 1_initial_migration.js deploys a contract named Migrations to the blockchain and is used to store the latest contract you have deployed. Every time you run the migration, truffle queries the blockchain to get the last contract that has been deployed and then deploys any contracts which haven’t been deployed yet. It then updates the last_completed_migration field in the Migrations contract to indicate the latest contract deployed. You can simply think of it as a database table called Migration with a column named last_completed_migration which is kept up to date always. You can find more details on the truffle documentation page.

Let’s now update the project with all the code we wrote in the previous tutorial with few changes explained below.

First, copy over the Voting.sol from the previous tutorial to the contracts directory (there are no changes to this file).

Text Box

pragma solidity ^0.4.18;
// We have to specify what version of compiler this code will compile with

contract Voting {
  /* mapping field below is equivalent to an associative array or hash.
  The key of the mapping is candidate name stored as type bytes32 and value is
  an unsigned integer to store the vote count
  */
  
  mapping (bytes32 => uint8) public votesReceived;
  
  /* Solidity doesn't let you pass in an array of strings in the constructor (yet).
  We will use an array of bytes32 instead to store the list of candidates
  */
  
  bytes32[] public candidateList;

  /* This is the constructor which will be called once when you
  deploy the contract to the blockchain. When we deploy the contract,
  we will pass an array of candidates who will be contesting in the election
  */
  function Voting(bytes32[] candidateNames) public {
    candidateList = candidateNames;
  }

  // This function returns the total votes a candidate has received so far
  function totalVotesFor(bytes32 candidate) view public returns (uint8) {
    require(validCandidate(candidate));
    return votesReceived[candidate];
  }

  // This function increments the vote count for the specified candidate. This
  // is equivalent to casting a vote
  function voteForCandidate(bytes32 candidate) public {
    require(validCandidate(candidate));
    votesReceived[candidate] += 1;
  }

  function validCandidate(bytes32 candidate) view public returns (bool) {
    for(uint i = 0; i < candidateList.length; i++) {
      if (candidateList[i] == candidate) {
        return true;
      }
    }
    return false;
  }
}
mahesh@projectblockchain:~/voting$ ls contracts/
Migrations.sol Voting.sol

Next, replace the contents of 2_deploy_contracts.js in the migrations directory with the following:

var Voting = artifacts.require("./Voting.sol");
module.exports = function(deployer) {
deployer.deploy(Voting, ['Rama', 'Nick', 'Jose'], {gas: 6700000});
};
/* As you can see above, the deployer expects the first argument to be the name of the contract followed by constructor arguments. In our case, there is only one argument which is an array of
candidates. The third argument is a hash where we specify the gas required to deploy our code. The gas amount varies depending on the size of your contract.
*/

You can also set the gas value as a global setting in truffle.js. Go ahead and add the gas option like below so in the future if you forget to set the gas in specific migration file, it will by default use the global value.

require('babel-register')
module.exports = {
networks: {
development: {
host: 'localhost',
port: 8545,
network_id: '*',
gas: 470000
}
}
}

Replace the contents of app/javascripts/app.js with the contents below.

Text Box

// Import the page's CSS. Webpack will know what to do with it.
import "../stylesheets/app.css";

// Import libraries we need.
import { default as Web3} from 'web3';
import { default as contract } from 'truffle-contract'

/*
 * When you compile and deploy your Voting contract,
 * truffle stores the abi and deployed address in a json
 * file in the build directory. We will use this information
 * to setup a Voting abstraction. We will use this abstraction
 * later to create an instance of the Voting contract.
 * Compare this against the index.js from our previous tutorial to see the difference
 * https://gist.github.com/maheshmurthy/f6e96d6b3fff4cd4fa7f892de8a1a1b4#file-index-js
 */

import voting_artifacts from '../../build/contracts/Voting.json'

var Voting = contract(voting_artifacts);

let candidates = {"Rama": "candidate-1", "Nick": "candidate-2", "Jose": "candidate-3"}

window.voteForCandidate = function(candidate) {
  let candidateName = $("#candidate").val();
  try {
    $("#msg").html("Vote has been submitted. The vote count will increment as soon as the vote is recorded on the blockchain. Please wait.")
    $("#candidate").val("");

    /* Voting.deployed() returns an instance of the contract. Every call
     * in Truffle returns a promise which is why we have used then()
     * everywhere we have a transaction call
     */
    Voting.deployed().then(function(contractInstance) {
      contractInstance.voteForCandidate(candidateName, {gas: 140000, from: web3.eth.accounts[0]}).then(function() {
        let div_id = candidates[candidateName];
        return contractInstance.totalVotesFor.call(candidateName).then(function(v) {
          $("#" + div_id).html(v.toString());
          $("#msg").html("");
        });
      });
    });
  } catch (err) {
    console.log(err);
  }
}

$( document ).ready(function() {
  if (typeof web3 !== 'undefined') {
    console.warn("Using web3 detected from external source like Metamask")
    // Use Mist/MetaMask's provider
    window.web3 = new Web3(web3.currentProvider);
  } else {
    console.warn("No web3 detected. Falling back to http://localhost:8545. You should remove this fallback when you deploy live, as it's inherently insecure. Consider switching to Metamask for development. More info here: http://truffleframework.com/tutorials/truffle-and-metamask");
    // fallback - use your fallback strategy (local node / hosted node + in-dapp id mgmt / fail)
    window.web3 = new Web3(new Web3.providers.HttpProvider("http://localhost:8545"));
  }

  Voting.setProvider(web3.currentProvider);
  let candidateNames = Object.keys(candidates);
  for (var i = 0; i < candidateNames.length; i++) {
    let name = candidateNames[i];
    Voting.deployed().then(function(contractInstance) {
      contractInstance.totalVotesFor.call(name).then(function(v) {
        $("#" + candidates[name]).html(v.toString());
      });
    })
  }
});

Replace the contents of app/index.html with the following. Even this file is pretty much the same as last chapter except the js file included is app.js on line 41.

Text Box

<!DOCTYPE html>
<html>
<head>
  <title>Hello World DApp</title>
  <link href='https://fonts.googleapis.com/css?family=Open+Sans:400,700' rel='stylesheet' type='text/css'>
  <link href='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css' rel='stylesheet' type='text/css'>
</head>
<body class="container">
  <h1>A Simple Hello World Voting Application</h1>
  <div id="address"></div>
  <div class="table-responsive">
    <table class="table table-bordered">
      <thead>
        <tr>
          <th>Candidate</th>
          <th>Votes</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Rama</td>
          <td id="candidate-1"></td>
        </tr>
        <tr>
          <td>Nick</td>
          <td id="candidate-2"></td>
        </tr>
        <tr>
          <td>Jose</td>
          <td id="candidate-3"></td>
        </tr>
      </tbody>
    </table>
    <div id="msg"></div>
  </div>
  <input type="text" id="candidate" />
  <a href="#" onclick="voteForCandidate()" class="btn btn-primary">Vote</a>
</body>
<script src="https://cdn.rawgit.com/ethereum/web3.js/develop/dist/web3.js"></script>
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js"></script>
<script src="app.js"></script>
</html>

4. Deploy the contract to Rinkeby test network

Before we can deploy the contract, we will need an account and some ether. When we used ganache, it created 10 test accounts and came preloaded with 100 test ethers. But for testnet and mainnet we have to create the account and add some ether ourselves.

In your command line terminal, do the following:

mahesh@projectblockchain:~/voting$ truffle console
truffle(default)> web3.personal.newAccount('verystrongpassword')
'0x95a94979d86d9c32d1d2ab5ace2dcc8d1b446fa1'
truffle(default)> web3.eth.getBalance('0x95a94979d86d9c32d1d2ab5ace2dcc8d1b446fa1')
{ [String: '0'] s: 1, e: 0, c: [ 0 ] }
truffle(default)> web3.personal.unlockAccount('0x95a94979d86d9c32d1d2ab5ace2dcc8d1b446fa1', 'verystrongpassword', 15000)
// Replace 'verystrongpassword' with a good strong password.
// The account is locked by default, make sure to unlock it before using the account for deploying and interacting with the blockchain.

In the previous post, we started a node console and initialized the web3 object. When we execute truffle console, all of that is done for us and we get a web3 object ready to use. We now have an account with address ‘0x95a94979d86d9c32d1d2ab5ace2dcc8d1b446fa1’ (you will have a different address in your case) and the balance will be 0.

You can get some test ether for Rinkeby network through the faucet here: https://faucet.rinkeby.io/. Try web3.eth.getBalance again to make sure you have ether. You can also enter your address on rinkeby.etherscan.io to see your account balance. If you can see a non-zero balance on rinkeby.etherscan.io but if web3.eth.getBalance still shows 0, it means your sync hasn’t completed. You just have to wait for your local blockchain to sync and catch up.

Now that you have some ether, go ahead and compile and deploy the contract to the blockchain. Below is the command to run and the output you will see if everything goes well.

* Do not forget to unlock the account before deploying your contract.

mahesh@projectblockchain:~/voting$ truffle migrate
Compiling Migrations.sol...
Compiling Voting.sol...
Writing artifacts to ./build/contracts
Running migration: 1_initial_migration.js
Deploying Migrations...
Migrations: 0x3cee101c94f8a06d549334372181bc5a7b3a8bee
Saving successful migration to network...
Saving artifacts...
Running migration: 2_deploy_contracts.js
Deploying Voting...
Voting: 0xd24a32f0ee12f5e9d233a2ebab5a53d4d4986203
Saving successful migration to network...
Saving artifacts...
mahesh@projectblockchain:~/voting$

On my machine, it took about 70–80 seconds to deploy the contracts.

5. Interacting with the voting contract

If you were able to deploy the contract successfully, you should now be able to fetch the vote count and also vote through truffle console.

mahesh@projectblockchain:~/voting$ truffle console
truffle(default)> Voting.deployed().then(function(contractInstance) {contractInstance.voteForCandidate('Rama').then(function(v) {console.log(v)})})
// After a few seconds, you should see a transaction receipt like this:
receipt:
{ blockHash: '0x7229f668db0ac335cdd0c4c86e0394a35dd471a1095b8fafb52ebd7671433156',
blockNumber: 469628,
contractAddress: null,
....
....
truffle(default)> Voting.deployed().then(function(contractInstance) {contractInstance.totalVotesFor.call('Rama').then(function(v) {console.log(v)})})
{ [String: '1'] s: 1, e: 0, c: [ 1] }

If you are able to do this, it’s a success, your contract is live and functional! Now, go ahead and start the the server

mahesh@projectblockchain:~/voting$ npm run dev

You should see the voting page at localhost:8080 and be able to vote and see the vote counts of all the candidates. Since we are dealing with a real blockchain, every write to the blockchain (voteForCandidate) will take a few seconds (The miners have to include your transaction in a block and the block to the blockchain).

If you see this page and are able to vote, you have a built a full fledged Ethereum application on the public test network, congratulations!

Since all your transactions are public, you can look at them here: https://rinkeby.etherscan.io/. Just enter your account address and it will show you all your transactions with timestamp.

Hopefully you were able to follow along and get the application working. You can find the all the files in the github repo here. If you run into issues getting the application working, feel free to DM me on twitter @zastrinlab.

===========================================================

Full Stack Hello World Voting Ethereum Dapp Tutorial — Part 3

In Part 1, we built a simple voting dapp and got it working on our local machine. In Part 2, we moved our app to use truffle framework and deployed it to the public Ropsten testnet and interacted with it through the truffle console and through a webpage. In this tutorial, we will add few more features to our voting dapp in order to learn a few key concepts. Here is what you will learn in this tutorial:

  1. Learn to use new data types like struct to organize and store data on the blockchain.
  2. Learn the concept of tokens and its usage.
  3. Learn to make payments using Ether, the currency of the Ethereum blockchain platform.

You can find all the code in chapter3 directory in this repository: https://github.com/maheshmurthy/ethereum_voting_dapp

As you may know, in a general election, every citizen gets to cast one vote for their favorite candidate. However there are elections like electing a board of directors of a company where you are a shareholder, you get to vote based on the number of shares you own in that company. So, the more shares you own, the more votes you get.

Let’s enhance our voting dapp to support this type of election. We will add functionality for anyone to purchase shares in the company. They can then use those shares to vote for the candidates. We will also add a feature to lookup voter information. In the Ethereum blockchain world, these shares are more commonly referred to as tokens. We will refer to these shares as tokens in the rest of this tutorial.

If you want to skip all the explanation and want to just see the contract file, you can find it here: https://github.com/maheshmurthy/ethereum_voting_dapp/blob/master/chapter3/contracts/Voting.sol.

The first step is to declare the variables we need to store all the information we are interested in. Below are the contract variables with explanation.

Text Box

// We use the struct datatype to store the voter information.
  struct voter {
    address voterAddress; // The address of the voter
    uint tokensBought;    // The total no. of tokens this voter owns
    uint[] tokensUsedPerCandidate; // Array to keep track of votes per candidate.
    /* We have an array called candidateList initialized below.
     Every time this voter votes with her tokens, the value at that
     index is incremented. Example, if candidateList array declared
     below has ["Rama", "Nick", "Jose"] and this
     voter votes 10 tokens to Nick, the tokensUsedPerCandidate[1] 
     will be incremented by 10.
     */
  }
/* mapping is equivalent to an associate array or hash.
 The key of the mapping is candidate name stored as type bytes32 
 and value is an unsigned integer which used to store the vote 
 count
 */
mapping (bytes32 => uint) public votesReceived;
mapping (address => voter) public voterInfo;
/* Solidity doesn't let you return an array of strings yet. We will 
 use an array of bytes32 instead to store the list of candidates
 */
bytes32[] public candidateList;
uint public totalTokens; // Total no. of tokens available for this election
uint public balanceTokens; // Total no. of tokens still available for purchase
uint public tokenPrice; // Price per token

In tutorial 1 and tutorial 2, we initialized the list of candidates contesting in a constructor. Remember that the constructor is invoked just once when the contract is deployed on the blockchain. Here, we also have to initialize the contract with total number of tokens available for sale and the cost of each token. So, we update our contract constructor like below:

/* When the contract is deployed on the blockchain, we will 
initialize the total number of tokens for sale, cost per token and
all the candidates
*/
function Voting(uint tokens, uint pricePerToken, bytes32[] candidateNames) public {
candidateList = candidateNames;
totalTokens = tokens;
balanceTokens = tokens;
tokenPrice = pricePerToken;
}

In truffle, you deploy your code on to the blockchain using migrations. You can take a peek at a migration file here. An example deploy call in truffle migration file looks like this:

deployer.deploy(Voting, 1000, web3.toWei('0.1', 'ether'), ['Rama', 'Nick', 'Jose']);
// 1000 is the total number of tokens for sale and the price of each token is set to 0.1 ether.
// We will revisit this section again later in this tutorial.

Now that we have initialized the tokens and set the price, let’s see how someone could purchase these tokens by paying ether. Here is the function to buy tokens.

/* This function is used to purchase the tokens. Note the keyword 
'payable' below. By just adding that one keyword to a function,
your contract can now accept Ether from anyone who calls this
function. Accepting money can not get any easier than this!
*/
function buy() payable public returns (uint) {
uint tokensToBuy = msg.value / tokenPrice;
if (tokensToBuy > balanceTokens) throw;
voterInfo[msg.sender].voterAddress = msg.sender;
voterInfo[msg.sender].tokensBought += tokensToBuy;
balanceTokens -= tokensToBuy;
return tokensToBuy;
}

An example purchase call looks like this:

truffle(development)> Voting.deployed().then(function(contract) {contract.buy({value: web3.toWei('1', 'ether'), from: web3.eth.accounts[1]})})

The value: web3.toWei(‘1’, ‘ether’) argument is accessed in the buy() function using msg.value and msg.sender gives us the account address of web3.eth.accounts[1]. Assuming the value of each token to be 0.1 Ether, the web3.eth.accounts[1] will receive 1 Ether/0.1 Ether = 10 tokens.

Let’s take a break from looking at the code for a moment and visualize the interaction between accounts (voters) and the contract.

As you can see in the contract file on github, the rest of the new methods in the contract are mostly getters and should be easy to follow along.

The index.html file has some new updates:

  1. To vote for a candidate, you now have to specify the no. of tokens you want to vote with.
  2. There is a new section where you can purchase tokens.
  3. You can now look up voter information — how many tokens they own and no. of votes they have cast to each candidate.
  4. The candidates are not hardcoded anymore. We fetch the candidates from the blockchain and populate it.

The app.js file has the updates to support all the UI functionality above.

Update the deployment file 2_deploy_contracts.js to pass in total tokens and token price along with candidate names.

var Voting = artifacts.require("./Voting.sol");
module.exports = function(deployer) {
deployer.deploy(Voting, 1000, web3.toWei('0.1', 'ether'), ['Rama', 'Nick', 'Jose']);
};

To summarize, the four files we have updated in this tutorial are Voting.sol, index.html, app.js and 2_deploy_contracts.js. Once you have updated your truffle repository with these files, we can deploy the contract to the blockchain. The deploy process is exactly the same as the previous tutorial.

You just have to compile and migrate using truffle command.

maheshmurthy|~/dev/ethereum_voting_dapp/chapter3$ truffle migrate
Using network 'development'.
Compiling Migrations.sol...
Compiling Voting.sol...
Writing artifacts to ./build/contracts
Running migration: 1_initial_migration.js
Deploying Migrations...
Migrations: 0xc9249947010675b8a3b1defb12334148f7f59010
Saving successful migration to network...
Saving artifacts...
Running migration: 2_deploy_contracts.js
Deploying Voting...
Voting: 0x795d6d1f7cf467f27e48181da5f1ebd5bbd0a8df
Saving successful migration to network...
Saving artifacts...

If you are able to successfully deploy the contract and start your web server, your page will look like below:

As you can see in the screenshot above, you will be able to purchase tokens, vote for candidates using the tokens and lookup voter information by their address. If you are able to get all these features working, congratulations!

I hope this series of tutorials has given you an idea of what Ethereum is, its capabilities, and how to build decentralized applications. If you run into issues getting the application working (github repo), feel free to DM me on twitter @zastrinlab.

You now know just enough Ethereum to be dangerous :)

Comments