Cosmos 使用 Ignite-Cli 快速開發(fā) NameService 應(yīng)用

概述

這篇文章主要講述使用CosmosIgnite-Cli工具快速開發(fā)NameService應(yīng)用饮焦。NameService的主要功能是用戶可以購(gòu)買域名皇耗,給域名設(shè)置可以解析的地址或則值联喘,域名擁有者可以刪除域名。

環(huán)境安裝

  1. 我們使用 Docker 來(lái)部署環(huán)境,首先編寫 DockerFile 鏡像文件丹喻,命名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
  1. 創(chuàng)建鏡像
docker build -f DockerFile-ubuntu . -t ns_i
  1. 創(chuàng)建 Container
docker create --name ns -i -v $(pwd):/nameservice -w /nameservice -p 1317:1317 -p 4500:4500 -p 5000:5000 -p 26657:26657 ns_i
  1. 啟動(dòng)容器
docker start ns
  1. 檢查環(huán)境
docker exec -it ns ignite version

顯示如下內(nèi)容襟铭,則表示環(huán)境安裝成功碌奉。

Ignite CLI version:     v0.22.1

如果環(huán)境安裝有問(wèn)題,可以私信我?guī)湍憧纯矗?/p>

創(chuàng)建項(xiàng)目

docker exec -it ns ignite scaffold chain nameservice --no-module

這個(gè)命令會(huì)創(chuàng)建一個(gè)nameservice目錄寒砖,已經(jīng)實(shí)現(xiàn)了基于Cosmos SDK的區(qū)塊鏈功能赐劣。
然后我們把代碼移動(dòng)到當(dāng)前的工作目錄

