cosmos主网即将上线,对文档做了大量更新。特地翻译了一下,方便小伙伴们阅览, 之后会持续更新
第三章教程:
- 开始
- 程序目标
- 开始编写你的程序
- Keeper
- Msg和Handler
- SetName
- BuyName
- Querier
- Codec文件
- Nameservice模块的CLI
- nameservice模块的REST接口
- 引入你的模块并完成程序
- Entrypoint
- 编译你的程序
- 编译并运行程序
- 运行REST路由
SetName
Msg
SDK中Msg
的命令约束是 Msg{.Action}
。要实现的第一个操作是SetName
,因此命名为MsgSetName
。此Msg
允许域名的所有者设置该域名的解析返回值。首先在名为./x/nameservice/msgs.go
的新文件中定义MsgSetName
:
package nameservice
import (
"encoding/json"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// MsgSetName defines a SetName message
type MsgSetName struct {
Name string
Value string
Owner sdk.AccAddress
}
// NewMsgSetName is a constructor function for MsgSetName
func NewMsgSetName(name string, value string, owner sdk.AccAddress) MsgSetName {
return MsgSetName{
Name: name,
Value: value,
Owner: owner,
}
}
MsgSetName
具有设置域名解析值所需的三个属性:
-
name
- 所要设置的域名 -
value
- 要设置的域名解析值 -
owner
- 域名的所有者
接下来,实现Msg
接口:
// Type should return the name of the module
func (msg MsgSetName) Route() string { return "nameservice" }
// Name should return the action
func (msg MsgSetName) Type() string { return "set_name"}
SDK使用上述函数将Msg
路由至合适的模块进行处理。它们还为用于索引的数据库标签添加了可读性的名称。
// ValdateBasic Implements Msg.
func (msg MsgSetName) ValidateBasic() sdk.Error {
if msg.Owner.Empty() {
return sdk.ErrInvalidAddress(msg.Owner.String())
}
if len(msg.Name) == 0 || len(msg.Value) == 0 {
return sdk.ErrUnknownRequest("Name and/or Value cannot be empty")
}
return nil
}
ValidateBasic
用于对Msg
的有效性进行一些基本的无状态检查。在此情形下,请检查没有属性为空。请注意这里使用sdk.Error
类型。 SDK提供了一组应用开发人员经常遇到的错误类型。
// GetSignBytes Implements Msg.
func (msg MsgSetName) GetSignBytes() []byte {
b, err := json.Marshal(msg)
if err != nil {
panic(err)
}
return sdk.MustSortJSON(b)
}
GetSignBytes
定义了如何编码Msg
以进行签名。在大多数情形下,要编码成排好序的JSON。不应修改输出。
// GetSigners Implements Msg.
func (msg MsgSetName) GetSigners() []sdk.AccAddress {
return []sdk.AccAddress{msg.Owner}
}
GetSigners
定义一个Tx
上需要哪些人的签名才能使其有效。在这种情形下,MsgSetName
要求域名所有者在尝试重置域名解析值时要对该交易签名。
Handler
现在MsgSetName
已经定义好了,下一部来定义收到此Msg时需要采取的操作。也就是handler
所要做的。
在一个新文件(./x/nameservice/handler.go
)先写入如下代码:
package nameservice
import (
"fmt"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// NewHandler returns a handler for "nameservice" type messages.
func NewHandler(keeper Keeper) sdk.Handler {
return func(ctx sdk.Context, msg sdk.Msg) sdk.Result {
switch msg := msg.(type) {
case MsgSetName:
return handleMsgSetName(ctx, keeper, msg)
default:
errMsg := fmt.Sprintf("Unrecognized nameservice Msg type: %v", msg.Type())
return sdk.ErrUnknownRequest(errMsg).Result()
}
}
}
NewHandler
本质上是一个子路由,它将进入该模块的msg路由到正确的handler做处理。目前,只有一个 Msg
/Handler
。
现在,你需要定义在handlerMsgSetName
中定义处理MsgSetName
消息的实际逻辑:
注意:SDK中handler的命名规范是
handlerMsg{.Action}
// Handle MsgSetName
func handleMsgSetName(ctx sdk.Context, keeper Keeper, msg MsgSetName) sdk.Result {
if !msg.Owner.Equals(keeper.GetOwner(ctx, msg.Name)) { // Checks if the the msg sender is the same as the current owner
return sdk.ErrUnauthorized("Incorrect Owner").Result() // If not, throw an error
}
keeper.SetName(ctx, msg.Name, msg.Value) // If so, set the name to the value specified in the msg.
return sdk.Result{} // return
}
在此函数中,要检查Msg
的发送者是否就是域名的所有者(keeper.GetOwner)。如果是,就能通过调用Keeper
里的函数来设置域名。如果不是,则抛出错误并返回给用户。