Playing with the XO Transaction Family
XO is an example transaction family that implements the game tic-tac-toe, also known as Noughts and Crosses or X's and O's. We chose XO as an example transaction family for Sawtooth because of its simplicity, global player base, and straightforward implementation as a computer program. This transaction family demonstrates the functionality of Sawtooth; in addition, the code that implements it serves as a reference for building other transaction processors.
This section introduces the concepts of a Sawtooth transaction family
with XO, summarizes XO game rules, and describes how use the xo
client
application to play a game of tic-tac-toe on the blockchain.
About the XO Transaction Family
The XO transaction family defines the data model and business logic for playing tic-tac-toe on the blockchain by submitting transactions for create, take, and delete actions. For more information, see XO Transaction Family
The XO transaction family includes:
- Transaction processors in several languages, including Go (
xo-tp-go
), JavaScript, and Python (xo-tp-python
). These transaction processors implement the business logic of XO game play.- An
xo
client: A set of commands that provide a command-line interface for playing XO. Thexo
client handles the construction and submission of transactions. For more information, see xo
Game Rules
In tic-tac-toe, two players take turns marking spaces on a 3x3 grid.
- The first player (player 1) marks spaces with an X. Player 1 always makes the first move.
- The second player (player 2) marks spaces with an O.
- A player wins the game by marking three adjoining spaces in a horizontal, vertical, or diagonal row.
- The game is a tie if all nine spaces on the grid have been marked, but no player has won.
See Wikipedia for more information on playing tic-tac-toe. For the detailed business logic of game play, see "Execution" in XO Transaction Family
Playing XO with the xo Client
This procedure introduces you to the XO transaction family by playing a
game with the xo
client. Each xo
command is a transaction that the
client submits to the validator via the REST API.
Prerequisites
- A working Sawtooth development environment, as described in Setting Up a Sawtooth Application Development Environment. This environment must be running a validator, a REST API, and the Settings transaction processor. (The IntegerKey transaction processor is not used in this procedure.)
- This procedure also requires the XO transaction processor. The Docker and AWS procedures start it automatically. For Ubuntu, this procedure shows how to start the XO transaction processor if necessary.
Step 1: Confirm Connectivity to the REST API
-
Connect to your development environment, as described in the procedure for your platform in Setting Up a Sawtooth Application Development Environment.
-
Verify that you can connect to the REST API.
- Docker: See Step 5: Confirm Connectivity to the REST API
- Ubuntu: See Setting Up a Sawtooth Application Development Environment
- AWS: See Step 2: Check the Status of Sawtooth Components
Important
The
xo
client sends requests to update and query the blockchain to the URL of the REST API (by default,http://127.0.0.1:8008
).If the REST API's URL is not
http://127.0.0.1:8008
, you must add the--url
argument to eachxo
command in this procedure.For example, the following command specifies the URL for the Docker demo application environment when creating a new game:
$ xo create my-game --username jack --url http://rest-api:8008
Step 2. Ubuntu only: Start the XO Transaction Processor
If you did not start the XO transaction processor on your Ubuntu application development environment, start it now.
-
Open a new terminal window (the xo window).
-
Check whether the XO transaction processor is running.
user@xo$ ps aux | grep [x]o-tp root 1546 0.0 0.1 52700 3776 pts/2 S+ 19:15 0:00 sudo -u sawtooth xo-tp-python -v sawtooth 1547 0.0 1.5 277784 31192 pts/2 Sl+ 19:15 0:00 /usr/bin/python3 /usr/bin/xo-tp-python -v
-
If the output does not show that
/usr/bin/xo-tp-python
is running, start the XO transaction processor with the following command:user@xo$ sudo -u sawtooth xo-tp-python -v
For more information, see Step 5.3 in ubuntu
Step 3. Create Players
Create keys for two players to play the game:
$ sawtooth keygen jack
writing file: /home/ubuntu/.sawtooth/keys/jack.priv
writing file: /home/ubuntu/.sawtooth/keys/jack.addr
$ sawtooth keygen jill
writing file: /home/ubuntu/.sawtooth/keys/jill.priv
writing file: /home/ubuntu/.sawtooth/keys/jill.addr
Note
The output may differ slightly from this example.
Step 4. Create a Game
Create a game named my-game
with the following command:
$ xo create my-game --username jack
Note
The
--username
argument is required forxo create
andxo take
so that a single player (you) can play as two players. By default,<username>
is the Linux user name of the person playing the game.
Verify that the create
transaction was committed by displaying the
list of existing games:
$ xo list
GAME PLAYER 1 PLAYER 2 BOARD STATE
my-game --------- P1-NEXT
Note
The
xo list
command is a wrapper that provides a quick way to show game state rather than usingcurl
with the REST API's URL to request state.
Step 5. Take a Space as Player 1
Note
The first player to issue an
xo take
command to a newly created game is recorded asPLAYER 1
. The second player to issue atake
command is recorded by username asPLAYER 2
.The
--username
argument determines where thexo
client should look for the player's key to sign the transaction. By default, if you're logged in asroot
,xo
would look for the key file named~/.sawtooth/keys/root.priv
. Instead, the following command specifies thatxo
should use the key file~/.sawtooth/keys/jack.priv
.
Start playing tic-tac-toe by taking a space as the first player, Jack. In this example, Jack takes space 5:
$ xo take my-game 5 --username jack
This diagram shows the number of each space.
1 | 2 | 3
---|---|---
4 | 5 | 6
---|---|---
7 | 8 | 9
What Happens During a Game Move?
Each xo
command is a transaction. A successful transaction updates
global state with the game name, board state, game state, and player
keys, using this format:
<game-name>,<board-state>,<game-state>,<player1-key>,<player2-key>
Each time a player attempts to take a space, the transaction processor will verify that their username matches the name of the player whose turn it is. This ensures that no player is able to mark a space out of turn.
After each turn, the XO transaction processor scans the board state for
a win or tie. If either condition occurs, no more take
actions are
allowed on the finished game.
Step 6. Take a Space as Player 2
Next, take a space on the board as player 2, Jill. In this example, Jill takes space 1:
$ xo take my-game 1 --username jill
Step 7. Show the Current Game Board
Whenever you want to see the current state of the game board, enter the following command:
$ xo show my-game
The output includes the game name, the first six characters of each
player's public key, the game state, and the current board state. This
example shows the game state P1-NEXT
(player 1 has the next turn) and
a board with Jack's X in space 5 and Jill's O in space 1.
GAME: : my-game
PLAYER 1 : 02403a
PLAYER 2 : 03729b
STATE : P1-NEXT
O | |
---|---|---
| X |
---|---|---
| |
This xo
client formats the global state data so that it's easier to
read than the state returned to the transaction processor:
my-game,O---X----,P1-NEXT,02403a...,03729b...
Step 8. Continue the Game
Players take turns using xo take my-game <space>
to mark spaces on the
grid.
You can continue the game until one of the players wins or the game ends in a tie, as in this example:
$ xo show my-game
GAME: : my-game
PLAYER 1 : 02403a
PLAYER 2 : 03729b
STATE : TIE
O | X | O
---|---|---
X | X | O
---|---|---
X | O | X
Step 9. Delete the Game
Either player can use the xo delete
command to remove the game data
from global state.
$ xo delete my-game
Using Authentication with the xo Client
The XO client supports optional authentication. If the REST API is
connected to an authentication proxy, you can point the XO client at it
with the --url
argument. You must also specify your authentication
information using the --auth-user [user]
and
--auth-password [password]
options for each xo
command.
Note that the value of the --auth-user
argument is not the same
username that is entered with the --username
argument.