mv nameservice/* ./
rm -rf nameservice

創(chuàng)建Module

docker exec -it ns ignite scaffold module nameservice --dep bank

--dep bank表示該模塊依賴bank模塊

創(chuàng)建Message

根據(jù)我們的業(yè)務(wù)我們需要?jiǎng)?chuàng)建 3 個(gè)Message

  • BuyName(Name, Bid) // 購(gòu)買域名
  • SetName(Name, Value) // 給域名設(shè)置值
  • DeleteName(Name) // 刪除域名
    我們需要執(zhí)行以下命令創(chuàng)建這些Message:
docker exec -it ns ignite scaffold message buy-name name bid

buy-name是方法名,(name, bid)是參數(shù)

docker exec -it ns ignite scaffold message set-name name value

set-name是方法名哩都,(name, value)是參數(shù)

docker exec -it ns ignite scaffold message delete-name name

delete-name是方法名魁兼,(name)是參數(shù)

創(chuàng)建Types

現(xiàn)在我們需要?jiǎng)?chuàng)建一個(gè)儲(chǔ)存的數(shù)據(jù)結(jié)構(gòu)來(lái)記錄當(dāng)前域名的歸屬關(guān)系,我們創(chuàng)建一個(gè)Whois的結(jié)構(gòu)

docker exec -it ns ignite scaffold map whois name value price owner --no-message
  • whois是 type
  • name是域名
  • value是域名映射的值
  • price是當(dāng)前域名的價(jià)格
  • owner是當(dāng)前域名的擁有者
  • --no-message表示不需要?jiǎng)?chuàng)建message

實(shí)現(xiàn)業(yè)務(wù)代碼

  1. 聲明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 // 需要添加的方法
}
  1. 編輯x/nameservice/keeper/msg_server_buy_name.go文件咐汞,實(shí)現(xiàn)購(gòu)買邏輯
// 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中獲取域名數(shù)據(jù)
    whois, isFound := k.GetWhois(ctx, msg.Name)

    // 設(shè)置域名購(gòu)買的初始最低價(jià)
    minPrice := sdk.Coins{sdk.NewInt64Coin("token", 10)}

    // 把價(jià)格轉(zhuǎn)換成代幣
    price, _ := sdk.ParseCoinsNormalized(whois.Price)
    bid, _ := sdk.ParseCoinsNormalized(msg.Bid)

    // 轉(zhuǎn)換地址
    owner, _ := sdk.AccAddressFromBech32(whois.Owner)
    buyer, _ := sdk.AccAddressFromBech32(msg.Creator)

    // 如果當(dāng)前域名數(shù)據(jù)已經(jīng)存在
    if isFound {
        // 如果當(dāng)前價(jià)格大于競(jìng)拍價(jià)格
        if price.IsAllGT(bid) {
            // 拋出錯(cuò)誤
            return nil, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "Bid is not high enough")
        }

        // 如果當(dāng)前價(jià)格小于競(jìng)拍價(jià)格盖呼,把購(gòu)買者的代幣轉(zhuǎn)給域名擁有者
        err := k.bankKeeper.SendCoins(ctx, buyer, owner, bid)
        if err != nil {
            return nil, err
        }
    } else { // 如果域名不存在
        // 如果域名購(gòu)買最低價(jià)大于競(jìng)拍價(jià)格
        if minPrice.IsAllGT(bid) {
            // 拋出錯(cuò)誤
            return nil, sdkerrors.Wrap(sdkerrors.ErrInsufficientFunds, "Bid is less than min amount")
        }

        // 如果當(dāng)前價(jià)格小于競(jìng)拍價(jià)格,把購(gòu)買者的代幣轉(zhuǎn)到模塊地址
        err := k.bankKeeper.SendCoinsFromAccountToModule(ctx, buyer, types.ModuleName, bid)
        if err != nil {
            return nil, err
        }
    }

    // 更新`whois`的數(shù)據(jù)
    newWhois := types.Whois{
        Index: msg.Name,
        Name:  msg.Name,
        Value: whois.Value,
        Price: bid.String(),
        Owner: buyer.String(),
    }

    // 儲(chǔ)存到store
    k.SetWhois(ctx, newWhois)
    return &types.MsgBuyNameResponse{}, nil
}
  1. 編輯x/nameservice/keeper/msg_server_set_name.go化撕,實(shí)現(xiàn)設(shè)置域名映射值的邏輯
// 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中獲取域名數(shù)據(jù)
    whois, _ := k.GetWhois(ctx, msg.Name)

    // 如果方法調(diào)用者不是域名擁有者几晤,則報(bào)錯(cuò)
    if !(msg.Creator == whois.Owner) {
        return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Incorrect Owner")
    }

    // 更新whois的記錄,設(shè)置值
    newWhois := types.Whois{
        Index: msg.Name,
        Name:  msg.Name,
        Value: msg.Value,
        Owner: whois.Owner,
        Price: whois.Price,
    }

    // 儲(chǔ)存到store
    k.SetWhois(ctx, newWhois)
    return &types.MsgSetNameResponse{}, nil
}
  1. 編輯x/nameservice/keeper/msg_server_delete_name.go植阴,實(shí)現(xiàn)域名刪除邏輯
// 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中獲取域名數(shù)據(jù)
    whois, isFound := k.GetWhois(ctx, msg.Name)

    // 如果找不到域名蟹瘾,則報(bào)錯(cuò)
    if !isFound {
        return nil, sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "Name doesn't exist")
    }

    // 如果方法調(diào)用者不是域名擁有者,則報(bào)錯(cuò)
    if !(whois.Owner == msg.Creator) {
        return nil, sdkerrors.Wrap(sdkerrors.ErrUnauthorized, "Incorrect Owner")
    }

    // 將域名從store中刪除
    k.RemoveWhois(ctx, msg.Name)
    return &types.MsgDeleteNameResponse{}, nil
}

測(cè)試

  1. 啟動(dòng)節(jié)點(diǎn)
docker exec -it ns ignite chain serve -r

-r表示重置節(jié)點(diǎn)數(shù)據(jù) 2. 測(cè)試購(gòu)買域名

docker exec -it ns nameserviced tx nameservice buy-name foo 20token --from alice
  1. 查詢域名數(shù)據(jù)
docker exec -it ns nameserviced q nameservice list-whois
  1. 測(cè)試設(shè)置域名值
docker exec -it ns nameserviced tx nameservice set-name foo bar --from alice
  1. 測(cè)試刪除域名
docker exec -it ns nameserviced tx nameservice delete-name foo --from alice

總結(jié)

這篇文章只是告訴大家如何使用Ignite-CLI更加快速的開發(fā)Cosmos項(xiàng)目掠手,如果想更深入的理解相關(guān)代碼憾朴,請(qǐng)參考以下鏈接
官方文檔:https://docs.ignite.com/guide/nameservice
登鏈社區(qū)文檔:https://learnblockchain.cn/docs/cosmos/tutorial/#%E5%BC%80%E5%A7%8B

如果你不會(huì)使用 Docker,也可以自己安裝本地環(huán)境喷鸽,參考鏈接:https://tutorials.cosmos.network/hands-on-exercise/1-ignite-cli/1-ignitecli.html

我是 Victor众雷,Web3 愛(ài)好者!希望幫助更多人進(jìn)入 Web3 的世界做祝!

如果有任何問(wèn)題砾省,請(qǐng)私信我忌栅!

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末棋返,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子却嗡,更是在濱河造成了極大的恐慌纵隔,老刑警劉巖翻诉,帶你破解...
    沈念sama閱讀 222,681評(píng)論 6 517
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異捌刮,居然都是意外死亡碰煌,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 95,205評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門绅作,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)芦圾,“玉大人,你說(shuō)我怎么就攤上這事俄认「錾伲” “怎么了?”我有些...
    開封第一講書人閱讀 169,421評(píng)論 0 362
  • 文/不壞的土叔 我叫張陵眯杏,是天一觀的道長(zhǎng)夜焦。 經(jīng)常有香客問(wèn)我,道長(zhǎng)岂贩,這世上最難降的妖魔是什么茫经? 我笑而不...
    開封第一講書人閱讀 60,114評(píng)論 1 300
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上卸伞,老公的妹妹穿的比我還像新娘抹镊。我一直安慰自己,他們只是感情好荤傲,可當(dāng)我...
    茶點(diǎn)故事閱讀 69,116評(píng)論 6 398
  • 文/花漫 我一把揭開白布垮耳。 她就那樣靜靜地躺著,像睡著了一般弃酌。 火紅的嫁衣襯著肌膚如雪氨菇。 梳的紋絲不亂的頭發(fā)上儡炼,一...
    開封第一講書人閱讀 52,713評(píng)論 1 312
  • 那天妓湘,我揣著相機(jī)與錄音,去河邊找鬼乌询。 笑死榜贴,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的妹田。 我是一名探鬼主播唬党,決...
    沈念sama閱讀 41,170評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼鬼佣!你這毒婦竟也來(lái)了驶拱?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 40,116評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤晶衷,失蹤者是張志新(化名)和其女友劉穎蓝纲,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晌纫,經(jīng)...
    沈念sama閱讀 46,651評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡税迷,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,714評(píng)論 3 342
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锹漱。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箭养。...
    茶點(diǎn)故事閱讀 40,865評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖哥牍,靈堂內(nèi)的尸體忽然破棺而出毕泌,到底是詐尸還是另有隱情,我是刑警寧澤嗅辣,帶...
    沈念sama閱讀 36,527評(píng)論 5 351
  • 正文 年R本政府宣布撼泛,位于F島的核電站,受9級(jí)特大地震影響辩诞,放射性物質(zhì)發(fā)生泄漏坎弯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,211評(píng)論 3 336
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望抠忘。 院中可真熱鬧撩炊,春花似錦、人聲如沸崎脉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,699評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)囚灼。三九已至骆膝,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間灶体,已是汗流浹背阅签。 一陣腳步聲響...
    開封第一講書人閱讀 33,814評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留蝎抽,地道東北人政钟。 一個(gè)月前我還...
    沈念sama閱讀 49,299評(píng)論 3 379
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像樟结,于是被迫代替她去往敵國(guó)和親养交。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,870評(píng)論 2 361

推薦閱讀更多精彩內(nèi)容