This README provides comprehensive instructions on how to build, run, and interact with the BlockPost application. BlockPost is a custom blockchain built using the Cosmos SDK, featuring a custom module for posting and retrieving messages.
- Prerequisites
- Building the Blockchain
- Running the Blockchain
- Interacting with the Blockchain
- Backend Server
- Frontend Application
- Running Tests
Ensure you have the following installed:
- Go (version 1.21 or later)
- Node.js and npm
- Ignite CLI
- Download Go from the official website.
- Follow the installation instructions for your operating system.
- Set up your Go workspace:
mkdir -p $HOME/go/bin
echo 'export GOPATH=$HOME/go' >> ~/.zshrc
echo 'export PATH=$PATH:$GOPATH/bin' >> ~/.zshrc
source ~/.zshrcReplace .zshrc with .bashrc if you're using Bash.
curl https://get.ignite.com/cli! | bash- Create a new blockchain project:
ignite scaffold chain blockpost --no module
cd blockpost- Scaffold the
blockpostmodule:
ignite scaffold module blockpost --dep account,bank- Define the
BlockPostMessageinproto/blockpost/blockpost/tx.proto:
message MsgBlockPostMessage {
string signer = 1;
string message = 2;
}
message MsgBlockPostMessageResponse {
uint64 id = 1;
}- Implement the message handler in
x/blockpost/keeper/msg_server_block_post_message.go:
func (k msgServer) BlockPostMessage(goCtx context.Context, msg *types.MsgBlockPostMessage) (*types.MsgBlockPostMessageResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
id := k.AppendMessage(ctx, *msg)
return &types.MsgBlockPostMessageResponse{Id: id}, nil
}- Implement state management in
x/blockpost/keeper/message.go:
func (k Keeper) AppendMessage(ctx sdk.Context, message types.MsgBlockPostMessage) uint64 {
count := k.GetMessageCount(ctx)
storedMessage := types.StoredMessage{
Id: count,
Message: message.Message,
Signer: message.Signer,
}
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.KeyPrefix(types.MessageKey))
appendedValue := k.cdc.MustMarshal(&storedMessage)
store.Set(GetMessageIDBytes(count), appendedValue)
k.SetMessageCount(ctx, count+1)
return count
}- Add query endpoints in
proto/blockpost/blockpost/query.proto:
service Query {
rpc Message(QueryGetMessageRequest) returns (QueryGetMessageResponse) {
option (google.api.http).get = "/blockpost/blockpost/message/{id}";
}
rpc MessageAll(QueryAllMessageRequest) returns (QueryAllMessageResponse) {
option (google.api.http).get = "/blockpost/blockpost/message";
}
}-
Implement query handlers in
x/blockpost/keeper/query_message.go. -
implement tyes and tests for both msg_server and types
-
Alternatively, in place of steps 4- 8, scaffold the chain as below (afterwards implement all placeholders, module code and app code):
ignite scaffold list message message --no-message
ignite scaffold message create-block-post-message message:string
ignite scaffold query show-block-post-message id:uint
ignite scaffold query list-block-post-messages - Build the blockchain.
ignite chain buildif for any reason you edit the proto files, run:
ignite generate proto-go- Start the blockchain. First, navigate to the blockchain folder:
cd blockpost
ignite chain serveyou should get something similar to this:
➜ blockpost git:(main) ignite chain serve
Blockchain is running
👤 alice's account address: blocpost1stqf3nda9da0ae9ycx6kdjytevzu2ar2gzjjp9
👤 bob's account address: blocpost1yvsaajje2pdjt4ch5ahhstezmvqnr4dmpg88wt
🌍 Tendermint node: http://0.0.0.0:26657
🌍 Blockchain API: http://0.0.0.0:1317
🌍 Token faucet: http://0.0.0.0:4500
⋆ Data directory: /Users/emekaonwuliri/.blockpost
⋆ App binary: /Users/emekaonwuliri/go/bin/blockpostdNote the address output, e.g., blocpost1stqf3nda9da0ae9ycx6kdjytevzu2ar2gzjjp9 for future steps
ctrl C to exit the serve. And follow next commands:
cd ..
blockpostd startif you get a 'command not found error', repeat these
echo 'export PATH=$PATH:/Users/emekaonwuliri/go/bin' >> ~/.zshrc
source ~/.zshrc- Set up another test account as below if needed, preferably use the alice or bob account from step 1:
blockpostd keys add test1- Post a message. Use your address from earlier steps as the 'from' address:
blockpostd tx blockpost create-block-post-message "Hello, BlockPost!" --from blocpost1stqf3nda9da0ae9ycx6kdjytevzu2ar2gzjjp9 --chain-id blockpost
blockpostd tx blockpost create-block-post-message "Welcome Emeka!" --from blocpost1stqf3nda9da0ae9ycx6kdjytevzu2ar2gzjjp9 --chain-id blockpost- Query all messages:
blockpostd q blockpost list-block-post-messages- Query a specific message:
blockpostd q blockpost show-block-post-message 0
blockpostd q blockpost show-block-post-message 1- Navigate to the backend directory:
cd backend- Install dependencies:
npm install- Start the server:
node server.jsThe server will start on http://localhost:3001.
- Navigate to the frontend directory:
cd frontend- Install dependencies:
npm install- Update the signer address in
src/components/SubmitMessage.jsand save:
const signer = 'blocpost1stqf3nda9da0ae9ycx6kdjytevzu2ar2gzjjp9'; //use your alice address from earlier steps- Start the React app:
npm startThe app will be available at http://localhost:3000.
- Blockchain tests:
cd x/blockpost
go test ./...- Backend tests:
cd backend
npm test- Frontend tests:
cd frontend
npm testThis README demonstrates the process of building a custom Cosmos SDK blockchain with a specific module (blockpost), implementing message handling, state management, and query endpoints. It also covers setting up a backend server to interact with the blockchain and a frontend application for user interaction.
The use of Protobuf for message definitions, the implementation of keepers for state management, and the setup of CLI commands showcase the depth of knowledge in Cosmos SDK development. The integration of a custom module into the blockchain, along with the frontend and backend components, demonstrates a full-stack blockchain application development process.
