# Create a Game Message

synopsis

Make sure you have all you need before proceeding:

Right now:

  • Your game objects have been defined in storage.
  • You prevented a simple CRUD to set the objects straight from transactions.

Now you need a message to instruct the checkers blockchain to create a game. This message needs to:

  • Not specify the creator: this is implicit because it shall be the signer of the message.
  • Not specify the ID of the game because the system uses an incrementing counter. On the other hand, the server needs to return the newly created ID value since the eventual value cannot be known before the transaction is included in a block and the state computed. Call this idValue.
  • Not specify the game board as it is under the full control of the checkers rules.
  • Specify who is playing reds. Call the field red.
  • Specify who is playing blacks. Call the field black.

Instruct Starport to take care of all this:

Copy $ starport scaffold message createGame red black --module checkers --response idValue

It creates a certain number of files (opens new window) plus some GUI elements (opens new window).

# Protobuf objects

Simple Protobuf objects are created:

Copy message MsgCreateGame { string creator = 1; string red = 2; string black = 3; } message MsgCreateGameResponse { string idValue = 1; } proto checkers tx.proto View source

Which, when compiled for instance with starport generate proto-go yield:

Copy type MsgCreateGame struct { Creator string `protobuf:"bytes,1,opt,name=creator,proto3" json:"creator,omitempty"` Red string `protobuf:"bytes,2,opt,name=red,proto3" json:"red,omitempty"` Black string `protobuf:"bytes,3,opt,name=black,proto3" json:"black,omitempty"` } x checkers types tx.pb.go View source

And:

Copy type MsgCreateGameResponse struct { IdValue string `protobuf:"bytes,1,opt,name=idValue,proto3" json:"idValue,omitempty"` } x checkers types tx.pb.go View source

Files were generated to serialize the pair which are named *.pb.go. Caution: you should not edit these files.

Starport also registered MsgCreateGame as a concrete message type with the two (de-)serialization engines:

Copy func RegisterCodec(cdc *codec.LegacyAmino) { cdc.RegisterConcrete(&MsgCreateGame{}, "checkers/CreateGame", nil) } x checkers types codec.go View source

And:

Copy func RegisterInterfaces(registry cdctypes.InterfaceRegistry) { registry.RegisterImplementations((*sdk.Msg)(nil), &MsgCreateGame{}, ) ... } x checkers types codec.go View source

Which is code that you probably do not need to change.

Starport also creates boilerplate code to have the message conform to the sdk.Msg (opens new window) type:

Copy func (msg *MsgCreateGame) GetSigners() []sdk.AccAddress { creator, err := sdk.AccAddressFromBech32(msg.Creator) if err != nil { panic(err) } return []sdk.AccAddress{creator} } x checkers types message_create_game.go View source

This code is created only once. You can modify it as you see fit.

# Protobuf service interface

Starport also adds a new function to your gRPC interface that receives all transaction messages for the module because the message is meant to be sent and received. The interface is called service Msg and is declared inside proto/checkers/tx.proto.

Starport creates this tx.proto (opens new window) file at the beginning when you scaffold your project's module. Starport separates different concerns into different files so that it knows where to add elements according to instructions received. Starport adds a function to the empty service Msg with your instruction.

The new function receives this MsgCreateGame, namely:

Copy service Msg { rpc CreateGame(MsgCreateGame) returns (MsgCreateGameResponse); } proto checkers tx.proto View source

As an interface it does not describe what should happen when called. What Starport does with the help of Protobuf is compile the interface and create a default Go implementation.

# Next up

Starport separates concerns into different files. The most relevant file for you at this point is x/checkers/keeper/msg_server_create_game.go which is created once. You need to code in the creation of the game proper in this file:

Copy func (k msgServer) CreateGame(goCtx context.Context, msg *types.MsgCreateGame) (*types.MsgCreateGameResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) // TODO: Handling the message _ = ctx return &types.MsgCreateGameResponse{}, nil } x checkers keeper msg_server_create_game.go View source

This is the object of the next section.