Path: blob/main/docs/versioned_docs/version-v0.26/02-guide/04-blog/03-create.md
1007 views
Creating posts
In this chapter, we will be focusing on the process of handling a "create post" message. This involves the use of a special type of function known as a keeper method. Keeper methods are responsible for interacting with the blockchain and modifying its state based on the instructions provided in a message.
When a "create post" message is received, the corresponding keeper method will be called and passed the message as an argument. The keeper method can then use the various getter and setter functions provided by the store object to retrieve and modify the current state of the blockchain. This allows the keeper method to effectively process the "create post" message and make the necessary updates to the blockchain.
In order to keep the code for accessing and modifying the store object clean and separate from the logic implemented in the keeper methods, we will create a new file called post.go
. This file will contain functions that are specifically designed to handle operations related to creating and managing posts within the blockchain.
Appending posts to the store
This code defines a function called AppendPost
which belongs to a Keeper
type. The Keeper
type is responsible for interacting with the blockchain and modifying its state in response to various messages.
The AppendPost
function takes in two arguments: a Context
object and a Post
object. The Context
object is a standard parameter in many functions in the Cosmos SDK and is used to provide contextual information about the current state of the blockchain, such as the current block height. The Post
object represents a post that will be added to the blockchain.
The function begins by retrieving the current post count using the GetPostCount
method. You will implement this method in the next step as it has not been implemented yet. This method is called on the Keeper
object and takes in a Context
object as an argument. It returns the current number of posts that have been added to the blockchain.
Next, the function sets the ID of the new post to be the current post count, so that each post has a unique identifier. It does this by assigning the value of count to the Id
field of the Post
object.
The function then creates a new store object using the prefix.NewStore
function. The prefix.NewStore
function takes in two arguments: the KVStore
associated with the provided context and a key prefix for the Post
objects. The KVStore
is a key-value store that is used to persist data on the blockchain, and the key prefix is used to differentiate the Post
objects from other types of objects that may be stored in the same KVStore
.
The function then serializes the Post
object using the cdc.MustMarshal
function and stores it in the blockchain using the Set
method of the store object. The cdc.MustMarshal
function is part of the Cosmos SDK's encoding/decoding library and is used to convert the Post
object into a byte slice that can be stored in the KVStore
. The Set
method is called on the store object and takes in two arguments: a key and a value. In this case, the key is a byte slice generated by the GetPostIDBytes
function and the value is the serialized Post
object. You will implement this method in the next step as it has not been implemented yet.
Finally, the function increments the post count by one and updates the blockchain state using the SetPostCount
method. You will implement this method in the next step as it has not been implemented yet. This method is called on the Keeper object and takes in a Context
object and a new post count as arguments. It updates the current post count in the blockchain to be the new post count provided.
The function then returns the ID of the newly created post, which is the current post count before it was incremented. This allows the caller of the function to know the ID of the post that was just added to the blockchain.
To complete the implementation of AppendPost
, the following tasks need to be performed:
Define
PostKey
, which will be used to store and retrieve posts from the database.Implement
GetPostCount
, which will retrieve the current number of posts stored in the database.Implement
GetPostIDBytes
, which will convert a post ID to a byte array.Implement
SetPostCount
, which will update the post count stored in the database.
Post key prefix
In the file keys.go
, let's define the PostKey
prefix as follows:
This prefix will be used to uniquely identify a post within the system. It will be used as the beginning of the key for each post, followed by the ID of the post to create a unique key for each post.
Getting the post count
In the file post.go
, let's define the GetPostCount
function as follows:
This code defines a function named GetPostCount
that belongs to the Keeper
struct. The function takes in a single argument, a context object ctx
of type sdk.Context
, and returns a value of type uint64
.
The function begins by creating a new store using the key-value store in the context and an empty byte slice as the prefix. It then defines a byte slice byteKey
using the KeyPrefix
function from the types
package, which takes in the PostCountKey
. You will define PostCountKey
in the next step.
The function then retrieves the value at the key byteKey
in the store using the Get
method and stores it in a variable bz
.
Next, the function checks if the value at byteKey
is nil
using an if statement. If it is nil
, meaning that the key does not exist in the store, the function returns 0. This indicates that there are no elements or posts associated with the key.
If the value at byteKey
is not nil, the function uses the binary
package's BigEndian
type to parse the bytes in bz
and returns the resulting uint64
value. The BigEndian
type is used to interpret the bytes in bz
as a big-endian encoded unsigned 64-bit integer. The Uint64
method converts the bytes to a uint64
value and returns it.
GetPostCount
function is used to retrieve the total number of posts stored in the key-value store, represented as a uint64
value.
In the file keys.go
, let's define the PostCountKey
as follows:
This key will be used to keep track of the ID of the latest post added to the store.
Converting post ID to bytes
Now, let's implement GetPostIDBytes
, which will convert a post ID to a byte array.
GetPostIDBytes
takes in a value id
of type uint64
and returns a value of type []byte
.
The function starts by creating a new byte slice bz
with a length of 8 using the make
built-in function. It then uses the binary
package's BigEndian
type to encode the value of id
as a big-endian encoded unsigned integer and store the result in bz
using the PutUint64
method. Finally, the function returns the resulting byte slice bz
.
This function can be used to convert a post ID, represented as a uint64
, to a byte slice that can be used as a key in a key-value store. The binary.BigEndian.PutUint64
function encodes the uint64
value of id
as a big-endian encoded unsigned integer and stores the resulting bytes in the []byte
slice bz
. The resulting byte slice can then be used as a key in the store.
Updating the post count
Implement SetPostCount
in post.go
, which will update the post count stored in the database.
This code defines a function SetPostCount
in the Keeper
struct. The function takes in a context ctx
of type sdk.Context
and a value count
of type uint64
, and does not return a value.
The function first creates a new store by calling the NewStore
function from the prefix package and passing in the key-value store from the context and an empty byte slice as the prefix. It stores the resulting store in a variable named store
.
Next, the function defines a byte slice byteKey
using the KeyPrefix
function from the types
package and passing in the PostCountKey
. The KeyPrefix
function returns a byte slice with the given key as a prefix.
The function then creates a new byte slice bz
with a length of 8 using the make
built-in function. It then uses the binary
package's BigEndian
type to encode the value of count as a big-endian encoded unsigned integer and store the result in bz
using the PutUint64
method.
Finally, the function calls the Set
method on the store
variable, passing in byteKey
and bz
as arguments. This sets the value at the key byteKey
in the store to the value bz
.
This function can be used to update the count of posts stored in the database. It does this by converting the uint64
value of count to a byte slice using the binary.BigEndian.PutUint64
function, and then storing the resulting byte slice at the key byteKey
in the store using the Set
method.
Now that you have implemented the code for creating blog posts, you can proceed to implement the keeper method that is invoked when the "create post" message is processed.
Handling the "create post" message
The CreatePost
function is a message handler for the MsgCreatePost
message type. It is responsible for creating a new post on the blockchain based on the information provided in the MsgCreatePost
message.
The function first retrieves the Cosmos SDK context from the Go context using the sdk.UnwrapSDKContext
function. It then creates a new Post
object using the Creator
, Title
, and Body
fields from the MsgCreatePost message.
Next, the function calls the AppendPost
method on the msgServer
object (which is of the Keeper type) and passes in the Cosmos SDK context and the new Post
object as arguments. The AppendPost
method is responsible for adding the new post to the blockchain and returning the ID of the new post.
Finally, the function returns a MsgCreatePostResponse
object that contains the ID of the new post. It also returns a nil error, indicating that the operation was successful.
Summary
Great job! You have successfully implemented the logic for writing blog posts to the blockchain store and the keeper method that will be called when a "create post" message is processed.
The AppendPost
keeper method retrieves the current post count, sets the ID of the new post to be the current post count, serializes the post object, and stores it in the blockchain using the Set
method of the store
object. The key for the post in the store is a byte slice generated by the GetPostIDBytes
function and the value is the serialized post object. The function then increments the post count by one and updates the blockchain state using the SetPostCount
method.
The CreatePost
handler method receives a MsgCreatePost
message containing the data for the new post, creates a new Post
object using this data, and passes it to the AppendPost
keeper method to be added to the blockchain. It then returns a MsgCreatePostResponse
object containing the ID of the newly created post.
By implementing these methods, you have successfully implemented the necessary logic for handling "create post" messages and adding posts to the blockchain.