You have finished the checkers Go blockchain exercise. If not, you can follow the tutorial here, or just clone and checkout the relevant branch(opens new window) that contains the final version.
With your checkers application ready for use, it is a good time to prepare client elements that eventually allow you to create a GUI and/or server-side scripts. Here, you will apply what you have learned about creating your own custom CosmJS interfaces.
Before you can get into working on your application directly, you need to make sure CosmJS understands your checkers module and knows how to interact with it. This generally means you need to create the Protobuf objects and clients in TypeScript and create extensions that facilitate the use of them.
You will have to create a client folder that will contain all these new elements. If you want to keep the Go parts of your checkers project separate from the TypeScript parts, you can use another repository for the client. To keep a link between the two repositories, add the client parts as a submodule to your Go parts:
In effect, this creates a new client folder. This client folder makes it possible for you to easily update another repository with content generated out of your Go code.
As noted previously when you created your project with Ignite, your project is known as alice/checkers (or the alternative name you chose).
Therefore, if you choose to reuse github.com/cosmos/academy-checkers-ui, you must do one of the following:
Make sure to replace all occurrences of b9lab/checkers with alice/checkers, or whichever name you picked.
Re-run the protoc step so that it does this replacement for you.
If you do not do one of these actions, you may encounter ambiguous errors such as:
Copy
Query failed with (6): unknown query path: unknown request
at QueryClient.queryUnverified (http://localhost:3000/static/js/bundle.js:21568:13)
at async Object.getAllStoredGames (http://localhost:3000/static/js/bundle.js:2975:26)
at async src_checkers_stargateclient__WEBPACK_IMPORTED_MODULE_0__.CheckersStargateClient.getGuiGames
Create a folder named scripts in your project root. This is where you will launch the Protobuf compilation:
Copy
$ mkdir -p scripts/protoc
In the scripts folder, or in your Docker image, install a compiler:
Copy
$ cd scripts/protoc
$ curl -L https://github.com/protocolbuffers/protobuf/releases/download/v21.5/protoc-21.5-linux-x86_64.zip -o protoc.zip
$ unzip protoc.zip
$ rm protoc.zip
# If /usr/local/bin is in your $PATH
$ ln -s $(pwd)/bin/protoc /usr/local/bin/protoc
$ cd ../..
Make sure that:
/usr/local/bin is the right folder to link to in the command above.
You are downloading the right executable for your computer; see your options here(opens new window).
Copy
- FROM --platform=linux ubuntu:22.04
+ FROM --platform=linux ubuntu:22.04 as base
ARG BUILDARCH
...
ENV MOCKGEN_VERSION=1.6.0
+ ENV PROTOC_VERSION=21.7
++ FROM base AS platform-amd64
+ ENV PROTOC_PLATFORM=x86_64
++ FROM base AS platform-arm64
+ ENV PROTOC_PLATFORM=aarch_64
++ FROM platform-${BUILDARCH}
ENV LOCAL=/usr/local
...
- ENV PACKAGES curl gcc jq make
+ ENV PACKAGES curl gcc jq make unzip
...
RUN go install github.com/golang/mock/mockgen@v${MOCKGEN_VERSION}
+ # Install ProtoC
+ RUN mkdir -p /usr/lib/protoc
+ WORKDIR /usr/lib/protoc
+ RUN curl -L https://github.com/protocolbuffers/protobuf/releases/download/v${PROTOC_VERSION}/protoc-${PROTOC_VERSION}-linux-${PROTOC_PLATFORM}.zip -o protoc.zip
+ RUN unzip -o protoc.zip
+ RUN rm protoc.zip
+ RUN ln -s /usr/lib/protoc/bin/protoc ${LOCAL}/bin/protoc
...
Dockerfile-ubuntu View source
Rebuild your Docker image.
Now install your additional modules:
Copy
$ cd scripts
$ npm install ts-proto@1.121.6 --save-dev --save-exact
$ cd ..
At this point, you have the generated files in your client folder. If you have made this client folder as a Git submodule, then you can work directly in it and do not need to go back to the checkers Cosmos SDK:
Copy
$ cd client
Also, if you use Docker and did not go through the trouble of building the Docker image for the checkers Cosmos SDK, you can use the node:18.7-slim image.
Install the Protobuf.js package in your client project:
At a later stage, you will add checkers as an extension to Stargate, but you can define your checkers extension immediately. The canPlay query could make use of better types for player and position. Start by declaring them in client/src/checkers/player.ts:
Describe how to connect to the running blockchain in a .env file in your project root. This depends on where you will run the tests, not on where you run the blockchain:
Because the intention is to run these tests against a running chain, possibly a fresh one, they cannot expect too much, such as how many games have been created so far. Still, it is possible to at least test that the connection is made and queries pass through.
Copy
import{ expect }from"chai"import{ config }from"dotenv"import Long from"long"import _ from"../../environment"import{ CheckersStargateClient }from"../../src/checkers_stargateclient"import{ CheckersExtension }from"../../src/modules/checkers/queries"config()describe("StoredGame",function(){let client: CheckersStargateClient, checkers: CheckersExtension["checkers"]before("create client",asyncfunction(){
client =await CheckersStargateClient.connect(process.env.RPC_URL)
checkers = client.checkersQueryClient!.checkers
})it("can get game list",asyncfunction(){const allGames =await checkers.getAllStoredGames(
Uint8Array.of(),
Long.fromInt(0),
Long.fromInt(0),true,)expect(allGames.storedGames).to.be.length.greaterThanOrEqual(0)})it("cannot get non-existent game",asyncfunction(){try{await checkers.getStoredGame("no-id")
expect.fail("It should have failed")}catch(error){expect(error.toString()).to.equal("Error: Query failed with (22): rpc error: code = NotFound desc = not found: key not found",)}})}) test integration stored-game.ts View source
Note the forced import of import _ from "../../environment", to actively inform on the string type (as opposed to string | undefined) and avoid any compilation error.
There is more than one way to run a checkers blockchain. For instance:
If you came here after going through the rest of the hands-on exercise, you know how to launch a running chain with Ignite.
If you arrived here and are only focused on learning CosmJS, it is possible to abstract away niceties of the running chain in a minimal package. For this, you need Docker and to create an image:
If that is not the case, you may encounter ambiguous errors such as:
Copy
Query failed with (6): unknown query path: unknown request
at QueryClient.queryUnverified (http://localhost:3000/static/js/bundle.js:21568:13)
at async Object.getAllStoredGames (http://localhost:3000/static/js/bundle.js:2975:26)
at async src_checkers_stargateclient__WEBPACK_IMPORTED_MODULE_0__.CheckersStargateClient.getGuiGames
Launch your checkers chain. You can choose your preferred method, as long as it can be accessed at the RPC_URL you defined earlier. For the purposes of this exercise, you have the choice between three methods:
If your checkers-net network already exists, the first command fails with:
Copy
Error response from daemon: network with name checkers-net already exists
But that is okay.
When using Docker, note:
--name checkers either matches the name you wrote in RPC_URL, or can be passed as an environment variable to another container to override the value found in .env.
--network checkers-net, which is reused shortly if you also run your npm tests in Docker. See the paragraph on Docker network, later in this section.
This starts the container on the same network as the blockchain container, where checkers resolves to the checkers container. And it also passes RPC_URL as an override of the value found in .env, typically localhost.
This should return:
Copy
StoredGame
✔ can get game list (39ms)
✔ cannot get non-existent game
SystemInfo
✔ can get system info
3 passing (287ms)
The only combination of running chain / running tests that will not work is if you run Ignite on your local computer and the tests in a container. For this edge case, you should put your host IP address in --env RPC_URL="http://YOUR-HOST-IP:26657".
You may not have used Docker up to this point. The following paragraphs acquaint you with a Docker user-defined bridged network.
If you plan on using Docker Compose at a later stage, having a first taste of such networks is beneficial. Docker Compose can be used to orchestrate and launch separate containers in order to mimic a production setup. In fact, in the production section of this hands-on exercise you do exactly that. If you think this could eventually be useful, you should go through this section. You may want to redo this section with Docker(opens new window).
A Docker network was created with the name checkers-net. If containers are started in this network, all ports are mutually accessible.
Your container started in it with the resolvable name of checkers.
With -p 26657:26657, port 26657 was forwarded to your host computer, on top of being already shared on the checkers-net network.
Then, for tests:
When you ran:
Copy
$ npm test
Your tests, running on the host computer, accessed the checkers chain from the host computer via the forwarded port 26657. Hence RPC_URL="http://localhost:26657".
Your tests, running in a different container, accessed the checkers chain within the checkers-netDocker network thanks to the checkers name resolution. Hence RPC_URL="http://checkers:26657".
In particular, the -p 26657:26657 port forwarding was not necessary. You can confirm that by stopping your chain and starting it again, this time without -p.
Docker networks are explored further in the next section.
When you are done, if you started the chain in Docker you can stop the containers with:
The need to prepare the elements that will eventually allow you to create a GUI and/or server-side scripts for your checkers application.
How to create the necessary Protobuf objects and clients in TypeScript, the extensions that facilitate the use of these clients, so that CosmJS will understand and be able to interact with your checkers module.
How to use Docker to define a network to launch separate containers that can communicate, for the purpose of integration testing.