ICON DAPP From A-Z Part 3: ICON Dice Roll DAPP

This is part 3 of a tutorial series, in continuation to Part 1: Tools & Environment and Part 2: SCORE, it is highly recommended that you finish previous tutorials before reading on.

Level: Intermediate

Prerequisites

Programming Concepts ★★★☆☆

Python ★★★★

Python Web Framework Flask ☆☆☆☆☆

T-Bears (Local Emulated ICON Node) ★★★★★

SCORE (Smart Contract) ★★★★★

ICON Workshop SF Blockchain Week

The presented DAPP is ICON Dice Roll, but it is really a coin flip game. The application logic is much the same, it takes a predefined input to compare against the generated result. In a coin flip game, there are 2 possible outcomes, heads or tails. In a real dice roll, there are 6 possible outcomes from 1 to 6 for each side. In the Ethereum casino game Ethroll, there are 100 possible outcomes from 1 to 100. With minor tweaks, this DAPP can work like a real dice roll or Ethroll game.

By the end of this tutorial, you’ll build a functional betting DAPP on the ICON network, let’s get started!

# Create a new environment for this DAPP project
$ mkdir WORKSHOP && cd WORKSHOP
$ pwd
# .../icon-tutorial/WORKSHOP
# First clone the workshop project from github
$ git clone https://gitlab.com/ibriz/icon-dice-roll.git
$ cd icon-dice-roll
# Have a glance of the files we cloned
$ ls -1
# 'ICON Workshop Guide.pdf'
# README.md
# config/
# dice-roll/
# keystores/
# testcmdline/
# webapp/

The included ICON Workshop Guide.pdf seems a bit broken in layout and README.md doesn’t contain full instructions, so ignore or delete those. The most up-to-date version of the presentation slide can be found here: ICON Workshop Guide.pdf

The project organized our tbears_cli_config files to the config folder, keystore files to keystores folder and JSON-RPC call json files to testcmdline. The project also built a front end to display results on a web page, using Flask, all under webapp folder.

DiceRoll SCORE

Let’s dig into the SCORE first,

I’ve added more explanations to the source file above, the SCORE is fairly straight forward implementation. It will take ICX transfers (bets), does a coin flip to determine if the bet was won or lost. Winning bets will receive a transfer of 1.98x the betting amount.

Deploy DiceRoll SCORE to Localhost

Let’s deploy the SCORE to localhost first and test it out,

$ tbears deploy dice-roll -k keystores/keystore_test1.json -c config/tbears_cli_config.json

and use test1_Account as keystore password.

# Check if deployment was successful
$ tbears txresult 0xd6bf8f864cb12eaf12c94d1af97192e3b95290248b00b87a42a31bb0dd344192

This SCORE is basically the house taking bets, let’s check the treasury balance first, you can use the get_treasury method, but it is really just checking the contract’s balance, so let’s just use tbears.

# Check the balance of scoreAddress
$ tbears balance cx6f030fceecce9adad0fa967b79ed46151d292576

balance in decimal: 0

We need to topup the house balance with set_treasury, first open testcmdline/send_set_treasury.json

# testcmdline/send_set_treasury.json
{
"jsonrpc": "2.0",
"method": "icx_sendTransaction",
"params": {
"version": "0x3",
"from": "hxe7af5fcfd8dfc67530a01a0e403882687528dfcb",
"value": "0x6f05b59d3b200000",
"stepLimit": "0x200000",
"nid": "0x3",
"nonce": "0x2",
"to": "cx6f030fceecce9adad0fa967b79ed46151d292576",
"dataType": "call",
"data": {
"method": "set_treasury"
}
},
"id": 1
}

and change “to” address to the scoreAddress on our localhost. The value in the example is ‘0x6f05b59d3b200000’, using Unit Converter, it is 8 ICX.

# Make the transaction
$ tbears sendtx -k keystores/keystore_test1.json -c config/tbears_cli_config.json testcmdline/send_set_treasury.json
# use test1_Account as keystore password

Check balance again,

$ tbears balance cx6f030fceecce9adad0fa967b79ed46151d292576

balance in decimal: 8000000000000000000 (8 ICX).

Create a Webpage to Display Results

The workshop uses the Python web framework Flask to create the webpage frontend, we’ll explain more about this later, first let’s install it

$ pip install flask

then open webapp/main.py and modify the default SCORE address to our localhost SCORE address

# webapp/main.pydefault_score = "cx6f030fceecce9adad0fa967b79ed46151d292576"

We’ll be running the built-in development server which will occupy the terminal while running, let’s launch a new terminal window first,

