This is part six of the series of blog posts explaining how to build a full stack application using Tendermint and Cosmos-SDK to build the blockchain backend. The previous part can be found here.
Here we will show how to build CLI for running the node software, as well as the CLI for the blockchain clients — sending transactions, querying blockchain and application state, querying node status, managing cryptographic keys etc.
We will not show the full code, for the sake of keeping the blog post short enough. The whole code will be available at: https://github.com/Sentrylink/tic_tac_toe
Implementing the node daemon is very simple, since all we need to do is connect the building blocks that exist in the Cosmos-SDK. The Cosmos-SDK contains functions for initialising the node state and configuration, starting the node, exporting its state etc.
It looks like this:
First we are setting the default home directory for our nodes. This is where all the configuration, blockchain data and application state will be stored. The default is the .ttt directory inside of the user’s home directory
After that we are setting up the CLI structure. The CLI is implemented using Cobra third-party software. We are hooking up functions with Cosmos-SDK with our application in the cool to server.AddCommand, by making sure that the function newApp returns an instance of our application.
The rest of the code in the file is taken from Cosmos-SDK and is pretty straightforward and contains the boilerplate that is needed to make this work. The full implementation is available on the Github
Client is separated into two halves — transactions and querying.
Transactions — consists of:
- taking the user input, either as command line arguments, flags, or interactive input
- instantiating the desired messages of the given module
- packaging them into transactions
- signing the transactions
- broadcasting the transactions
- checking the response and presenting it to the user
Querying — consists of:
- taking the user input as command line arguments or flags
- forming the desired query, by creating the query path
- sending the query to the node
- parsing, verifying and presenting the response to the user
For briefness sake, we will only show the implementation of CLI command to create and broadcast transaction containing a StartGame message. The implementation for the Play message is very similar and follows the same pattern.
The implementation looks like this:
Here, we are relying on cobra third-party package to handle a lot of the boilerplate needed to write CLI applications, like presenting the help to the user, parsing flags and arguments, doing the validations etc.
Then we are creating the cliCtx structure which holds important information for the proper execution of the command, as well as the txBldr structure which will be responsible for creating the transaction before signing and broadcasting it.
The address of the opponent is passed as an argument to the command, and the sender is passed with the — from flag, which is the convention used in Cosmos-SDK. The tokens that are used for the bet are passed on as a command line argument.
Then we create the MsgStartGame object, and call the SendTx function which is responsible for finalising the setup of txBldr and calling appropriate functions to broadcast the transaction to the node that the client is connected to.
After that, the utility functions in the Cosmos-SDK will parse the node response and present the outcome to the user in their terminal.
Implementation of the query looks like this:
The user is passing the game id as a command line argument. After creating the cliCtx object, as we did above, we are creating the appropriate query path, which matches to the one that is registered on the application router and implemented in the querier part of our module.
Once the query path is created, it is handed off to Cosmos-SDK’s utility function QueryWithData that will take care of sending the query to node, getting the response back and verifying it before returning it to us so that we can print it to the user.
To integrate our module’s CLI, we need to register it with the CLI core. This is done like this, in the main CLI function:
The module client list, in our case containing a single module, is then added to the root command through the query and tx command, to be fully integrated into the application’s CLI.
This concludes the blog post number six. In the following blog post we will show how to build and run the application, and interact with it using the CLI.