Cosmos-- 三.教程 -- 7.BuyName

cosmos主网即将上线,对文档做了大量更新。特地翻译了一下,方便小伙伴们阅览, 之后会持续更新

第三章教程:

  1. 开始
  2. 程序目标
  3. 开始编写你的程序
  4. Keeper
  5. Msg和Handler
  6. SetName
  7. BuyName
  8. Querier
  9. Codec文件
  10. Nameservice模块的CLI
  11. nameservice模块的REST接口
  12. 引入你的模块并完成程序
  13. Entrypoint
  14. 编译你的程序
  15. 编译并运行程序
  16. 运行REST路由

BuyName

Msg

现在来定义购买域名的Msg,并加在./x/nameservice/msgs.go文件中。代码同SetName非常相似:

// MsgBuyName defines the BuyName message
type MsgBuyName struct {
    Name string
    Bid    sdk.Coins
    Buyer  sdk.AccAddress
}

// NewMsgBuyName is the constructor function for MsgBuyName
func NewMsgBuyName(name string, bid sdk.Coins, buyer sdk.AccAddress) MsgBuyName {
    return MsgBuyName{
        Name: name,
        Bid:    bid,
        Buyer:  buyer,
    }
}

// Type Implements Msg.
func (msg MsgBuyName) Route() string { return "nameservice" }

// Name Implements Msg.
func (msg MsgBuyName) Type() string { return "buy_name" }

// ValidateBasic Implements Msg.
func (msg MsgBuyName) ValidateBasic() sdk.Error {
    if msg.Buyer.Empty() {
        return sdk.ErrInvalidAddress(msg.Buyer.String())
    }
    if len(msg.Name) == 0 {
        return sdk.ErrUnknownRequest("Name cannot be empty")
    }
    if !msg.Bid.IsPositive() {
        return sdk.ErrInsufficientCoins("Bids must be positive")
    }
    return nil
}

// GetSignBytes Implements Msg.
func (msg MsgBuyName) GetSignBytes() []byte {
    b, err := json.Marshal(msg)
    if err != nil {
        panic(err)
    }
    return sdk.MustSortJSON(b)
}

// GetSigners Implements Msg.
func (msg MsgBuyName) GetSigners() []sdk.AccAddress {
    return []sdk.AccAddress{msg.Buyer}
}

接着,在./x/nameservice/handler.go文件中,把MsgBuyName加入到模块路由器中:

// 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)
        case MsgBuyName:
            return handleMsgBuyName(ctx, keeper, msg)
        default:
            errMsg := fmt.Sprintf("Unrecognized nameservice Msg type: %v", msg.Type())
            return sdk.ErrUnknownRequest(errMsg).Result()
        }
    }
}

最后,定义BuyNamehandler,该函数执行由msg触发的状态转换。请记住,此时msg已运行其ValidateBasic函数,因此已进行了一些输入验证。但是,ValidateBasic无法查询应用程序状态。应在handler中执行依赖于网络状态(例如帐户余额)的验证逻辑。

// Handle MsgBuyName
func handleMsgBuyName(ctx sdk.Context, keeper Keeper, msg MsgBuyName) sdk.Result {
    if keeper.GetPrice(ctx, msg.Name).IsAllGT(msg.Bid) { // Checks if the the bid price is greater than the price paid by the current owner
        return sdk.ErrInsufficientCoins("Bid not high enough").Result() // If not, throw an error
    }
    if keeper.HasOwner(ctx, msg.Name) {
        _, err := keeper.coinKeeper.SendCoins(ctx, msg.Buyer, keeper.GetOwner(ctx, msg.Name), msg.Bid)
        if err != nil {
            return sdk.ErrInsufficientCoins("Buyer does not have enough coins").Result()
        }
    } else {
        _, _, err := keeper.coinKeeper.SubtractCoins(ctx, msg.Buyer, msg.Bid) // If so, deduct the Bid amount from the sender
        if err != nil {
            return sdk.ErrInsufficientCoins("Buyer does not have enough coins").Result()
        }
    }
    keeper.SetOwner(ctx, msg.Name, msg.Buyer)
    keeper.SetPrice(ctx, msg.Name, msg.Bid)
    return sdk.Result{}
}

首先确保出价高于当前价格。然后,检查域名是否已有所有者。如果有,之前的所有者将会收到Buyer的钱。

如果没有所有者,你的nameservice模块会把Buyer的资金“燃烧”(即发送到不可恢复的地址)。

如果SubtractCoinsSendCoins返回一个非空错误,handler会抛出一个错误,回退状态转变。没有的话,使用之前在Keeper上定义的getter和setter,handler将买方设置为新所有者,并将新价格设置为当前出价。

注意:此handler使用coinKeeper中的函数执行货币相关操作。如果你的应用程序正在执行货币相关操作,你可能需要查看此模块的文档,以查看它暴露出来的功能。

你可能感兴趣的:(Cosmos-- 三.教程 -- 7.BuyName)