# Scaffold a new Cosmos SDK chain $โฏ ignite scaffold chain blog --address-prefix blog # Start your node (with hot reloading!) $โฏ ignite chain serve Cosmos SDK's version is: stargate - v0.46.3 ๐ Building proto... ๐ Building the blockchain... ๐ฟ Initializing the app... ๐ Initialize accounts... ๐ Added account alice with address blog1nq85jtlrjdtyvek8q9kdazxnz6fl55xt8m345h and mnemonic: man share habit age clap drama hammer pen genre flag employ bag fiscal air right stomach few risk fuel bleak certain phone victory topic ๐ Added account bob with address blog1r2s8g8phvx9axv9fwzr65rg7m8lkkg92ce2xxc and mnemonic: entry real theory salt obvious item bid avocado cluster desk strike trigger need poverty toward soda cancel annual wife float jewel dash focus else ๐ Tendermint node: http://0.0.0.0:26657 ๐ Blockchain API: http://0.0.0.0:1317 ๐ Token faucet: http://0.0.0.0:4500
$โฏ ignite scaffold message createPost title body modify proto/blog/blog/tx.proto modify x/blog/client/cli/tx.go create x/blog/client/cli/tx_create_post.go create x/blog/keeper/msg_server_create_post.go modify x/blog/module_simulation.go create x/blog/simulation/create_post.go modify x/blog/types/codec.go create x/blog/types/message_create_post.go create x/blog/types/message_create_post_test.go ๐ Created a message `createPost`.
message MsgCreatePost { string creator = 1; string title = 2; string body = 3; } message MsgCreatePostResponse { } service Msg { rpc CreatePost(MsgCreatePost) returns (MsgCreatePostResponse); }
message MsgCreatePost { string creator = 1; string title = 2; string body = 3; } message MsgCreatePostResponse { uint64 id = 1; // <--------- Fill the response! } service Msg { rpc CreatePost(MsgCreatePost) returns (MsgCreatePostResponse); }
package keeper func (k msgServer) CreatePost( goCtx context.Context, msg *types.MsgCreatePost, ) (*types.MsgCreatePostResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) // TODO: Handling the message _ = ctx return &types.MsgCreatePostResponse{}, nil }
syntax = "proto3"; package blog.blog; option go_package = "blog/x/blog/types"; // we'll be able to use `types.Post` in our Go code message Post { string creator = 1; uint64 id = 2; string title = 3; string body = 4; }
package types const ( // ModuleName defines the module name ModuleName = "blog" // StoreKey defines the primary module store key StoreKey = ModuleName // RouterKey defines the module's message routing key RouterKey = ModuleName // MemStoreKey defines the in-memory store key MemStoreKey = "mem_blog" // Keep track of the index of posts PostKey = "Post/value/" PostCountKey = "Post/count/" )
package keeper func (k Keeper) AppendPost(ctx sdk.Context, post types.Post) uint64 { // count = k.GetPostCount() // post = types.Post{ Id: count, ... } // k.Save(post) // k.SetPostCount(count + 1) } func (k Keeper) GetPostCount(ctx sdk.Context) uint64 { ... } func (k Keeper) SetPostCount(ctx sdk.Context, count uint64) { ... }
func (k Keeper) GetPostCount(ctx sdk.Context) uint64 { // Get the store using storeKey (which is "blog") and PostCountKey (which is "Post/count/") store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.PostCountKey)) // Get the value of the count bz := store.Get([]byte("count")) // Return zero if the count value is not found (for example, it's the first post) if bz == nil { return 0 } // Convert the count into uint64 return binary.BigEndian.Uint64(bz) }
func (k Keeper) SetPostCount(ctx sdk.Context, count uint64) { // Get the store using storeKey (which is "blog") and PostCountKey (which is "Post/count/") store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.PostCountKey)) // Convert count from uint64 to string and get bytes bz := make([]byte, 8) binary.BigEndian.PutUint64(bz, count) // Set the value of Post/count/ to count store.Set([]byte("count"), bz) }
func (k Keeper) AppendPost(ctx sdk.Context, post types.Post) uint64 { // Get the current number of posts in the store count := k.GetPostCount(ctx) // Assign an ID to the post based on the number of posts in the store post.Id = count // Get the store store := prefix.NewStore(ctx.KVStore(k.storeKey), []byte(types.PostKey)) // Convert the post ID into bytes byteKey := make([]byte, 8) binary.BigEndian.PutUint64(byteKey, post.Id) // Marshal the post into bytes appendedValue := k.cdc.MustMarshal(&post) // Insert the post bytes using post ID as a key store.Set(byteKey, appendedValue) // Update the post count k.SetPostCount(ctx, count+1) return count }
package keeper func (k msgServer) CreatePost(goCtx context.Context, msg *types.MsgCreatePost) (*types.MsgCreatePostResponse, error) { // Get the context ctx := sdk.UnwrapSDKContext(goCtx) // Create variable of type Post var post = types.Post{ Creator: msg.Creator, Title: msg.Title, Body: msg.Body, } // Add a post to the store and get back the ID id := k.AppendPost(ctx, post) // Return the ID of the post return &types.MsgCreatePostResponse{Id: id}, nil }
$โฏ blogd tx blog create-post \ 'Ciao pisa.dev!!' \ 'Questo รจ il primo post sulla nostra blockchain!' \ --from alice auth_info: fee: gas_limit: "200000" body: messages: - '@type': /blog.blog.MsgCreatePost creator: blog1nq85jtlrjdtyvek8q9kdazxnz6fl55xt8m345h body: Questo รจ il primo post sulla nostra blockchain! title: Ciao pisa.dev!! confirm transaction before signing and broadcasting [y/N]: ... gas_used: "53758" gas_wanted: "200000"
$โฏ ignite scaffold query posts --response title,body modify proto/blog/blog/query.proto modify x/blog/client/cli/query.go create x/blog/client/cli/query_posts.go create x/blog/keeper/grpc_query_posts.go ๐ Created a query `posts`.
message QueryPostsRequest { } message QueryPostsResponse { string title = 1; string body = 2; } service Query { rpc Posts(QueryPostsRequest) returns (QueryPostsResponse) }
import "blog/blog/post.proto"; message QueryPostsRequest { } message QueryPostsResponse { repeated Post Posts = 1; } service Query { rpc Posts(QueryPostsRequest) returns (QueryPostsResponse) }
func (k Keeper) Posts( goCtx context.Context, req *types.QueryPostsRequest, ) (*types.QueryPostsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } ctx := sdk.UnwrapSDKContext(goCtx) // TODO: Process the query _ = ctx return &types.QueryPostsResponse{}, nil }
func (k Keeper) Posts( goCtx context.Context, req *types.QueryPostsRequest, ) (*types.QueryPostsResponse, error) { ... // Define a variable that will store a list of posts var posts []*types.Post // Get the post store store := ctx.KVStore(k.storeKey) postStore := prefix.NewStore(store, []byte(types.PostKey)) for iter := postStore.Iterator(nil, nil); iter.Valid(); iter.Next() { var post types.Post k.cdc.MustUnmarshal(iter.Value(), &post) posts = append(posts, &post) } return &types.QueryPostsResponse{ Posts: posts }, nil }
$โฏ blogd query blog posts Posts: - body: Questo รจ il primo post sulla nostra blockchain! creator: blog1nq85jtlrjdtyvek8q9kdazxnz6fl55xt8m345h id: "0" title: Ciao pisa.dev!! - body: Questo รจ il secondo post sulla nostra blockchain! creator: blog1r2s8g8phvx9axv9fwzr65rg7m8lkkg92ce2xxc id: "1" title: Hey sono Bob
#{{ post.id }} {{ post.title }} {{ post.body }} written by {{ post.creator }}
{{ post.body }}
written by {{ post.creator }}
type MyApp struct { db *badger.DB currentTx *badger.Txn } func (app *MyApp) Query(reqQuery abci.RequestQuery) (res abci.ResponseQuery) { value, _ := app.db.Get(reqQuery.Data) return &abci.ResponseQuery{Value: value} } func (app *MyApp) BeginBlock(...) abci.ResponseBeginBlock { app.currentTx = app.db.NewTransaction(true) } func (app *MyApp) DeliverTx(req abci.RequestDeliverTx) abci.ResponseDeliverTx { key, value := bytes.Split(req.Tx, []byte("=")) err := app.currentTx.Set(key, value) ... } func (app *MyApp) Commit() abci.ResponseCommit { app.currentTx.Commit() }