# New terminal window
$ cd <...>/icon-tutorial/
# We installed flask into the virtualenv, so activate it first
$ source venv/bin/activate
# go back to webapp directory
$ cd icon-dice-roll/webapp

Then run the program which will spin up the development server,

$ python main.py# minimize the window, and go back to the original terminal

Launch a browser of your choice and visit

http://localhost:5000

You should see a dancing coin without any data.

Let’s place our first bet using the same wallet, first edit testcmdline/send_bet.json and assign the destination address to our own SCORE,

#testcmdline/send_bet.json"to": "cx6f030fceecce9adad0fa967b79ed46151d292576",

The value is “0xde0b6b3a7640000” which is 1 ICX, now bet it

$ tbears sendtx -k keystores/keystore_test1.json -c config/tbears_cli_config.json testcmdline/send_bet.json# use test1_Account as keystore password

You could check the balance with tbears, but since we have a webpage to display the results and balances nicely, let’s just go to the browser that has http://localhost:5000/ open, the results should refresh automatically every 60 seconds.

Send a few more bets by executing the same send_bet.json, how was your luck?

Deploy to testnet

In the next step we’ll deploy the contract to testnet, at this point you should be quite familiar with the process so we’ll go straight ahead with the deployment without much explanation. The project provided a keystore ‘keystore1.json’ that is shared by everybody following this tutorial, so make sure there’s still enough balance in there, if not, request from the faucet page.

The project has already prepared a testnet config in the config/ folder, but the code is deprecated, replace tbears_cli_config_testnet.json with

# /config/tbears_cli_config_testnet.json
{
"uri": "https://bicon.net.solidwallet.io/api/v3",
"nid": "0x3",
"keyStore": null,
"from": "hxe9d75191906ccc604fc1e45a9f3c59fb856c215f",
"to": "cx0000000000000000000000000000000000000000",
"deploy": {
"stepLimit": "0x5a000000",
"contentType": "zip",
"mode": "install"
},
"txresult": {},
"transfer": {}
}

Then deploy to testnet,

$ tbears deploy dice-roll -k keystores/keystore1.json -c config/tbears_cli_config_testnet.json# use password: p@ssword1

Check transaction result and copy the SCORE address,

$ tbears txresult 0xe0e001ad0eaef54ba62f1cc6ba757899de0c95ffa4af4c0dd3b32b7587d72f60 -u https://bicon.net.solidwallet.io/api/v3

Topup the house balance on testnet,

# testcmdline/send_set_treasury.json "from": "hxe9d75191906ccc604fc1e45a9f3c59fb856c215f", 
"to"
: "cxd73fdab694c5bbb3b489f760bcae767c301ae4dc",

then execute it

$ tbears sendtx -k keystores/keystore1.json -c config/tbears_cli_config_testnet.json testcmdline/send_set_treasury.json

Check SCORE balance directly on testnet https://bicon.tracker.solidwallet.io/contract/cxd73fdab694c5bbb3b489f760bcae767c301ae4dc

Edit the webapp/main.py and change default_score to our testnet SCORE address, icon_service to the testnet API endpoint,

# webapp/main.py
default_score = "cxd73fdab694c5bbb3b489f760bcae767c301ae4dc"
icon_service = IconService(HTTPProvider("https://bicon.net.solidwallet.io/api/v3"))

Kill the 2nd terminal that is running our flask development server by ctrl-c<enter>

Re-run the service

python main.py

Now open http://localhost:5000 again, this page will monitor our transactions on the testnet.

Placing Bets Through ICONex to Testnet

Launch your ICONex, remember to point your ICONex to testnet

Start betting!

Remember to slightly up your step limit as this involves a contract call, we’ll go with 500,000 steps.

You should see results in http://localhost:5000,

Note that payouts are internal transactions, that means they’re not real transactions with signatures and included in the blockchain. They’re contracts initiating a value transfer, so you won’t see the transaction history in your ICONex wallet, you’ll check the contract’s ‘Internal Transactions tab’ instead,

Python Web Framework

We skipped this earlier, because there’s a bit of learning to do and involves some kind of Python web frameworks holy war. You’ll find about ten thousand discussions on Django vs Flask. To give you a very short summary, Flask is a bare bone Python web framework, it provides simplicity, flexibility and fine-grained control. It is suited when your web app only needs exactly the web stack: requests, routing and responses, just about all we need.

For the purpose of this tutorial, I also reviewed several learning resources, my choice is Pocoo’s official site. One of the members from the Pocoo group, Armin Ronacher, was the creator of Flask.

If you’re looking to get started asap, visit:

