cosmos主网即将上线,对文档做了大量更新。特地翻译了一下,方便小伙伴们阅览, 之后会持续更新
第三章教程:
Keeper
Cosmos SDK模块的主要核心是名为Keeper
的部分。它处理同存储的交互,引用其他的keeper进行跨模块的交互,并包含模块的大部分核心功能。
首先创建文件./x/nameservice/keeper.go
来保存模块的keeper。在Cosmos SDK应用程序中,模块通常放在./x/
文件夹中。
Keeper结构
开始制作你的SDK模块,请在./x/nameservice/keeper.go
文件中定义nameservice.Keeper
:
package nameservice
import (
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/x/bank"
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Keeper maintains the link to data storage and exposes getter/setter methods for the various parts of the state machine
type Keeper struct {
coinKeeper bank.Keeper
namesStoreKey sdk.StoreKey // Unexposed key to access name store from sdk.Context
ownersStoreKey sdk.StoreKey // Unexposed key to access owners store from sdk.Context
pricesStoreKey sdk.StoreKey // Unexposed key to access prices store from sdk.Context
cdc *codec.Codec // The wire codec for binary encoding/decoding.
}
关于上述代码的几点说明:
- 3个不同的
cosmos-sdk
包被引入: -
Keeper
结构体。在keeper中有几个关键部分:-
bank.Keeper
: 这是bank
模块的Keeper
引用。包括它来允许该模块中的代码调用bank
模块的函数。SDK使用对象能力
来访问应用程序状态的各个部分。这是为了允许开发人员采用小权限准入原则,限制错误或恶意模块的去影响其不需要访问的状态的能力。 -
*codec.Codec
: 这是被Amino用于编码及解码二进制机构的编码解码器的指针。 -
sdk.StoreKey
: 通过它来访问一个持久化保存你的应用程序状态的sdk.KVStore
。
-
- 模块有3个StoreKey:
-
namesStoreKey
- 存储域名所指向的字符串值的主存储(即map[name]value
)。 -
ownerStoreKey
- 保存给定域名的当前所有者(即map[name]sdk_address
)。 -
pricesStoreKey
- 保存给定域名的当前所有者为其支付的价格。任何人要购买此域名的花费都必须超过当前所有者(即map[name]price
)。
-
Getter和Setter
现在要添加通过Keeper
来与存储交互的方法了。首先,添加一个函数来为指定域名设置解析字符串值:
// SetName - sets the value string that a name resolves to
func (k Keeper) SetName(ctx sdk.Context, name string, value string) {
store := ctx.KVStore(k.namesStoreKey)
store.Set([]byte(name), []byte(value))
}
在此方法中,首先使用Keeper
中的namesStoreKey
获取map[name]value
的存储对象。
注意:这个函数使用
sdk.Context
。该对象持有访问像blockHeight
和chainID
这样重要部分状态的函数。
接下来,你可以使用方法.Set([]byte,[]byte)
向存储中插入<name, value>
键值对。由于存储只接受[]byte
,想要把string
转化成[]byte
再把它们作为参数传给Set
方法。
接下来,添加一个函数来解析域名(即查找域名对应的解析值):
// ResolveName - returns the string that the name resolves to
func (k Keeper) ResolveName(ctx sdk.Context, name string) string {
store := ctx.KVStore(k.namesStoreKey)
bz := store.Get([]byte(name))
return string(bz)
}
这里,与SetName
方法一样,首先使用StoreKey
访问存储。接下来,不使用使用.Get([] byte) []byte
方法而不是Set
方法。向函数传参,传递key值,要把name
字符串转化成[]byte
,并以[]byte
的形式返回结果。将此转换成字符串再返回。
添加类似的函数来获取和设置域名所有者:
// HasOwner - returns whether or not the name already has an owner
func (k Keeper) HasOwner(ctx sdk.Context, name string) bool {
store := ctx.KVStore(k.ownersStoreKey)
bz := store.Get([]byte(name))
return bz != nil
}
// GetOwner - get the current owner of a name
func (k Keeper) GetOwner(ctx sdk.Context, name string) sdk.AccAddress {
store := ctx.KVStore(k.ownersStoreKey)
bz := store.Get([]byte(name))
return bz
}
// SetOwner - sets the current owner of a name
func (k Keeper) SetOwner(ctx sdk.Context, name string, owner sdk.AccAddress) {
store := ctx.KVStore(k.ownersStoreKey)
store.Set([]byte(name), owner)
}
注意在上述代码中:
-
sdk.Coins
: 没有自己的字节编码器,这意味着价格需要使用Amino进行序列化和反序列化,以便从存储中插入或删除。 - 在获取所有者暂缺(因此也没有价格)的域名时,返回
1mycoin
作为价格。
最后需要在./x/nameservice/keeper.go
文件中加上Keeper
的构造函数:
// NewKeeper creates new instances of the nameservice Keeper
func NewKeeper(coinKeeper bank.Keeper, namesStoreKey sdk.StoreKey, ownersStoreKey sdk.StoreKey, priceStoreKey sdk.StoreKey, cdc *codec.Codec) Keeper {
return Keeper{
coinKeeper: coinKeeper,
namesStoreKey: namesStoreKey,
ownersStoreKey: ownersStoreKey,
pricesStoreKey: priceStoreKey,
cdc: cdc,
}
}
网友评论