Implementing Rock Paper Scissors in Solidity
Have you ever thought about playing rock paper scissors on the blockchain? In this tutorial, we will build a privacy focussed rock paper scissors application on Ethereum using Solidity.
The aim is to understand the differences between a web2 application and web3 application also known as DApp (Decentralised Application). In a web2 application, the database is private and the server is trusted whereas in a web3 application, there is no server, there is no one database, there is only a blockchain which has state and trust isnt really present, asking a blockchain node about the state can only be trusted if other nodes agree on that as well, these are all sort of topics I have discussed in my privacy course which you can watch here: Introduction to privacy on Ethereum.
Rock paper scissors may sound simple to you at first but implementing it on a blockchain has its concerns and can teach you more than what you would think, we dont want to use a library or any other means to achieve privacy, the goal is to keep it as simple as possible and learn about privacy and smart contracts by implementing it yourself.
Blockchains such as Bitcoin and Ethereum are public by nature so while in the database world, we dont have to worry about the database being public, this is casual for blockchain, so as you will see in the first iteration of the game, the moves are store publicly, so this means that we have to dig deeper into what we store, storing plaintext is very dangerous since the entire world can read it so we have to seek help from our cryptography toolbox.
The requirements are simple:
1. Two users must be able to play rock paper scissors
2. No user should have an advantage because of their turn
3. Any user can check who has won the game
- The game can be extended such that both players have to deposit eth and the winner takes it all (could also deposit ERC20 tokens as well)
- The game can support multiple parallel games
- The game can be played off chain with state channels
Basic Rock Paper Scissors
In the basic rock paper scissors, we want to implement the game without thinking about privacy and this can be done in many different ways and to give you a chance to implement it yourself, here is the interface of the contract:
Lets dive into the implementation
First of all, we need a way to store the rock paper scissor values so we can verify the moves later, this can be done in many ways and we will change it as we go along, to begin with, lets use `uint8` to begin with since ROCK, PAPER, SCISSORS can be the only three acceptable choices.
Now that we have a way of representing the valid moves (ROCK, PAPER, SCISSORS), we need a way to store the values played by the players and the simplest ways to do that is by using a mapping, like this:
Now that we have the mapping, we can now start implementing the play function, this is a simple function which should check that a move is valid and store move along with the users address in the `choices` mapping. Lets do this:
Thats all needed for the play function, now we can look at implementing the evaluate function which can take two addresses and return the winning address, this essentially implements rock paper scissors game rules.
Congratulations! Now we have a fully working game, go ahead and you can play it by copy pasting the code on [Remix](https://remix.ethereum.org/), it gives you multiple addresses so you can play it against yourself too!
Rock Paper Scissors with hashes
In the previous section, our goal was just to implement a rock paper scissors game without worrying about any privacy concerns, lets talk about them now,
mapping(address => uint8) public choices;
Yes, the choices mapping, it stores the users moves, and its public, yup, so the player who plays second can always take advantage because they always can see the move played by the first player and therefore can always play the move which will make them win the game.
The only way this game would work in its current state is if both users play the moves simultaneously, however thats not an option with blockchains in general because the transactions are ordered and nothing can happen within Ethereum. But we can try to hide the values by using a hash function, like this:
We now have the hashed versions of ROCK, PAPER, SCISSORS and users now play a `bytes32` choice instead of the `uint8` from before.
Think about the problems with this before moving onto the next section!
Rock Paper Scissors with Randomness
If you are wondering that hash functions dont really hide anything and the same attack can still be used, you are absolutely right, hash functions are a deterministic one way functions which can take an input and always return the same output but if you know the inputs, the outputs are the same and therefore you can still use that to your advantage.
How do we go about making this work in a public setting _without adding too much complexity_ and by _complexity_ I mean, no Oracles, Enigma, ZKPROOFS, or any sophisticated means to achieve a very simple goal. Whats the answer? You guessed it! *Randomness*!
How do we go about adding randomness and how would that help? Remember we used `bytes32` for the choice, now its time to put that choice to good use and we do that by combining the users move and a random hashed string picked by the user, lets see how this changes our implementation.
Hint: Follow the CHANGED comments to see what has changed
By adding the randomness into the mix, we have prevented the attack but it comes with its caveats, the current implementation assumes that an application built on top of the smart contracts will be managing the randomness and making sure its truly random, many things can be broken if there are enough incentives and what we achieve with this solution is simplicity, we are only using simple cryptography which is already used a lot in web applications to store user passwords and much more and achieve privacy. There are cases where we have to use fancy cryptography like ZK-SNARKS but this certainly isnt a use case for it!
If you would like to learn about something else, please message me on Twitter @aliazam2251 or email me firstname.lastname@example.org. I hope you had fun building rock paper scissors on Blockchain!