cosmos主網(wǎng)即將上線,對文檔做了大量更新。特地翻譯了一下,方便小伙伴們閱覽, 之后會持續(xù)更新
第三章教程:
Keeper
Cosmos SDK模塊的主要核心是名為Keeper
的部分绅络。它處理同存儲的交互,引用其他的keeper進行跨模塊的交互嘁字,并包含模塊的大部分核心功能恩急。
首先創(chuàng)建文件./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
模塊的函數(shù)。SDK使用對象能力
來訪問應用程序狀態(tài)的各個部分兔魂。這是為了允許開發(fā)人員采用小權限準入原則烤芦,限制錯誤或惡意模塊的去影響其不需要訪問的狀態(tài)的能力。 -
*codec.Codec
: 這是被Amino用于編碼及解碼二進制機構的編碼解碼器的指針析校。 -
sdk.StoreKey
: 通過它來訪問一個持久化保存你的應用程序狀態(tài)的sdk.KVStore
构罗。
-
- 模塊有3個StoreKey:
-
namesStoreKey
- 存儲域名所指向的字符串值的主存儲(即map[name]value
)铜涉。 -
ownerStoreKey
- 保存給定域名的當前所有者(即map[name]sdk_address
)。 -
pricesStoreKey
- 保存給定域名的當前所有者為其支付的價格遂唧。任何人要購買此域名的花費都必須超過當前所有者(即map[name]price
)芙代。
-
Getter和Setter
現(xiàn)在要添加通過Keeper
來與存儲交互的方法了。首先盖彭,添加一個函數(shù)來為指定域名設置解析字符串值:
// 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
的存儲對象。
注意:這個函數(shù)使用
sdk.Context
召边。該對象持有訪問像blockHeight
和chainID
這樣重要部分狀態(tài)的函數(shù)铺呵。
接下來,你可以使用方法.Set([]byte,[]byte)
向存儲中插入<name, value>
鍵值對隧熙。由于存儲只接受[]byte
,想要把string
轉化成[]byte
再把它們作為參數(shù)傳給Set
方法片挂。
接下來,添加一個函數(shù)來解析域名(即查找域名對應的解析值):
// 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
方法症昏。向函數(shù)傳參,傳遞key值父丰,要把name
字符串轉化成[]byte
肝谭,并以[]byte
的形式返回結果。將此轉換成字符串再返回蛾扇。
添加類似的函數(shù)來獲取和設置域名所有者:
// 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
: 沒有自己的字節(jié)編碼器攘烛,這意味著價格需要使用Amino進行序列化和反序列化,以便從存儲中插入或刪除镀首。 - 在獲取所有者暫缺(因此也沒有價格)的域名時坟漱,返回
1mycoin
作為價格。
最后需要在./x/nameservice/keeper.go
文件中加上Keeper
的構造函數(shù):
// 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,
}
}