Pizza Hackathon was the 1st blockchain hackathon event in Thailand which was held on 25-26 August 2018. The objective of this event was to educate blockchain technologies as well as building up thai blockchain developers. The event consisted of education and project hacking sessions in which all participating developers had freedom to develop any project based on any blockchain technologies. There was eventually the project competition among teams of developers at the end of the event.
To find the winning team, we developed a voting system named PizzaCoin. PizzaCoin is a voting system based on Ethereum blockchainβs smart contract compatible with ERC-20 token standard. Each event participant (i.e., all participating developers and all event staffs) would be registered to PizzaCoin contract. The contract allowed a group of developers create and join a team. Meanwhile, any authorized staff was able to perform operations such as revoking some developer from a team, revoking a whole team, changing contract states, etc. All participants would receive equal voting tokens. With PizzaCoin contract, a participating developer was able to give his/her votes to any favourite projects developed by other different teams whereas a staff had freedom to vote to any teams. Each voter could spend voting tokens according to his/her own balance. Specifically, all voting results would be transacted and recorded on the blockchain. As a result, the winning team, who got maximum voting tokens, was judged transparently by the developed PizzaCoin contract automatically without any possible interference even by any event staff.
One of the biggest challenges when developing Ethereum smart contract is to find a solution to handling βOut-of-Gasβ error during deploying the contract onto the blockchain network, due to some block gas limits on Ethereum blockchain. The prototype of our PizzaCoin contract also confronted with these limitations since our contract requires several functional subsystems such as staff management, team and player management, and voting management subsystems. To avoid block gas limit problems, PizzaCoin contract was designed and developed using several advanced concepts and techniques.
PizzaCoin contract consists of eight dependencies including three contracts: PizzaCoinStaff, PizzaCoinPlayer and PizzaCoinTeam, and five libraries: PizzaCoinStaffDeployer, PizzaCoinPlayerDeployer, PizzaCoinTeamDeployer, PizzaCoinCodeLib and PizzaCoinCodeLib2.
PizzaCoin contract acts as a mother contract of all dependencies. In more detail, the contract has three special children contracts, namely PizzaCoinStaff, PizzaCoinPlayer and PizzaCoinTeam contracts which would be deployed by the three deployer libraries named PizzaCoinStaffDeployer, PizzaCoinPlayerDeployer and PizzaCoinTeamDeployer respectively. Furthermore, PizzaCoin contract also has another two proxy libraries named PizzaCoinCodeLib and PizzaCoinCodeLib2 which would be used as libraries for migrating source code of PizzaCoin mother contract.
There are two stages when deploying PizzaCoin contract onto the blockchain. In the first stage, PizzaCoin contract's dependencies including PizzaCoinStaffDeployer, PizzaCoinPlayerDeployer, PizzaCoinTeamDeployer, PizzaCoinCodeLib and PizzaCoinCodeLib2 libraries have to be deployed onto the blockchain one by one as separate transactions. The previously deployed libraries' addresses would then be linked and injected as dependency instances in order to deploy PizzaCoin mother contract to the ethereum network as illustrated in Figure 2.
In the second stage, the previously deployed PizzaCoin mother contract must get initialized by a project deployer (a staff who previously deployed PizzaCoin contract). A project deployer initiates three transactions (steps 1.1, 2.1 and 3.1) in order to deploy PizzaCoin children contracts--including PizzaCoinStaff, PizzaCoinPlayer and PizzaCoinTeam contracts--as shown in Figure 3. At this point, we employed a contract factory pattern using the deployer libraries, i.e. PizzaCoinStaffDeployer, PizzaCoinPlayerDeployer and PizzaCoinTeamDeployer, to deploy each corresponding child contract (steps 1.2 - 1.3, 2.2 - 2.3 and 3.2 - 3.3). The resulting children contracts' addresses would then be returned to store on PizzaCoin contract (steps 1.4, 2.4 and 3.4). This way makes PizzaCoin contract know where its children contracts are located on the ethereum blockchain.
Figure 4. PizzaCoin contract acts as a contract coordinator for PizzaCoinStaff, PizzaCoinPlayer and PizzaCoinTeam contracts
On the prototype of PizzaCoin contract, we faced 'Out-of-Gas' error when deploying the contract because the contract contains too many function definitions. The solution to avoiding such the error we have used on a production version is to migrate almost all the logical source code of each function on PizzaCoin contract to store on proxy libraries named PizzaCoinCodeLib and PizzaCoinCodeLib2 instead
as depicted in Figure 4.
PizzaCoin contract is considered as a contract coordinator or a reverse proxy contract
for PizzaCoinStaff, PizzaCoinPlayer and PizzaCoinTeam contracts. When a user needs to interact with any contract function, a user just makes a call to PizzaCoin contract right away. For example, a user wants to join some specific team, he/she can achieve this by invoking registerPlayer function on PizzaCoin contract. The contract would then interact with its children contracts in order to do register the calling user as a player to the specified team.
In more technical detail when a user makes a call to PizzaCoin.registerPlayer() function on PizzaCoin contract, the function will instead forward the request to the delegated function named PizzaCoinCodeLib.registerPlayer() on the proxy library PizzaCoinCodeLib in order to process the requesting transaction on behalf of PizzaCoin contract. Next, the delegated function will hand over the process to the real worker function named PizzaCoinPlayer.registerPlayer() which is on PizzaCoinPlayer child contract. With these code migration techniques, we can significantly reduce gas consumption when deploying the PizzaCoin mother contract.
There are five states representing the status of PizzaCoin contract including Initial, Registration, Registration Locked, Voting and Voting Finished. Each state defines a different working context to the contract and it is changable by a staff privilege only. The contract state is unidirectional as illustrated in Figure 5. This means that if the state has been changed from one to another, we cannot change it back to any previous state.
Initial is the first state that is automatically set during PizzaCoin contract getting deployed. The contract state can be changed from Initial to Registration if and only if all the three children contracts (i.e., PizzaCoinStaff, PizzaCoinPlayer and PizzaCoinTeam contracts) have been created by a project deployer (a staff who deployed PizzaCoin contract). A project deployer can create the children contracts by invoking the following functions on PizzaCoin contract in no particular order: createStaffContract, createPlayerContract and createTeamContract (steps 1.1, 2.1 and 3.1 in Figure 3).
Once PizzaCoin contract's state is changed to Registration, the contract is opened for registration. During this state, a staff can register a selected user as a new staff. A player can create a team and/or join to an existing team. Furthermore, a staff is allowed to revoke some player from a specific team or even revoke a whole team if necessary. PizzaCoin contract would be closed for registration once the state is changed to Registration Locked. Later, a staff can enable voting by changing the contract state to Voting. The vote would be opened until the contract state is moved to Voting Finished. In this state, PizzaCoin contract would determine the winning team automatically.
Let's say a staff changes PizzaCoin contract's state from Registration Locked to Voting. Figure 6 illustrates how PizzaCoin contract interacts with its children contracts. What happens is that as soon as a staff executes PizzaCoin.startVoting() function on PizzaCoin contract (step 1), the function would call to the delegated function PizzaCoinCodeLib2.signalChildrenContractsToStartVoting() on PizzaCoinCodeLib2 library (step 2). Later, the delegated function would order all the three children contracts to change their state to Voting by respectively executing PizzaCoinStaff.startVoting(), PizzaCoinPlayer.startVoting() and PizzaCoinTeam.startVoting() (steps 3.1 - 3.3).
In addition to understanding the detailed implementation of PizzaCoin voting system, please check out the series of articles named "PizzaCoin the series" below.
PizzaCoin the series consists of 6 articles as follows.
Part 1: How Did We Develop Ethereum-based Voting System for Pizza Hackathon?
Part 2: Workflow Design for PizzaCoin Voting System
Part 3: Detailed Implementation of Staff and Player Contracts
Part 4: Detailed Implementation of Team Contract
Part 5: Deploying Children Contracts with Contract Factories
Part 6: Integrating PizzaCoin Contract with Dependencies
- Install MetaMask on Chrome browser.
- Get free ETH on test network, by googling using keywords like ropsten faucet, rinkeby faucet or kovan faucet.
- Go to remix.ethereum.org
- Choose π, select all files in Smart-Contract/contracts/
- Open PizzaCoin.sol on the left panel
- Select Run tab on the right panel
- Select PizzaCoin on the list below
- Specify _ownerName = "Your name" and _voterInitialTokens = 3 (i.e., the initial voting tokens every participant will get during a registration process). At this step, your Metamask will prompt you to confirm signing transaction 6 times.
- Select Deployed Contract pane below and then invoke the following contract functions: createStaffContract(), createPlayerContract(), createTeamContract() and startRegistration().
- Finally, configure your DApp by heading to the config file system.js which is in the directory ../DApp/src/store/. Then, define the following variables with corresponding settings: network, etherscanPrefix, ethereumNode, pizzaCoinAddr, pizzaCoinStaffAddr, pizzaCoinPlayerAddr and pizzaCoinTeamAddr.
cd Smart-Contract/
npm install
βRegister to get a free api. Note that, the api will be sent to your registered e-mail.
echo "'your-infura-api'" > infura-api.secret // Your Infura api must be marked with single quotes
echo "'your-secret-mnemonic'" > mnemonic.secret // Your secret mnemonic must be marked with single quotes
truffle compile
truffle migrate --network mainnet // Deploy to Ethereum public main network via Infura
or
truffle migrate --network ropsten // Deploy to Ropsten testnet via Infura
or
truffle migrate --network rinkeby // Deploy to Rinkeby testnet via Infura
or
truffle migrate --network kovan // Deploy to Kovan testnet via Infura
or
truffle migrate --network rinkeby_localsync // Deploy to Rinkeby testnet via local Geth node
or
truffle migrate --network ganache // Deploy to Ganache local test environment
node init-contract.js <<ethereum_network>> // For example, run 'node init-contract.js rinkeby'
To execute Node.JS based lazy-web3-wrapper functions (for demonstrating how to interact the contract with web3 node.js backend)
node web3-demo.js // This script supports a connection to Ganache or local Geth/Parity node only
To facilitate our users, we developed Decentralized Application (DApp) as a web frontend connecting with PizzaCoin contract. DApp is a static web frontend application which runs at the client side without the need of any backend server. Our DApp connects with PizzaCoin contract through Web3.js library. The underlying protocal used by Web3.js is Json RPC over HTTP and/or Websocket as shown in Figure 7.
cd DApp
npm install
npm run serve
cd live-feed
npm install
npm run serve
cd live-feed
TBD
The following addresses point to PizzaCoin contract as well as its dependencies that were used at the hackathon event.
- Ethereum network: Kovan
- PizzaCoin contract: 0x76030b8f0e6e938afabe7662ec248f2b7815e6bb
- PizzaCoinStaffDeployer library: 0x7F8366b1C1aCE62A74531F9D1477428E15Aa1109
- PizzaCoinPlayerDeployer library: 0x2659a5CEcC38250bf8a0F4f48DBF9C36C4eAB923
- PizzaCoinTeamDeployer library: 0xD32dC427118DA8CBfc300C6E483C03d7877f3d39
- PizzaCoinCodeLib library: 0xD9ea584DAB76F0BcF6Db85D61AA7Ee5606f15876
- PizzaCoinCodeLib2 library: 0xFaB51C36088D9651872f2cd610dAE7F82E4F04E0
- PizzaCoinStaff contract: 0xEa1E67465b688Ea1b30856F55AcD77af43376d01
- PizzaCoinPlayer contract: 0x785A811Ad43c733B0FdDd8113E8478bc2AEd02e0
- PizzaCoinTeam contract: 0x216C611001b2e8B6ff2cf51C5e9EB39ABE558E35