【cosmos-sdk-笔记】cosmovisor 简单实现(代码:修改存储结构)

Page content

这一篇整理使用cosmovisor更新时如何修改代码。

1.下载代码

我使用cosmos-sdk简单的写了tvote模块。

git clone https://github.com/taoyuans/mingxie.git

cd mingxie
git checkout main_v1_2

这里有 2 个分支:
main_v1 是升级前的代码(v0.1.0)
main_v1_1 是升级后的代码(v0.1.1)
main_v1_2 是升级后的代码添加逻辑(v0.1.1)

2.项目结构

app
| ... ...
|___app.go  
|___upgrades // => 创建更新目录,后续的更新代码卸载这里
| |___v011   // => 版本号,因为是 v0.1.1 系列版本,所以取名为 011 这个可以随意
|   |___upgrades.go // => 此版本更新逻辑
|   |___constants.go // => 一些使用的常量
|___upgrades.go // => 整体更新逻辑
|... ...

x/tvote
| ... ...
|___keeper 
| |___ ... ...
| |___migrations.go   
|___migrations 
|   |___v2
|     |___migrations.go
|... ...

3.x/tvote/migrations/v2/migrations.go

这里的MigrateStore方法要处理具体的逻辑。
我这里简单的添加了一个字段,计算出来后存储了。

package v011 // migrations.go
import (
 "fmt"
 "mingxie/x/tvote/types"

 "github.com/cosmos/cosmos-sdk/codec"
 storetypes "github.com/cosmos/cosmos-sdk/store/types"
 sdk "github.com/cosmos/cosmos-sdk/types"
 paramtypes "github.com/cosmos/cosmos-sdk/x/params/types"
)

func UpdateParams(ctx sdk.Context, paramStore *paramtypes.Subspace) error {

 // paramStore.Set(ctx, []byte(types.VoterKey), "foobar")

 return nil
}
func MigrateStore(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.BinaryCodec) error {
 store := ctx.KVStore(storeKey)

 return migrateValuesWithPrefix(store, cdc)
}
func migrateValuesWithPrefix(store sdk.KVStore, cdc codec.BinaryCodec) error {
 oldStoreIter := store.Iterator(nil, nil)

 for ; oldStoreIter.Valid(); oldStoreIter.Next() {
  oldKey := oldStoreIter.Key()
  oldVal := store.Get(oldKey)

  newKey, newVal := migrateValue(cdc, oldKey, oldVal)
  store.Set(newKey, newVal)
  // store.Delete(oldKey) // Delete old key, value
 }

 return nil
}
func migrateValue(cdc codec.BinaryCodec, oldKey []byte, oldVal []byte) (newKey []byte, newVal []byte) {
 var newVoter types.Voter
 err := cdc.Unmarshal(oldVal, &newVoter)
 if err != nil {
  fmt.Println(err)
 }

 newVoter.Level = uint32(newVoter.Age - newVoter.Vid)

 newKey = oldKey
 newVal = cdc.MustMarshal(&newVoter)
 return
}

4.tvote/x/keeper/migrations.go

这里主要是控制调用哪个 migration

package keeper // migrations.go
import (
 v2 "mingxie/x/tvote/migrations/v2"

 sdk "github.com/cosmos/cosmos-sdk/types"
)

type Migrator struct {
 keeper Keeper
}

func NewMigrator(keeper Keeper) Migrator {
 return Migrator{keeper: keeper}
}
func (m Migrator) Migrate1to2(ctx sdk.Context) error {
 if err := v2.UpdateParams(ctx, &m.keeper.paramstore); err != nil {
  return err
 }

 return v2.MigrateStore(ctx, m.keeper.storeKey, m.keeper.cdc)
}

5.tvote/x/module.go

最后在 module.go 里注册migration 方法。

// RegisterServices registers a gRPC query service to respond to the module-specific gRPC queries
func (am AppModule) RegisterServices(cfg module.Configurator) {
 migrator := keeper.NewMigrator(am.keeper)
 if err := cfg.RegisterMigration(types.ModuleName, 1, migrator.Migrate1to2); err != nil {
  panic(fmt.Errorf("failed to migrate %s to v011: %w", types.ModuleName, err))
 }

 types.RegisterMsgServer(cfg.MsgServer(), keeper.NewMsgServerImpl(am.keeper))
 types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
}

7.运行

使用 cosmovisor 运行就可以了。


欢迎大家的意见和交流

email: li_mingxie@163.com