Full Stack Hello World Voting Ethereum Dapp Tutorial — Part 1
https://medium.com/@mvmurthy/full-stack-hello-world-voting-ethereum-dapp-tutorial-part-1-40d2d0d807c2
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:
Set up the development environment.
Learn the process of writing a contract, compiling it and deploying it in your development environment.
Interact with the contract on the blockchain through a nodejs console.
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.
- 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 testrpc. In Part 2 of the tutorial, we will interact with the real blockchain. Below are the steps to install testrpc, 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.1. Instead of running npm install ethereumjs-testrpc web3 run npm install ethereumjs-testrpc web3@0.20.1 . I will update the tutorial once web3js 1.0 stable is released
Notice that the testrpc creates 10 test accounts to play with automatically. These accounts come preloaded with 100 (fake) ethers.
- 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 hello_world_voting directory. Now let’s compile the code and deploy it to testrpc 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:
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.
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:
data: This is the compiled bytecode which we deploy to the blockchain.
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 testrpc 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. Testrpc by default unlocks all the 10 accounts for convenience.
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.
-
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.
-
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.
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
If you want a more challenging project, I created a course to build a decentralized eBay on Ethereum & IPFS.
If you would like to get notified when I write more tutorials, you can subscribe here.
Thanks to Raine Rupert Revere.
EthereumBlockchainTutorial
One clap, two clap, three clap, forty?
By clapping more or less, you can signal to us which stories really stand out.
4.7K
137
Follow
Go to the profile of Mahesh Murthy
Mahesh Murthy
Techie, Foodie, Traveler, Founder www.zastrin.com
Related reads
Making Sense of “Cryptoeconomics”
Go to the profile of Josh Stark
Josh Stark
2.1K
Also tagged Ethereum
Enigma and Ethlend Partner to bring Secret Contracts to Decentralized Lending
Go to the profile of Enigma Project
Enigma Project
2K
Also tagged Tutorial
A Look Back At 2017 (I): Best Web UI Kits, Design Video Tutorials, and UI/UX Designers
Go to the profile of linda
linda
739
Responses
Write a response…
Applause from Mahesh Murthy (author)
Go to the profile of Prateesh
Prateesh
Jun 17, 2017
Steps to install testrpc in windows 10
Install Visual Studio Community Edition. If you choose a custom installation, the bare minimum items that need to be checked are all pertaining to Visual C++ (Current version is VS 2017)
Install the Windows SDK for Windows (If you are in Windows 10 install SDK…
Read more…
277
6 responses
Applause from Mahesh Murthy (author)
Go to the profile of Арсений Печенкин
Арсений Печенкин
Nov 19, 2017
web3.eth.accounts
For web3.version ‘1.0.0-beta.26’ this code doesn’t work. You can get accounts by executing this code web3.eth.getAccounts().then(console.log)
64
Applause from Mahesh Murthy (author)
Go to the profile of Diego Quintana Valenzuela
Diego Quintana Valenzuela
Oct 25, 2017
Just wondering if this might help someone: I ran into this problem
web3.eth.accounts
Error: Invalid JSON RPC response: undefined
at Object.InvalidResponse
...
Which is solved having the testrc service up and listening, for example in another terminal. More info in https…
Read more…
30
1 response
Applause from Mahesh Murthy (author)
Go to the profile of Steve Suranant
Steve Suranant
May 1, 2017
Cant thank you enough for writing this post, I have been struggling to find an updated document as you are. Your post helped me a lot in understanding how everything comes together.
13
Applause from Mahesh Murthy (author)
Go to the profile of Joe Cotroneo
Joe Cotroneo
Jan 31, 2017
Thanks for this very helpful introduction to contract coding.
After running testrpc I was getting an error trying to connect via node on my ubuntu 16.04 VM (using vagrant/virtualbox).
node
Web3 = require('web3')
web3 = new Web3(new > Web3.providers.HttpProvider("http:…
Read more…
7
1 response
Applause from Mahesh Murthy (author)
Go to the profile of John Charles McLaughlin
John Charles McLaughlin
Nov 6, 2017
Thanks so much for the article. As a learning exercise I converted the tutorial contents to 1.0 web3 bindings and set up a one line build for it.
https://github.com/mjhm/hello_world_dapp
5
Conversation with Mahesh Murthy.
Go to the profile of Justin Zhang
Justin Zhang
Aug 17, 2017
Thanks for the tutorial! I have a few questions:
What is contract.runtimeBytecode?
In the code the contractInstance is acquired using abi and address. I wonder why can’t we get the instance using address only and then get the abi from the instance?
Finally, is there a tool…
Read more…
1 response
Go to the profile of Mahesh Murthy
Mahesh Murthy
Aug 18, 2017
Here is the difference between bytecode and runtime bytecode: https://www.reddit.com/r/ethereum/comments/3pq08g/some_quick_things_about_verifying_contracts/cw8qn0d/
The contract address is like a pointer to your contract on the blockchain. And your contract is in bytecode so you can’t get ABI from it. Although, in the future…
Read more…
70
2 responses
Applause from Mahesh Murthy (author)
Go to the profile of Grant Herman
Grant Herman
Jun 15, 2017
You have done such an amazing job with this. I have read through so many articles and this was just such a good starting place
3
Applause from Mahesh Murthy (author)
Go to the profile of Grace Tan
Grace Tan
Oct 23, 2017
Hi all. I got Mahesh’s blessing to post my very simple Node app version of this tutorial, which can be found here: https://github.com/gtan66/voting-dapp. Hopefully this repo will help anyone with version issues, and people who are running into obscure issues.
Invalid Opcode error:
Read more…
17
Applause from Mahesh Murthy (author)
Go to the profile of Arthur Mastropietro
Arthur Mastropietro
Nov 16, 2017
Great tutorial, congrats for that, you provided a great service for the community.
For those who are not having votes updated when open in browser and click some votes, don’t forget to update your code with the address where the contract is deployed as pointed at index.js:
Read more…
3
Conversation with Mahesh Murthy.
Go to the profile of W. Cameron
W. Cameron
May 18, 2017
I tried to write your Node REPL contracts commands all in one script and it didn’t work, the deployedContract.address was always undefined. Following your instructions to use the REPL, however, worked perfectly. I’m trying to understand why that might be the case. Could you provide any insight into that?
1
1 response
Go to the profile of Mahesh Murthy
Mahesh Murthy
May 19, 2017
The only thing I can think of is, the deploy (VotingContract.new) is somehow happening asynchronously in your script. You can try creating a callback function and check the address in that function. Details: https://github.com/ethereum/wiki/wiki/JavaScript-API#web3ethcontract I would be curious to hear what you find out.
5
2 responses
Applause from Mahesh Murthy (author)
Go to the profile of josh pierro
josh pierro
Oct 21, 2017
Here is a pure js and material design port of this excellent tutorial. I look forward to doing the rest on Zastrin!
https://github.com/joshpierro/ethereum-voting-dapp
4
Applause from Mahesh Murthy (author)
Go to the profile of MANAS MAHAPATRA
MANAS MAHAPATRA
Oct 25, 2017
Thanks for this great small hands-on tutorial. I tried this on AWS and could get it working. Initially struggled with the web page running — then I observed while debugging the JS that browser was caching the older contract address. Thanks again!!
1
Applause from Mahesh Murthy (author)
Go to the profile of Alex Mochu
Alex Mochu
Nov 16, 2017
This has been very helpful. Thank you
1
Applause from Mahesh Murthy (author)
Go to the profile of Keith Holliday
Keith Holliday
Sep 26, 2017
Great post! Thanks for doing the whole example from scratch. It is nice to see how the full stack works without the framework at first.
1
Conversation with Mahesh Murthy.
Go to the profile of Piyush Ramavat
Piyush Ramavat
May 19, 2017
Hey Mahesh,
Thanks for this wonderful post.
I had one doubt though. Similar to gas payment for deploying the contract, don’t we have to pay gas for executing the transactions?
I mean when we call: contractInstance.voteForCandidate(), don’t we’ve to specify gas?
I know call(…
Read more…
1
1 response
Go to the profile of Mahesh Murthy
Mahesh Murthy
May 20, 2017
You do pay gas for any transactions which change the state. In this tutorial, you are only interacting with testrpc and it has default gas price and limit already set. You are just not explicitly specifying the gas price. Check your account balance, execute a transaction and check again, you will notice the balance would have gone down.
2
Applause from Mahesh Murthy (author)
Go to the profile of Grady Laksmono
Grady Laksmono
Nov 25, 2017
Thanks a lot for the tutorial. This should be part of the Ethereum.org Hello World :)
1
Conversation with Mahesh Murthy.
Go to the profile of Craig Skipsey
Craig Skipsey
Jan 25, 2017
Could we host the HTML and JavaScript files (and anything else needed for the front end) on IPFS? Making it a truly decentralised “hello world”!
3
2 responses
Go to the profile of Mahesh Murthy
Mahesh Murthy
Jan 25, 2017
For sure, that would be awesome! I haven’t tried it yet, let me know if you get it working.
3
Applause from Mahesh Murthy (author)
Go to the profile of Partha SK
Partha SK
Jul 12, 2017
Tried all the steps and it works perfectly fine! Thanks Mahesh for putting this together.
1
Applause from Mahesh Murthy (author)
Go to the profile of InverseFunction
InverseFunction
Jun 28, 2017
Thanks Mahesh.
Nice article. I was struggling to get this done since long time but due to outdated articles, I was always getting stuck.
Finally I got this done.
Thanks a ton again
1
Applause from Mahesh Murthy (author)
Go to the profile of Jackson Ng
Jackson Ng
Sep 1, 2017
Murthy, thank you very much for writing this. This is probably the best tutorial I have come across that covers Ethereum, Smart Contract and Truffle.
I followed your tutorial and made some changes along the way so that I can have it running on Google Cloud and have users execute smart contract through the DApp on their…
Read more…
1
4.7K
Go to the profile of Mahesh Murthy
Never miss a story from Mahesh Murthy, when you sign up f