Skip to content

Commit

Permalink
Add diff to code when relevant. (#1296)
Browse files Browse the repository at this point in the history
  • Loading branch information
xavierlepretre committed Dec 6, 2022
1 parent faf05b2 commit 6f8afa5
Show file tree
Hide file tree
Showing 15 changed files with 684 additions and 549 deletions.
36 changes: 19 additions & 17 deletions hands-on-exercise/1-ignite-cli/3-stored-game.md
Original file line number Diff line number Diff line change
Expand Up @@ -365,12 +365,13 @@ return &GenesisState{

This is not correct. Your chain needs to start with an initial system info. This raises the point that the genesis' `SystemInfo` should in fact [never be null](https://pkg.go.dev/github.com/gogo/protobuf/gogoproto). You can enforce that in `genesis.proto`:
```protobuf [https://github.com/cosmos/b9-checkers-academy-draft/blob/full-game-object/proto/checkers/genesis.proto#L15]
message GenesisState {
...
SystemInfo systemInfo = 2 [(gogoproto.nullable) = false];
...
}
```diff-protobuf [https://github.com/cosmos/b9-checkers-academy-draft/blob/full-game-object/proto/checkers/genesis.proto#L15]
message GenesisState {
...
- SystemInfo systemInfo = 2;
+ SystemInfo systemInfo = 2 [(gogoproto.nullable) = false];
...
}
```
After compilation, this `nullable = false` flag changes the `SystemInfo` type in genesis from a pointer to a straight value. Make sure you recompile:
Expand Down Expand Up @@ -401,18 +402,19 @@ $ docker run --rm -it \
Then set a default value for `SystemInfo`:
```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/full-game-object/x/checkers/types/genesis.go#L13-L15]
const DefaultIndex uint64 = 1
func DefaultGenesis() *GenesisState {
return &GenesisState{
SystemInfo: SystemInfo{
NextId: uint64(DefaultIndex),
},
StoredGameList: []StoredGame{},
...
```diff-go [https://github.com/cosmos/b9-checkers-academy-draft/blob/full-game-object/x/checkers/types/genesis.go#L13-L15]
const DefaultIndex uint64 = 1
func DefaultGenesis() *GenesisState {
return &GenesisState{
- SystemInfo: nil,
+ SystemInfo: SystemInfo{
+ NextId: uint64(DefaultIndex),
+ },
StoredGameList: []StoredGame{},
...
}
}
}
```
You can choose to start with no games or insert a number of games to start with. In either case, you must choose the first ID of the first future created game, which here is set at `1` by reusing the `DefaultIndex` value.
Expand Down
20 changes: 11 additions & 9 deletions hands-on-exercise/1-ignite-cli/5-create-handling.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,10 +73,12 @@ Given that you have already done a lot of preparatory work, what coding is invol

1. First, `rules` represents the ready-made file with the imported rules of the game:

```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game.go#L7]
import (
"github.com/alice/checkers/x/checkers/rules"
)
```diff-go [https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game.go#L7]
import (
...
+ "github.com/alice/checkers/x/checkers/rules"
...
)
```

2. Get the new game's ID with the [`Keeper.GetSystemInfo`](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/system_info.go#L17) function created by the `ignite scaffold single systemInfo...` command:
Expand Down Expand Up @@ -199,7 +201,7 @@ Your keeper was initialized with an empty genesis. You must fix that one way or
You can fix this by always initializing the keeper with the default genesis. However such a default initialization may not always be desirable. So it is better to keep this default initialization closest to the tests. Copy the `setupMsgServer` from [`msg_server_test.go`](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_test.go#L13-L16) into your `msg_server_create_game_test.go`. Modify it to also return the keeper:
```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L21-L25]
```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L15-L19]
func setupMsgServerCreateGame(t testing.TB) (types.MsgServer, keeper.Keeper, context.Context) {
k, ctx := keepertest.CheckersKeeper(t)
checkers.InitGenesis(ctx, *k, *types.DefaultGenesis())
Expand All @@ -221,7 +223,7 @@ import (

Do not forget to replace `setupMsgServer(t)` with this new function everywhere in the file. For instance:

```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L28]
```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L22]
msgServer, _, context := setupMsgServerCreateGame(t)
```

Expand Down Expand Up @@ -253,15 +255,15 @@ $ docker run --rm -it \

The error has changed to `Not equal`, and you need to adjust the expected value as per the default genesis:

```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L35-L37]
```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L29-L31]
require.EqualValues(t, types.MsgCreateGameResponse{
GameIndex: "1",
}, *createResponse)
```

One unit test is good, but you can add more, in particular testing whether the values in storage are as expected when you create a single game:

```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L40-L62]
```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L34-L56]
func TestCreate1GameHasSaved(t *testing.T) {
msgSrvr, keeper, context := setupMsgServerCreateGame(t)
msgSrvr.CreateGame(context, &types.MsgCreateGame{
Expand All @@ -286,7 +288,7 @@ func TestCreate1GameHasSaved(t *testing.T) {
}
```

Or when you [create 3](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L108-L133) games. Other tests could include whether the _get all_ functionality works as expected after you have created [1 game](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L64-L80), or [3](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L187-L227), or if you create a game in a hypothetical [far future](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L229-L258). Also add games with [badly formatted](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L82-L93) or [missing input](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L95-L106).
Or when you [create 3](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L102-L127) games. Other tests could include whether the _get all_ functionality works as expected after you have created [1 game](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L58-L74), or [3](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L181-L221), or if you create a game in a hypothetical [far future](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L223-L252). Also add games with [badly formatted](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L76-L87) or [missing input](https://github.com/cosmos/b9-checkers-academy-draft/blob/create-game-handler/x/checkers/keeper/msg_server_create_game_test.go#L89-L100).

## Interact via the CLI

Expand Down
13 changes: 8 additions & 5 deletions hands-on-exercise/1-ignite-cli/6-play-game.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,11 +137,14 @@ Where the `TODO` is replaced as per the following.

The `rules` represent the ready-made file containing the rules of the game you imported earlier. Declare your new errors in `x/checkers/types/errors.go`, given your code has to handle new error situations:

```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/play-move-handler/x/checkers/types/errors.go#L14-L17]
ErrGameNotFound = sdkerrors.Register(ModuleName, 1103, "game by id not found")
ErrCreatorNotPlayer = sdkerrors.Register(ModuleName, 1104, "message creator is not a player")
ErrNotPlayerTurn = sdkerrors.Register(ModuleName, 1105, "player tried to play out of turn")
ErrWrongMove = sdkerrors.Register(ModuleName, 1106, "wrong move")
```diff-go [https://github.com/cosmos/b9-checkers-academy-draft/blob/play-move-handler/x/checkers/types/errors.go#L14-L17]
var (
...
+ ErrGameNotFound = sdkerrors.Register(ModuleName, 1103, "game by id not found")
+ ErrCreatorNotPlayer = sdkerrors.Register(ModuleName, 1104, "message creator is not a player")
+ ErrNotPlayerTurn = sdkerrors.Register(ModuleName, 1105, "player tried to play out of turn")
+ ErrWrongMove = sdkerrors.Register(ModuleName, 1106, "wrong move")
)
```

Take the following steps to replace the `TODO`:
Expand Down
2 changes: 1 addition & 1 deletion hands-on-exercise/1-ignite-cli/7-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ ctx.EventManager().EmitEvent(

The unit tests you have created so far still pass. However you also want to confirm that the events have been emitted in both situations. The events are recorded in the context, so the test is a little bit different. In `msg_server_create_game_test.go`, add this test:

```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/two-events/x/checkers/keeper/msg_server_create_game_test.go#L82-L103]
```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/two-events/x/checkers/keeper/msg_server_create_game_test.go#L76-L97]
func TestCreate1GameEmitted(t *testing.T) {
msgSrvr, _, context := setupMsgServerCreateGame(t)
msgSrvr.CreateGame(context, &types.MsgCreateGame{
Expand Down
39 changes: 21 additions & 18 deletions hands-on-exercise/1-ignite-cli/8-reject-game.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,11 +106,11 @@ func (k msgServer) RejectGame(goCtx context.Context, msg *types.MsgRejectGame) (

A new rule of the game should be that a player cannot reject a game once they begin to play. When loading a `StoredGame` from storage you have no way of knowing whether a player already played or not. To access this information add a new field to the `StoredGame` called `MoveCount`. In `proto/checkers/stored_game.proto`:

```protobuf [https://github.com/cosmos/b9-checkers-academy-draft/blob/reject-game-handler/proto/checkers/stored_game.proto#L12]
message StoredGame {
...
uint64 moveCount = 6;
}
```diff-protobuf [https://github.com/cosmos/b9-checkers-academy-draft/blob/reject-game-handler/proto/checkers/stored_game.proto#L12]
message StoredGame {
...
+ uint64 moveCount = 6;
}
```

Run Protobuf to recompile the relevant Go files:
Expand Down Expand Up @@ -143,20 +143,20 @@ $ docker run --rm -it \

1. Adjust it first in the handler when creating the game:

```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/reject-game-handler/x/checkers/keeper/msg_server_create_game.go#L28]
storedGame := types.StoredGame{
...
MoveCount: 0,
}
```diff-go [https://github.com/cosmos/b9-checkers-academy-draft/blob/reject-game-handler/x/checkers/keeper/msg_server_create_game.go#L28]
storedGame := types.StoredGame{
...
+ MoveCount: 0,
}
```

2. Before saving to the storage, adjust it in the handler when playing a move:

```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/reject-game-handler/x/checkers/keeper/msg_server_play_move.go#L57]
...
storedGame.MoveCount++
storedGame.Game = game.String()
...
```diff-go [https://github.com/cosmos/b9-checkers-academy-draft/blob/reject-game-handler/x/checkers/keeper/msg_server_play_move.go#L57]
...
+ storedGame.MoveCount++
storedGame.Board = game.String()
...
```

With `MoveCount` counting properly, you are now ready to handle a rejection request.
Expand All @@ -165,9 +165,12 @@ With `MoveCount` counting properly, you are now ready to handle a rejection requ

To follow the Cosmos SDK conventions, declare the following new errors:

```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/reject-game-handler/x/checkers/types/errors.go#L18-L19]
ErrBlackAlreadyPlayed = sdkerrors.Register(ModuleName, 1107, "black player has already played")
ErrRedAlreadyPlayed = sdkerrors.Register(ModuleName, 1108, "red player has already played")
```diff-go [https://github.com/cosmos/b9-checkers-academy-draft/blob/reject-game-handler/x/checkers/types/errors.go#L18-L19]
var (
...
+ ErrBlackAlreadyPlayed = sdkerrors.Register(ModuleName, 1107, "black player has already played")
+ ErrRedAlreadyPlayed = sdkerrors.Register(ModuleName, 1108, "red player has already played")
)
```

This time you will add an event for rejection. Begin by preparing the new keys:
Expand Down
111 changes: 56 additions & 55 deletions hands-on-exercise/2-ignite-cli-adv/1-game-fifo.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,22 @@ How do you implement a FIFO from which you extract elements at random positions?

1. You must remember the game ID at the head to pick expired games, and at the tail to send back fresh games. The existing `SystemInfo` object is useful, as it is already expandable. Add to its Protobuf declaration:

```protobuf [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/proto/checkers/system_info.proto#L8-L9]
message SystemInfo {
...
string fifoHeadIndex = 2; // Will contain the index of the game at the head.
string fifoTailIndex = 3; // Will contain the index of the game at the tail.
}
```diff-protobuf [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/proto/checkers/system_info.proto#L8-L9]
message SystemInfo {
...
+ string fifoHeadIndex = 2; // Will contain the index of the game at the head.
+ string fifoTailIndex = 3; // Will contain the index of the game at the tail.
}
```

2. To make extraction possible, each game must know which other game takes place before it in the FIFO, and which after. Store this double-link information in `StoredGame`. Add them to the game's Protobuf declaration:

```protobuf [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/proto/checkers/stored_game.proto#L13-L14]
message StoredGame {
...
string beforeIndex = 7; // Pertains to the FIFO. Toward head.
string afterIndex = 8; // Pertains to the FIFO. Toward tail.
}
```diff-protobuf [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/proto/checkers/stored_game.proto#L13-L14]
message StoredGame {
...
+ string beforeIndex = 7; // Pertains to the FIFO. Toward head.
+ string afterIndex = 8; // Pertains to the FIFO. Toward tail.
}
```

3. There must be an "ID" that indicates _no game_. Use `"-1"`, which you save as a constant:
Expand Down Expand Up @@ -165,16 +165,17 @@ How do you implement a FIFO from which you extract elements at random positions?

5. Adjust the default genesis values, so that it has a proper head and tail:

```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/x/checkers/types/genesis.go#L15-L16]
func DefaultGenesis() *GenesisState {
return &GenesisState{
SystemInfo: SystemInfo{
NextId: uint64(DefaultIndex),
FifoHeadIndex: NoFifoIndex,
FifoTailIndex: NoFifoIndex,
},
...
}
```diff-go [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/x/checkers/types/genesis.go#L15-L16]
func DefaultGenesis() *GenesisState {
return &GenesisState{
SystemInfo: SystemInfo{
NextId: uint64(DefaultIndex),
+ FifoHeadIndex: NoFifoIndex,
+ FifoTailIndex: NoFifoIndex,
},
...
}
}
```

## FIFO management
Expand Down Expand Up @@ -261,55 +262,55 @@ With these functions ready, it is time to use them in the message handlers.
1. In the handler when creating a new game, set default values for `BeforeIndex` and `AfterIndex`:
```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/x/checkers/keeper/msg_server_create_game.go#L29-L30]
...
storedGame := types.StoredGame{
```diff-go [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/x/checkers/keeper/msg_server_create_game.go#L29-L30]
...
BeforeIndex: types.NoFifoIndex,
AfterIndex: types.NoFifoIndex,
}
storedGame := types.StoredGame{
...
+ BeforeIndex: types.NoFifoIndex,
+ AfterIndex: types.NoFifoIndex,
}
```
Send the new game to the tail because it is freshly created:
```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/x/checkers/keeper/msg_server_create_game.go#L38]
...
k.Keeper.SendToFifoTail(ctx, &storedGame, &systemInfo)
k.Keeper.SetStoredGame(ctx, storedGame)
...
```diff-go [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/x/checkers/keeper/msg_server_create_game.go#L38]
...
+ k.Keeper.SendToFifoTail(ctx, &storedGame, &systemInfo)
k.Keeper.SetStoredGame(ctx, storedGame)
...
```
2. In the handler, when playing a move send the game back to the tail because it was freshly updated:
```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/x/checkers/keeper/msg_server_play_move.go#L57-L67]
...
systemInfo, found := k.Keeper.GetSystemInfo(ctx)
if !found {
panic("SystemInfo not found")
}
k.Keeper.SendToFifoTail(ctx, &storedGame, &systemInfo)
```diff-go [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/x/checkers/keeper/msg_server_play_move.go#L57-L67]
...
+ systemInfo, found := k.Keeper.GetSystemInfo(ctx)
+ if !found {
+ panic("SystemInfo not found")
+ }
+ k.Keeper.SendToFifoTail(ctx, &storedGame, &systemInfo)
storedGame.MoveCount++
...
k.Keeper.SetSystemInfo(ctx, systemInfo)
...
storedGame.MoveCount++
...
k.Keeper.SetStoredGame(ctx, storedGame)
+ k.Keeper.SetSystemInfo(ctx, systemInfo)
...
```
Note that you also need to call `SetSystemInfo`.
3. In the handler, when rejecting a game remove the game from the FIFO:
```go [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/x/checkers/keeper/msg_server_reject_game.go#L31-L37]
...
systemInfo, found := k.Keeper.GetSystemInfo(ctx)
if !found {
panic("SystemInfo not found")
}
k.Keeper.RemoveFromFifo(ctx, &storedGame, &systemInfo)
k.Keeper.RemoveStoredGame(ctx, msg.GameIndex)
...
k.Keeper.SetSystemInfo(ctx, systemInfo)
...
```diff-go [https://github.com/cosmos/b9-checkers-academy-draft/blob/game-fifo/x/checkers/keeper/msg_server_reject_game.go#L31-L37]
...
+ systemInfo, found := k.Keeper.GetSystemInfo(ctx)
+ if !found {
+ panic("SystemInfo not found")
+ }
+ k.Keeper.RemoveFromFifo(ctx, &storedGame, &systemInfo)
k.Keeper.RemoveStoredGame(ctx, msg.GameIndex)
+ k.Keeper.SetSystemInfo(ctx, systemInfo)
...
```
You have implemented a FIFO that is updated but never really used. It will be used in a [later section](./4-game-forfeit.md).
Expand Down
Loading

0 comments on commit 6f8afa5

Please sign in to comment.