这篇文章主要讲述使用Cosmos
的Ignite-Cli
工具快速开发NameService
应用。NameService
的主要功能是用户可以购买域名,给域名设置可以解析的地址或则值,域名拥有者可以删除域名。
DockerFile-ubuntu
FROM --platform=linux ubuntu:22.04
ARG BUILDARCH
# Change your versions here
ENV GO_VERSION=1.18.3
ENV IGNITE_VERSION=0.22.1
ENV NODE_VERSION=18.x
ENV LOCAL=/usr/local
ENV GOROOT=$LOCAL/go
ENV HOME=/root
ENV GOPATH=$HOME/go
ENV PATH=$GOROOT/bin:$GOPATH/bin:$PATH
RUN mkdir -p $GOPATH/bin
ENV PACKAGES curl gcc jq
RUN apt-get update
RUN apt-get install -y $PACKAGES
# Install Go
RUN curl -L https://go.dev/dl/go${GO_VERSION}.linux-$BUILDARCH.tar.gz | tar -C $LOCAL -xzf -
# Install Ignite
RUN curl -L https://get.ignite.com/cli@v${IGNITE_VERSION}! | bash
# Install Node
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION} | bash -
RUN apt-get install -y nodejs
EXPOSE 1317 3000 4500 5000 26657
WORKDIR /nameservice
docker build -f DockerFile-ubuntu . -t ns_i
docker create --name ns -i -v $(pwd):/nameservice -w /nameservice -p 1317:1317 -p 4500:4500 -p 5000:5000 -p 26657:26657 ns_i
docker start ns
docker exec -it ns ignite version
显示如下内容,则表示环境安装成功。
Ignite CLI version: v0.22.1
如果环境安装有问题,可以私信我帮你看看!
docker exec -it ns ignite scaffold chain nameservice --no-module
这个命令会创建一个nameservice
目录,已经实现了基于Cosmos SDK
的区块链功能。
然后我们把代码移动到当前的工作目录
mv nameservice/* ./
rm -rf nameservice
Module
docker exec -it ns ignite scaffold module nameservice --dep bank
--dep bank
表示该模块依赖bank
模块
Message
根据我们的业务我们需要创建 3 个Message
Message
:docker exec -it ns ignite scaffold message buy-name name bid
buy-name
是方法名,(name, bid)
是参数
docker exec -it ns ignite scaffold message set-name name value
set-name
是方法名,(name, value)
是参数
docker exec -it ns ignite scaffold message delete-name name
delete-name
是方法名,(name)
是参数
Types
现在我们需要创建一个储存的数据结构来记录当前域名的归属关系,我们创建一个Whois
的结构
docker exec -it ns ignite scaffold map whois name value price owner --no-message
whois
是 typename
是域名value
是域名映射的值price
是当前域名的价格owner
是当前域名的拥有者--no-message
表示不需要创建message
bank
下我们需要用到的方法,编辑x/nameservice/types/expected_keepers.go
// x/nameservice/types/expected_keepers.go
package types
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
type BankKeeper interface {
SendCoinsFromAccountToModule(ctx sdk.Context, senderAddr sdk.AccAddress, recipientModule string, amt sdk.Coins) error // 需要添加的方法
SendCoins(ctx sdk.Context, fromAddr sdk.AccAddress, toAddr sdk.AccAddress, amt sdk.Coins) error // 需要添加的方法
}
x/nameservice/keeper/msg_server_buy_name.go
文件,实现购买逻辑// x/nameservice/keeper/msg_server_buy_name.go
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"nameservice/x/nameservice/types"
)
func (k msgServer) BuyName(goCtx context.Context, msg *types.MsgBuyName) (*types.MsgBuyNameResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// 从store中获取域名数据
whois, isFound := k.GetWhois(ctx, msg.Name)
// 设置域名购买的初始最低价
minPrice := sdk.Coins{sdk.NewInt64Coin("token", 10)}
// 把价格转换成代币
price, _ := sdk.ParseCoinsNormalized(whois.Price)
bid, _ := sdk.ParseCoinsNormalized(msg.Bid)
// 转换地址
owner, _ := sdk.AccAddressFromBech32(whois.Owner)
buyer, _ := sdk.AccAddressFromBech32(msg.Creator)
// 如果当前域名数据已经存在
if isFound {
// 如果当前价格大于竞拍价格
if price.IsAllGT(bid) {
// 抛出错误
return nil, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "Bid is not high enough")
}
// 如果当前价格小于竞拍价格,把购买者的代币转给域名拥有者
err := k.bankKeeper.SendCoins(ctx, buyer, owner, bid)
if err != nil {
return nil, err
}
} else { // 如果域名不存在
// 如果域名购买最低价大于竞拍价格
if minPrice.IsAllGT(bid) {
// 抛出错误
return nil, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "Bid is less than min amount")
}
// 如果当前价格小于竞拍价格,把购买者的代币转到模块地址
err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, buyer, types.ModuleName, bid)
if err != nil {
return nil, err
}
}
// 更新`whois`的数据
newWhois := types.Whois{
Index: msg.Name,
Name: msg.Name,
Value: whois.Value,
Price: bid.String(),
Owner: buyer.String(),
}
// 储存到store
k.SetWhois(ctx, newWhois)
return &types.MsgBuyNameResponse{}, nil
}
x/nameservice/keeper/msg_server_set_name.go
,实现设置域名映射值的逻辑// x/nameservice/keeper/msg_server_set_name.go
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"nameservice/x/nameservice/types"
)
func (k msgServer) SetName(goCtx context.Context, msg *types.MsgSetName) (*types.MsgSetNameResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// 从store中获取域名数据
whois, _ := k.GetWhois(ctx, msg.Name)
// 如果方法调用者不是域名拥有者,则报错
if !(msg.Creator == whois.Owner) {
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Incorrect Owner")
}
// 更新whois的记录,设置值
newWhois := types.Whois{
Index: msg.Name,
Name: msg.Name,
Value: msg.Value,
Owner: whois.Owner,
Price: whois.Price,
}
// 储存到store
k.SetWhois(ctx, newWhois)
return &types.MsgSetNameResponse{}, nil
}
x/nameservice/keeper/msg_server_delete_name.go
,实现域名删除逻辑// x/nameservice/keeper/msg_server_delete_name.go
package keeper
import (
"context"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"nameservice/x/nameservice/types"
)
func (k msgServer) DeleteName(goCtx context.Context, msg *types.MsgDeleteName) (*types.MsgDeleteNameResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)
// 从store中获取域名数据
whois, isFound := k.GetWhois(ctx, msg.Name)
// 如果找不到域名,则报错
if !isFound {
return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Name doesn't exist")
}
// 如果方法调用者不是域名拥有者,则报错
if !(whois.Owner == msg.Creator) {
return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Incorrect Owner")
}
// 将域名从store中删除
k.RemoveWhois(ctx, msg.Name)
return &types.MsgDeleteNameResponse{}, nil
}
docker exec -it ns ignite chain serve -r
-r
表示重置节点数据 2. 测试购买域名
docker exec -it ns nameserviced tx nameservice buy-name foo 20token --from alice
docker exec -it ns nameserviced q nameservice list-whois
docker exec -it ns nameserviced tx nameservice set-name foo bar --from alice
docker exec -it ns nameserviced tx nameservice delete-name foo --from alice
这篇文章只是告诉大家如何使用Ignite-CLI
更加快速的开发Cosmos
项目,如果想更深入的理解相关代码,请参考以下链接
官方文档:https://docs.ignite.com/guide/nameservice
登链社区文档:https://learnblockchain.cn/docs/cosmos/tutorial/#%E5%BC%80%E5%A7%8B
如果你不会使用 Docker,也可以自己安装本地环境,参考链接:https://tutorials.cosmos.network/hands-on-exercise/1-ignite-cli/1-ignitecli.html