Full Stack Hello World Voting Ethereum Dapp Tutorial — Part 1

Mahesh Murthy
8 min readJan 18, 2017

--

[Tutorial was last updated in March 2020 to use the latest libraries]

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

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. If anyone can post updated instructions for Windows, I will be happy to link it here.

mahesh@zastrin:~$ npm -v
6.1.0
mahesh@zastrin:~$ node -v
v13.11.0
mahesh@zastrin:~$ mkdir -p ethereum_voting_dapp/chapter1/
mahesh@zastrin:~$ cd ethereum_voting_dapp/chapter1
mahesh@zastrin:~/ethereum_voting_dapp/chapter1$ npm install ganache-cli web3@1.2.6
mahesh@zastrin:~/ethereum_voting_dapp/chapter1$ node_modules/.bin/ganache-cli
The output should look like belowGanache CLI v6.3.0 (ganache-core: 2.4.0)Available Accounts==================(0) 0x66d1dda957bc7a087324130c89547ce579cee563 (~100 ETH)(1) 0xf98e7d03f312c8329d01ef0642b74e77740cc203 (~100 ETH)(2) 0x71d4ee31cd935d17a2b00b7d8873651d6aefbf73 (~100 ETH)(3) 0x2fdaa99748e6224e03e3e5a1a9a89abd906df671 (~100 ETH)(4) 0xfb32d320a858747453ac1b4e23c849fecd6ebf33 (~100 ETH)(5) 0x2c00cd8a488a8ae569553dfe90bf90d65af97630 (~100 ETH)(6) 0xa4099d0d4a0e7ce5bf26c3f4078a001daf5cedff (~100 ETH)(7) 0xa53c14d56683bdc775c19540679b0809bbf95a2b (~100 ETH)(8) 0x3ba642d43a2a24a0160fa22c358cf697aa4a627f (~100 ETH)(9) 0x81c43af78fdb4a2c8078ec37875e9616e3c5a3e4 (~100 ETH)Private Keys==================(0) 0xee670c7915b5e73b6f5c82da3919701f19ed1f72a1d4f31007836930623f4a57(1) 0xf40063c41978799ff6fa4b85d678b0f42ed6c774c35fa883a289fdc7fa0b65cb(2) 0x5228a5e30d1be11885cd7d44d4a47b1dfa22db4033cd758a1c3677a3a0cb5383(3) 0x3520c609b830538bd8c5d05c8f53338322411deb477308c5543f20a420fea5ec(4) 0xa7728cbc1eee41d696cb1d252157fc66ab1726ff751f2132c387726b5c901c35(5) 0xe459627dc49d59da76c393b40c36c674c8307ec52c24794a33ddc773f3c229fc(6) 0xa65715e3bdc8236420491de88486ff301a19b624b006811a89742e74120eac50(7) 0xc95ab6498d506f45b4b8ab2b04967d51e05af41059334df91d63097cb3254a3b(8) 0xf0619031f2ba4319aae691ce34fe8cce136640fb715b70d5baa045c2d58f1b80(9) 0x39a85154d16a1eba4a9f8514f187bcb6c8b867b790035afa9f92bf2731aebc5bHD Wallet==================Mnemonic: rather online beyond apology whale cheese game ankle together share potato leisureBase HD Path: m/44'/60'/0'/0/{account_index}

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:

Copy the above code to a file named Voting.sol in the ethereum_voting_dapp/chapter1 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. Then use the compiler to compile the contract

mahesh@zastrin:~/ethereum_voting_dapp/chapter1$ npm install solc@0.6.4
mahesh@zastrin:~/ethereum_voting_dapp/chapter1$ node_modules/.bin/solcjs --bin --abi Voting.sol
mahesh@zastrin:~/ethereum_voting_dapp/chapter1$ ls
Voting.sol Voting_sol_Voting.abi Voting_sol_Voting.bin

When you compile the code successfully using the command above, the compiler outputs 2 files that are important to understand:

  1. Voting_sol_Voting.bin: 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. Voting_sol_Voting.abi: 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

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 web3 object. All the code snippets below need to be typed in the node console.

mahesh@zastrin:~/ethereum_voting_dapp/chapter1$ node> Web3 = require('web3')> web3 = new Web3("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.getAccounts(console.log)['0x9c02f5c68e02390a3ab81f63341edc1ba5dbb39e',
'0x7d920be073e92a590dc47e4ccea2f28db3f218cc',
'0xf8a9c7c65c4d1c0c21b06c06ee5da80bd8f074a9',
'0x9d8ee8c3d4f8b1e08803da274bdaff80c2204fc6',
'0x26bb5d139aa7bdb1380af0e1e8f98147ef4c406a',
'0x622e557aad13c36459fac83240f25ae91882127c',
'0xbf8b1630d5640e272f33653e83092ce33d302fd2',
'0xe37a3157cb3081ea7a96ba9f9e942c72cf7ad87b',
'0x175dae81345f36775db285d368f0b1d49f61b2f8',
'0xc26bda5f3370bdd46e7c84bdb909aead4d8f35f3']

To compile the contract, load the bytecode and abi from the file system in to a string like below

> bytecode = fs.readFileSync('Voting_sol_Voting.bin').toString()
> abi = JSON.parse(fs.readFileSync('Voting_sol_Voting.abi').toString())

Let’s now deploy the contract. You first create a contract object (deployedContract) which is used to deploy and initiate contracts in the blockchain. Note: Replace the ‘from’ value below with one of the addresses generated by your ganache blockchain.

> deployedContract = new web3.eth.Contract(abi)
> listOfCandidates = ['Rama', 'Nick', 'Jose']
> deployedContract.deploy({
data: bytecode,
arguments: [listOfCandidates.map(name => web3.utils.asciiToHex(name))]
}).send({
from: 'ENTER 1 OF 10 ACCOUNT ADDRESSES like 0xfb3....',
gas: 1500000,
gasPrice: web3.utils.toWei('0.00003', 'ether')
}).then((newContractInstance) => {
deployedContract.options.address = newContractInstance.options.address
console.log(newContractInstance.options.address)
});

We use the web3 deploy function along with send to deploy the contract to the blockchain. Let’s see what are all the arguments we pass to deploy and send functions:

  1. data: This is the compiled bytecode which we deploy to the blockchain.
  2. arguments: These are the arguments we pass to the constructor of the contract. In our case we pass an array of candidate names. Note that we have to explicitly convert string to bytes32, that’s why we call web3.utils.asciiToHex on each candidate name (using map function).
  3. 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.getAccounts to be the owner of this contract (who will deploy it to the blockchain). Remember that web3.eth.getAccounts 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.
  4. 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.
  5. gasPrice: Each unit of gas has a price associated with it. That is set in the gasPrice field.

We have now deployed the contract and have an instance of the contract (variable deployedContract 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.options.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

> deployedContract.methods.totalVotesFor(web3.utils.asciiToHex('Rama')).call(console.log)> deployedContract.methods.voteForCandidate(web3.utils.asciiToHex('Rama')).send({from: 'YOUR ACCOUNT ADDRESS'}).then((f) => console.log(f))> deployedContract.methods.totalVotesFor(web3.utils.asciiToHex('Rama')).call(console.log)

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 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 ethereum_voting_dapp/chapter1 directory and open the index.html in your browser. Note: You have to update the contract address in index.js where specified.

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.

open the index.html in your browser and you should see something like this.

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 or email mahesh@zastrin.com.

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

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

--

--

Mahesh Murthy

Building www.boringcrypto.xyz - a community owned forum for non price crypto discussions.