Full Stack Hello World Voting Ethereum Dapp Tutorial — Part 2

[Tutorial was last updated in November 2018]

This is part 2 of 3 part series of tutorials. You can access Part 1 and Part 3 here.

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

It takes a many hours to sync the chain depending on your hardware and internet speed. You can skip this step and continue to use ganache if you are unable to sync the chain.

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 --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 scripts styles
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).

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.

module.exports = {
networks: {
ganache: {
host: 'localhost',
port: 8545,
network_id: '*',
gas: 4700000

Replace the contents of app/scripts/index.js with the contents below.

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.

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')
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 --network ganache
[Network name should be whatever you have in your truffle.js]
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...

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 --network ganache
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:
{ 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.

If you liked this tutorial, you might like many more interesting real-world project based courses at www.zastrin.com

As always thanks for the ever helpful Raine Rupert Revere for all the feedback and to Craig Skipsey for finding all the bugs!

If you would like to get notified when I write more tutorials, you can subscribe here.