cosmos主网即将上线,对文档做了大量更新。特地翻译了一下,方便小伙伴们阅览, 之后会持续更新
第三章教程:
- 开始
- 程序目标
- 开始编写你的程序
- Keeper
- Msg和Handler
- SetName
- BuyName
- Querier
- Codec文件
- Nameservice模块的CLI
- nameservice模块的REST接口
- 引入你的模块并完成程序
- Entrypoint
- 编译你的程序
- 编译并运行程序
- 运行REST路由
Nameservice模块的CLI
Cosmos SDK使用cobra
库进行CLI交互。该库使每个模块都可以轻松地公开自己的操作命令。要开始定义用户与模块的CLI交互,请创建以下文件:
./x/nameservice/client/cli/query.go
./x/nameservice/client/cli/tx.go
./x/nameservice/client/module_client.go
Querier
在query.go
文件中为你模块的每个Query
(resolve
和whois
)定义cobra.Command
:
package cli
import (
"fmt"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/spf13/cobra"
)
// GetCmdResolveName queries information about a name
func GetCmdResolveName(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "resolve [name]",
Short: "resolve name",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
name := args[0]
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/resolve/%s", queryRoute, name), nil)
if err != nil {
fmt.Printf("could not resolve name - %s \n", string(name))
return nil
}
fmt.Println(string(res))
return nil
},
}
}
// GetCmdWhois queries information about a domain
func GetCmdWhois(queryRoute string, cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "whois [name]",
Short: "Query whois info of name",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc)
name := args[0]
res, err := cliCtx.QueryWithData(fmt.Sprintf("custom/%s/whois/%s", queryRoute, name), nil)
if err != nil {
fmt.Printf("could not resolve whois - %s \n", string(name))
return nil
}
fmt.Println(string(res))
return nil
},
}
}
注意上述代码中:
- CLI引入了一个新的
context
:CLIContext
。它包含有关CLI交互所需的用户输入和应用程序配置的数据。 -
cliCtx.QueryWithData()
函数所需的path
直接从你的查询路径中映射。- 路径的第一部分用于区分SDK应用程序可能的querier类型:
custom
用于Querier
- 第二部分(
nameservice
)是将查询路由到的模块的名称。 - 最后是要调用模块中的特定的querier。
- 在这个例子中,第四部分是查询。这是因为查询参数是一个简单的字符串。要启用更复杂的查询输入,你需要使用
.QueryWithData()
函数的第二个参数来传入data
。有关此示例,请参阅Staking模块中的querier。
- 路径的第一部分用于区分SDK应用程序可能的querier类型:
Transaction
现在已经定义了查询交互,是时候继续在tx.go
中的交易生成了:
你的应用程序需要导入你刚编写的代码。这里导入路径设置为此存储库(github.com/cosmos/sdk-application-tutorial/x/nameservice)。如果您是在自己的仓库中进行的前面的操作,则需要更改导入路径(github.com/{.Username}/{.Project.Repo}/x/nameservice)。
package cli
import (
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/sdk-application-tutorial/x/nameservice"
sdk "github.com/cosmos/cosmos-sdk/types"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
)
// GetCmdBuyName is the CLI command for sending a BuyName transaction
func GetCmdBuyName(cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "buy-name [name] [amount]",
Short: "bid for existing name or claim new name",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(cdc)
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
if err := cliCtx.EnsureAccountExists(); err != nil {
return err
}
coins, err := sdk.ParseCoins(args[1])
if err != nil {
return err
}
msg := nameservice.NewMsgBuyName(args[0], coins, cliCtx.GetFromAddress())
err = msg.ValidateBasic()
if err != nil {
return err
}
cliCtx.PrintResponse = true
return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg})
},
}
}
// GetCmdSetName is the CLI command for sending a SetName transaction
func GetCmdSetName(cdc *codec.Codec) *cobra.Command {
return &cobra.Command{
Use: "set-name [name] [value]",
Short: "set the value associated with a name that you own",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
cliCtx := context.NewCLIContext().WithCodec(cdc).WithAccountDecoder(cdc)
txBldr := authtxb.NewTxBuilderFromCLI().WithTxEncoder(utils.GetTxEncoder(cdc))
if err := cliCtx.EnsureAccountExists(); err != nil {
return err
}
msg := nameservice.NewMsgSetName(args[0], args[1], cliCtx.GetFromAddress())
err := msg.ValidateBasic()
if err != nil {
return err
}
cliCtx.PrintResponse = true
// return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, msgs)
return utils.CompleteAndBroadcastTxCLI(txBldr, cliCtx, []sdk.Msg{msg})
},
}
}
注意在上述代码中:
- 使用了
authcmd
包。查看文档了解更多使用信息。它提供对CLI控制的帐户的访问权限,并便于签名。
Module Client
导出此功能的最后一部分称为ModuleClient
,在./x/nameservice/client/module_client.go
文件中实现。Module Client为模块提供了导出客户端功能的标准方法。
注意:你的应用程序需要导入你刚编写的代码。这里导入路径设置为此仓库(github.com/cosmos/sdk-application-tutorial/x/nameservice)。如果你是在自己项目中编写的,则需要更改导入路径成(github.com/{.Username}/ {.Project.Repo}/x/nameservice)。
package client
import (
"github.com/cosmos/cosmos-sdk/client"
nameservicecmd "github.com/cosmos/sdk-application-tutorial/x/nameservice/client/cli"
"github.com/spf13/cobra"
amino "github.com/tendermint/go-amino"
)
// ModuleClient exports all client functionality from this module
type ModuleClient struct {
storeKey string
cdc *amino.Codec
}
func NewModuleClient(storeKey string, cdc *amino.Codec) ModuleClient {
return ModuleClient{storeKey, cdc}
}
// GetQueryCmd returns the cli query commands for this module
func (mc ModuleClient) GetQueryCmd() *cobra.Command {
// Group gov queries under a subcommand
govQueryCmd := &cobra.Command{
Use: "nameservice",
Short: "Querying commands for the nameservice module",
}
govQueryCmd.AddCommand(client.GetCommands(
nameservicecmd.GetCmdResolveName(mc.storeKey, mc.cdc),
nameservicecmd.GetCmdWhois(mc.storeKey, mc.cdc),
)...)
return govQueryCmd
}
// GetTxCmd returns the transaction commands for this module
func (mc ModuleClient) GetTxCmd() *cobra.Command {
govTxCmd := &cobra.Command{
Use: "nameservice",
Short: "Nameservice transactions subcommands",
}
govTxCmd.AddCommand(client.PostCommands(
nameservicecmd.GetCmdBuyName(mc.cdc),
nameservicecmd.GetCmdSetName(mc.cdc),
)...)
return govTxCmd
}
上述代码要注意:
- 此抽象允许客户端以标准方式从模块导入客户端功能。当我们构建入口时,你将看到这一点。
- 有一个未解决的问题是将其余功能(在本教程的下一部分中描述)添加到此接口。