How Chainlink Solved Ethereum’s “Random Problem”
Testing a DApp on a local Blockchain is very different from testing it on a public one. For a start, you get used to the speedy response times and the immediate transactions. That, unfortunately, doesn’t happen on public testnets or the mainnet. This means your DApp needs to monitor the status of each transaction it executes on the Blockchain and provides sufficient feedback to the user.
Not only that, but if you’re subscribing to events in your DApp, listening for things like “Transfer” events, or in this game, “Train”, “Rest” and “MatchPlayed” events; the events won’t be pushed to your DApp through HTTP. No matter how many listeners you put in place, if you are connecting to the Blockchain with an HTTP connection, event listeners will never fire.
To catch the events, you need to maintain a Websocket connection, which I write about in this article. Fortunately, Infura offers HTTP and Websockets, so it wasn’t an issue, it’s just a little frustrating making sure you’re keeping both connections stored in parallel in the Redux store. Even more frustrating is the fact that the Websocket API is very limited compared with the HTTP one. This means that transactions need to be sent through HTTP, and listeners set up through Websocket.
Figure 5 shows my
On line 29 the function
subscribeToMatchEvents is declared, where “Enlist”, “Delist” and “MatchPlayed” events are listened to.
Taking a look at line 41, notice how
tennisPlayerWebsocket variable is used, representing a Websocket connection to the
TennisPlayer smart contract, to listen for the event.
It still needs the HTTP connected contract (
tennisPlayer) to reload the player after the match is played because Websockets don’t allow function calls to smart contracts. Line 43 shows a call to
tennisPlayer as a parameter to make the HTTP request.
I mentioned sundayleague.com as an inspiration for this game in the previous article. The way it works is by playing matches every day at a set time, I believe it’s 3 am GMT, so every player needs to have their tactics set for the upcoming game before that time.
If mimicked on the Blockchain, the system itself would need to pay gas costs for simulating the matches. The more players competing, the more gas needed.
(alternatively, each game could have a stake by each player, some of it contributing to gas and the rest going to the winner?)
We don’t want that. Instead, we want the players to be able to compete against others when they have enough resources (XP and condition). That way matches can be played as soon as the attacker submits the transaction (forwarding gas cost for the match of course). The winner is then calculated as soon as the block is confirmed.
Because matches cost player condition (they get worn out), players who aren’t in match condition can’t play. They need rest, hence the TrainableTennisPlayer contract.
If the game allows any player to play a match against anyone else, higher-level players would obliterate lower level players over and over rinsing the lower level player’s condition.
To combat this, I’m going to use a registration system, where players enlisted to compete can be challenged and can challenge others. They can be delisted by their managers at any time. They’ll also be auto-delisted if they complete a match and are subsequently below the minimum condition required.
Figure 3 shows a rudimentary diagram of how I’m envisaging the structure of the first few contracts.
TennisPlayerBase and TrainableTennisPlayer were coded in the previous article. CompetingTennisPlayer is where our match logic exists.
It enables players to enlist and compete against other enlisted players. I’m not worrying too much about the match mechanics just yet, other than a simple comparison between stats. I’ll work on that later.
Figure 4 shows the CompetingTennisPlayer Smart Contract.
There are three public functions:
enlist(): Adds a player to the enlisted players so long as the caller of the function is the owner of the player, the player is in good enough condition and is not already enlisted.
delist(): Removes a player so long as the caller is the owner and the player is currently listed.
playMatch(): Plays a match between two players providing they are both enlisted, the caller is the owner of the attacker, and both are in match condition. It then delists if either of the players is no longer match condition after the match.
I haven’t yet fully tested this contract, so that’s the next piece of work. I’ll likely need to change some of the code, but in terms of premise, I think most bases are covered for now.
This project is in active development. At the time of writing, the current state of the code is as described in this article.
I need to make sure what’s there is working as expected, which means lots of unit tests before moving on to the next piece of the puzzle.
After that, I’ll look to add the SomethingHere contract in Figure 4, yet to be named. Once that’s in place it should act as the main entry point for the game, and a front end can be built up around it. I’ll use React and Redux for that.
I’m already looking forward to being able to interact with the game despite its basic state right now. It’ll be great to see it working in the browser no matter how clunky for the time being.
The code repo is on Github so it’s public and open to pull requests. If you’re interested in helping out please to contribute! Here is the repo: