-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathreport.tex
More file actions
198 lines (179 loc) · 11.1 KB
/
Copy pathreport.tex
File metadata and controls
198 lines (179 loc) · 11.1 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
\documentclass[10pt]{article}
\usepackage{fancyvrb}
\usepackage{hyperref}
\title{Tic Tac Toe using Ethereum Smart Contracts}
\date{2018\\ May}
\author{Timo Hegnauer
\and Lenz Baumann
\and Cyrill Halter}
\begin{document}
\maketitle
This report documents the implementation of the \emph{Tic Tac Toe} game logic by means of an \emph{Ethereum Smart Contract} written in the \emph{Solidity} programming language. The smart contract should be compilable with the \emph{SOLC} compiler version \texttt{>= 0.4.21}.
\newline The source-code can be found here: \url{https://github.com/timohe/ethTicTacToe} along with instructions and further information on how to run using geth.
\section{Functionality}
The smart contract supports the following functionality:
\begin{enumerate}
\item The full \emph{Tic Tac Toe} game logic is implemented entirely within the smart contract and can be accessed either via the \emph{GETH} console or a custom web interface.
\item The smart contract is able to store and operate multiple games at the same time.
\item A betting system was implemented where each player has to pay a wager of 5 ether in order to join a game. The winner is awarded the entire pot of 10 ether. In case of a tie the pot is split up equally between the two players.
\item A business model was developed that allows for the exploitation of those people that are naive enough to spend 5 ether on a game of \emph{Tic Tac Toe} without reading the contract.
\end{enumerate}
\section{Events}
The we are using the following Events to trigger actions in the javascript:
\begin{Verbatim}[fontsize=\small]
event HostedGame(address sender ,string log);
event JoinedGame(address sender ,string log);
event Error(address sender ,string error);
event GameOver(address host ,string whoWon);
event TriggerBoardRefresh(address host);
\end{Verbatim}
These events are passing an address so the user can filter to only receive the event relevant to his games.
\section{The Game Struct}
The \texttt{Game} struct contains a set of variables used to define the state of a \emph{Tic Tac Toe} game between two players.
\begin{Verbatim}[fontsize=\small]
struct Game
{
address opponent;
bool isHostsTurn;
bool gameNotOver;
uint turnNr;
mapping(uint => mapping(uint => uint)) board;
}
mapping (address => Game) games;
\end{Verbatim}
In rough terms, a game consists of a player who hosts the game, an opponent and a game board. The \texttt{Game} struct stores the opponents address, as well as the game board, which is conceptualized as a 2d uint mapping. The host address is implicitly stored as the key to a mapping from host addresses to games. This implies that a player may host only one game at a time. The \texttt{Game} struct also keeps boolean variables indicating whose turn it is and whether the game has ended. The current turn is stored as a uint.
\section{Hosting and Joining a New Game}
In order to start a game between two parties, one of them needs to act as a host to initialize it in the smart contract. The second player can then join the hosted game.
\begin{Verbatim}[fontsize=\small]
function hostNewGame() payable rightAmountPaid public {
clearBoard(msg.sender);
Game storage g = games[msg.sender];
g.gameNotOver = true;
emit HostedGame(msg.sender, "successfully hosted Game!");
}
\end{Verbatim}
The \texttt{hostNewGame} method is called by the game's host to initialize a new game. Any old \texttt{Game} that was persisted in the smart contract for the host's address is first cleared out of storage. \texttt{clearBoard} is a helper method that deletes each variable in a game struct. After clearing, a new \texttt{Game} is initialized and the \texttt{gameNotOver} boolean is set to true, indicating that a game is in progress. Furthermore an event is passed to the user to inform him that he successfully hosted the game.
\begin{Verbatim}[fontsize=\small]
function joinExistingGame(address host) payable rightAmountPaid public {
Game storage g = games[host];
if(g.opponent == 0 && msg.sender != host)
{
g.opponent = msg.sender;
}
emit JoinedGame(msg.sender, "successfully joined Game!");
}
\end{Verbatim}
The \texttt{joinExistingGame} enables a second player to join a game hosted by another player. To do this, he must know the host's address. This method also checks whether a second player has already joined the game and whether the host is trying to play a game against himself, in which case it fails.
\begin{Verbatim}[fontsize=\small]
modifier rightAmountPaid {
if(msg.value != pot){
emit Error("You need to make a transaction of 5 eth...");
}else{ _; }
}
\end{Verbatim}
The \texttt{rightAmountPaid} modifier is appended to both the \texttt{hostNewGame} and the \texttt{joinExistingGame} methods and ensures that a transaction of 5 ether is made by each player to the smart contract upon entering a game.
\section{Playing a Move}
The main \emph{Tic Tac Toe} game logic is conceptualized in the \texttt{play}, the \texttt{youWon} and the \texttt{isTie} methods.
\begin{Verbatim}[fontsize=\small]
function play(address host, uint row, uint column) public{
Game storage g = games[host];
if(!g.gameNotOver){
emit Error(msg.sender, "The game is Over");
return;
}
uint player;
if(msg.sender == host){
player = 1;
}
else if(msg.sender == g.opponent){
player = 2;
} else{
emit Error(msg.sender, "You are not part of this game");
return;
}
if((g.isHostsTurn && player != 1) || (!g.isHostsTurn && player == 1)){
emit Error(msg.sender, "Its not your turn! Wait for your opponent to play");
return;
}else{
if(row >= 0 && row < 3 && column >= 0 && column < 3 && g.board[row][column] == 0){
g.board[row][column] = player;
g.turnNr ++;
emit TriggerBoardRefresh(host);
if(youWon(host)){
if(player == 1){
host.transfer(10 ether);
emit GameOver(host, "host");
g.gameNotOver = false;
}else{
g.opponent.transfer(10 ether);
emit GameOver(host, "opponent");
g.gameNotOver = false;
}
g.isHostsTurn = !g.isHostsTurn;
return;
}
if(isTie(host)){
host.transfer(5 ether);
g.opponent.transfer(5 ether);
g.isHostsTurn = !g.isHostsTurn;
emit GameOver(host, "tie");
g.gameNotOver = false;
return;
}
g.isHostsTurn = !g.isHostsTurn;
return;
} else {
emit Error(msg.sender, "Your choice of field was not valid");
}
}
}
\end{Verbatim}
The \texttt{play} method first performs a set of preliminary checks including whether the game is still in progress, whether the player trying to make a move is part of the game and it is his turn and whether the move is valid for the \emph{Tic Tac Toe} playing field. If this is the case, the move is performed. The smart contract then evaluates whether the game has been won by the player making the move using the \texttt{youWon} method. If this is the case, the pot amount of 10 ether is transferred to the winner and the game is ended. Otherwise, the smart contract evaluates whether the game has resulted in a tie using the \texttt{isTie} method. In this case, the pot is divided equally between the host and the opponent and the game is ended. If the game does not end, the \texttt{Game} struct's \texttt{isHostsTurn} variable is switched and the game continues.
\begin{Verbatim}[fontsize=\small]
function youWon(address host) internal view returns (bool didYouWin){
Game storage g = games[host];
for (uint i; i < 3; i++){
if(g.board[i][0] != 0 && g.board[i][0] == g.board[i][1] &&
g.board[i][1] == g.board[i][2] ){ return true; }
if(g.board[0][i] != 0 && g.board[0][i] == g.board[1][i] &&
g.board[1][i] == g.board[2][i]){ return true; }
}
if(g.board[0][0] != 0 && g.board[0][0] == g.board[1][1] && g.board[1][1]
== g.board[2][2]){ return true; }
if(g.board[2][0] != 0 && g.board[2][0] == g.board[1][1] && g.board[1][1]
== g.board[0][2]){ return true; }
return false;
}
\end{Verbatim}
The \texttt{youWon} method checks whether a winning constellation has been reached in a game. To achieve this, it checks both the rows and the columns, as well as both diagonals of the \texttt{Game} struct's \texttt{board} mapping for matching numbers. Since this check is always performed after a player has made a move and since therefore only he has the possibility of winning the game at that point, the method does not have to discern between player wich reduces the complexity of the method and reduces gas cost.
\begin{Verbatim}[fontsize=\small]
function isTie(address host) internal view returns (bool isItATie){
Game storage g = games[host];
if(g.turnNr > 8){ return true; }
}
\end{Verbatim}
The \texttt{isTie} method evaluates whether the game has ended in a tie by checking if the game has reached its ninth move without any one of the two parties winning.
\section{Exploiting the Rich and Naive}
5 ether is a lot to spend on a single game of \emph{Tic Tac Toe}. It can therefore be expected that only those with money to spare (or rather throw away) will be willing to participate in a game with stakes as high as these. To profit from this, the \texttt{withdraw} method allows the owner of the contract to extract the funds that belong to the smart contract. This is, for one, to gain access to ethers that may have been left over from a game that was never ended, but also to blatantly steal from those rich enough to play a game of \emph{Tic Tac Toe} for 5 ether with the intent of redistributing the gained money in a robbin-hood-esque fashion.
\newline Furthermore, this contract has an educational value for people blindly trusting often called "trust-free" blockchain applications and creates awarness of the consequence of such behaviour.
\begin{Verbatim}[fontsize=\small]
constructor () public {
owner = msg.sender;
}
\end{Verbatim}
The contract's constructor sets the owner of the contract
\begin{Verbatim}[fontsize=\small]
function withdraw() public onlyOwner {
require(address(this).balance > 0);
owner.transfer(address(this).balance);
}
\end{Verbatim}
The \texttt{withdraw} method enables the withdrawal of the funds in the contract if there are any.
\begin{Verbatim}[fontsize=\small]
modifier onlyOwner() {
require (msg.sender == owner);
_;
}
\end{Verbatim}
The \texttt{onlyOwner} modifier is appended to the \texttt{withdraw} method and ensures that only the contract's owner may execute the method.
\end{document}