Flask 1.0.2 documentation — Quickstart

If you’re looking to get a full understanding, visit:

Flask 1.0.2 documentation — Tutorial

It is ideal that you go through the entire tutorial, it will be helpful and a very handy skill set to have down the road. You’ll be able to build all kinds of web applications, create prototype mock-ups, and further strengthen your knowledge in Python. Depending on your previous knowledge of web frameworks and familiarity of Python, the full tutorial should take from 1–2 days to a week or two.

Flask Webapp Revisited

Let’s go back to our webapp, our default route is to the root URL with the main function that renders index.html.

index.html loads the necessary resources, including an important js file that invokes all the data requests and updates, under static/poll-dice.js

As soon as document is ready, it calls for /getLatestTx, which under our main.py would call latest_transactions function. Under this function we invoke a call to Python SDK, and call the external function get_results in our SCORE. The script would poll for new data every minute to see if data have been altered and update the page accordingly.

Deploy to Production Environment

Flask’s built-in development server is not suitable for production as it doesn’t scale well, nor is it stable, we want to use a real WSGI application server. There are a number of ways you can deploy your application to a production environment, you can check Deployment Options to find a suitable setting.

I’ll briefly cover my settings under Apache2 using mod_wsgi

# Install mod_wsgi and enable it
$ sudo apt-get install libapache2-mod-wsgi
$ a2enmod wsgi

Domain: dapps.icon.support

Port: 443 (SSL)

|/var/www/dapps.icon.support/
|-- icon-dice-roll/
|---- keystores/
|---- main.py
|---- repeater.py
|---- static/
|---- templates/
|---- webapp.wsgi

keystore/ is now saved in a different location so you’ll need to modify it under main.py

# main.py 
'wallet1': KeyWallet.load("/<path to>/keystore_test1.json", "test1_Account"),

Create an wsgi interface between Apache2 and your app,

# webapp.wsgi#!/usr/bin/python
import sys
sys.path.insert(0,"/var/www/dapps.icon.support/icon-dice-roll")
from main import app as application

Under /etc/apache2/sites-available/, create a new configuration file

/etc/apache2/sites-available/dapps.icon.support-le-ssl.conf<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerAdmin 2infiniti@gmail.com
ServerName dapps.icon.support
ServerAlias www.dapps.icon.support
DocumentRoot /var/www/dapps.icon.support/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
WSGIDaemonProcess dice user=flaskuser group=flaskgroup threads=5
WSGIScriptAlias /icon-dice-roll /var/www/dapps.icon.support/icon-dice-roll/webapp.wsgi
<Directory /var/www/dapps.icon.support/icon-dice-roll>
WSGIProcessGroup dice
WSGIApplicationGroup %{GLOBAL}
WSGIScriptReloading On
Require all granted
</Directory>
RewriteEngine on
SSLCertificateFile /etc/letsencrypt/live/dapps.icon.support/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/dapps.icon.support/privkey.pem
Include /etc/letsencrypt/options-ssl-apache.conf
</VirtualHost>
</IfModule>

Note that we have WSGIScriptReloading On, so you do not need to restart the server after making changes, simply do a touch webapp.wsgi. For apache2.4+, remember to use Require all granted directive under Directory, instead of the deprecated Allow from all.

Enable the site,

# Create sym link to sites-enabled
$ a2ensite /etc/apache2/sites-available/dapps.icon.support-le-ssl.conf
# Restart apache
$ systemctl restart apache2

Then visit the site and see if everything works, https://dapps.icon.support/icon-dice-roll

That’s it for this workshop! In this tutorial we stitched together all the components we’ve learned so far, from ICON Python SDK, T-Bears, SCORE development, testnet deployment and ICONex interaction with SCOREs. We also learned to build a web frontend to display data queried from our SCORE smart contract. Technically speaking this is already an ICON DAPP, even though not a very functional nor a fun one, but we’ll eventually get there!

If we want to extend on this idea to the Ethroll game, we could tweak the winning logic slightly, connect to ICONex wallet extension and allow placing bets on the website. Once deployed to ICON mainnet, the app can take real ICX bets, and we’ll have our real casino app!

I’ll leave the imagination to you, for now, you’re trained enough to build your own ICON DAPP!

Level Up!

Programming Concepts ★★★★

Python ★★★★

Python Web Framework Flask ★★★★

ICON SDK ★★★★★

T-Bears (Local Emulated ICON Node) ★★★★★

SCORE (Smart Contract) ★★★★★

Follow me on Twitter for most up-to-date ICON related content: https://www.twitter.com/2infiniti