Skip to content

Commit

Permalink
v5 Store Migration (#573)
Browse files Browse the repository at this point in the history
Co-authored-by: Hieu Vu <72878483+hieuvubk@users.noreply.github.com>
  • Loading branch information
sampocs and hieuvubk committed Jan 18, 2023
1 parent 39ad5b8 commit f635c1a
Show file tree
Hide file tree
Showing 41 changed files with 9,982 additions and 169 deletions.
12 changes: 12 additions & 0 deletions Makefile
Expand Up @@ -101,6 +101,9 @@ lint:
###############################################################################

test-unit:
@go test -mod=readonly ./x/... ./app/...

test-unit-module:
@go test -mod=readonly ./x/$(module)/...

test-cover:
Expand Down Expand Up @@ -134,6 +137,15 @@ stop-docker:
@pkill -f "tail .*.log" | true
docker-compose -f $(DOCKERNET_COMPOSE_FILE) down

upgrade-init:
PART=1 bash $(DOCKERNET_HOME)/tests/run_tests_upgrade.sh

upgrade-submit:
UPGRADE_HEIGHT=750 bash $(DOCKERNET_HOME)/upgrades/submit_upgrade.sh

upgrade-validate:
PART=2 bash $(DOCKERNET_HOME)/tests/run_tests_upgrade.sh

###############################################################################
### Protobuf ###
###############################################################################
Expand Down
18 changes: 5 additions & 13 deletions app/apptesting/test_helpers.go
Expand Up @@ -318,26 +318,18 @@ func (s *AppTestHelper) MarshalledICS20PacketData() sdk.AccAddress {
return data.GetBytes()
}

func (s *AppTestHelper) ICS20PacketAcknowledgement() channeltypes.Acknowledgement {
// see: https://github.com/cosmos/ibc-go/blob/8de555db76d0320842dacaa32e5500e1fd55e667/modules/apps/transfer/keeper/relay.go#L151
ack := channeltypes.NewResultAcknowledgement(s.MarshalledICS20PacketData())
return ack
}

func (s *AppTestHelper) ConfirmUpgradeSucceededs(upgradeName string, upgradeHeight int64) {
contextBeforeUpgrade := s.Ctx.WithBlockHeight(upgradeHeight - 1)
contextAtUpgrade := s.Ctx.WithBlockHeight(upgradeHeight)

s.Ctx = s.Ctx.WithBlockHeight(upgradeHeight - 1)
plan := upgradetypes.Plan{Name: upgradeName, Height: upgradeHeight}
err := s.App.UpgradeKeeper.ScheduleUpgrade(contextBeforeUpgrade, plan)
err := s.App.UpgradeKeeper.ScheduleUpgrade(s.Ctx, plan)
s.Require().NoError(err)

_, exists := s.App.UpgradeKeeper.GetUpgradePlan(contextBeforeUpgrade)
_, exists := s.App.UpgradeKeeper.GetUpgradePlan(s.Ctx)
s.Require().True(exists)

s.Ctx = s.Ctx.WithBlockHeight(upgradeHeight)
s.Require().NotPanics(func() {
beginBlockRequest := abci.RequestBeginBlock{}
s.App.BeginBlocker(contextAtUpgrade, beginBlockRequest)
s.App.BeginBlocker(s.Ctx, beginBlockRequest)
})
}

Expand Down
15 changes: 14 additions & 1 deletion app/upgrades.go
Expand Up @@ -13,6 +13,9 @@ import (
v4 "github.com/Stride-Labs/stride/v4/app/upgrades/v4"
v5 "github.com/Stride-Labs/stride/v4/app/upgrades/v5"
claimtypes "github.com/Stride-Labs/stride/v4/x/claim/types"
icacallbacktypes "github.com/Stride-Labs/stride/v4/x/icacallbacks/types"
recordtypes "github.com/Stride-Labs/stride/v4/x/records/types"
stakeibctypes "github.com/Stride-Labs/stride/v4/x/stakeibc/types"
)

func (app *StrideApp) setupUpgradeHandlers() {
Expand All @@ -37,7 +40,17 @@ func (app *StrideApp) setupUpgradeHandlers() {
// v5 upgrade handler
app.UpgradeKeeper.SetUpgradeHandler(
v5.UpgradeName,
v5.CreateUpgradeHandler(app.mm, app.configurator, app.InterchainqueryKeeper, app.StakeibcKeeper),
v5.CreateUpgradeHandler(
app.mm,
app.configurator,
app.appCodec,
app.InterchainqueryKeeper,
app.StakeibcKeeper,
app.keys[claimtypes.StoreKey],
app.keys[icacallbacktypes.StoreKey],
app.keys[recordtypes.StoreKey],
app.keys[stakeibctypes.StoreKey],
),
)

upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk()
Expand Down
83 changes: 31 additions & 52 deletions app/upgrades/README.md
Expand Up @@ -84,60 +84,20 @@ func (app *StrideApp) setupUpgradeHandlers() {
```
## Increment the Module's Consensus Version
* The consensus version is different from the chain version - it is specific to each module and is incremented every time state is migrated
```go
// x/{moduleName}/module.go
func (AppModule) ConsensusVersion() uint64 { return 2 }
```
## Specify the Migration in the Upgrade Handler
```go
// app/upgrades/{upgradeVersion}/upgrades.go

// CreateUpgradeHandler creates an SDK upgrade handler for {upgradeVersion}
func CreateUpgradeHandler(
mm *module.Manager,
configurator module.Configurator,
) upgradetypes.UpgradeHandler {
return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
vm[{moduleName}] = 2 // <- ADD THIS
return mm.RunMigrations(ctx, configurator, vm)
}
}
```
## Add Migration Handler
```go
// x/{moduleName}/keeper/migrations.go

package keeper

import (
sdk "github.com/cosmos/cosmos-sdk/types"

{upgradeVersion} "github.com/Stride-Labs/stride/v3/x/records/migrations/{upgradeVersion}"
)

type Migrator struct {
keeper Keeper
}

func NewMigrator(keeper Keeper) Migrator {
return Migrator{keeper: keeper}
}

func (m Migrator) Migrate1to2(ctx sdk.Context) error {
return {upgradeVersion}.MigrateStore(ctx)
}
```
## Define Migration Logic
```go
// x/{moduleName}/migrations/{upgradeVersion}/migrations.go
// x/{moduleName}/migrations/{new-consensus-version}/migrations.go
package {upgradeVersion}

import (
sdk "github.com/cosmos/cosmos-sdk/types"
{oldVersion} "github.com/Stride-Labs/stride/v3/x/records/migrations/{oldVersion}"
{new-consensus-version} "github.com/Stride-Labs/stride/v3/x/records/migrations/{new-consensus-version}"
)

// TODO: Add migration logic to deserialize with old protos and re-serialize with new ones
Expand All @@ -147,16 +107,35 @@ func MigrateStore(ctx sdk.Context) error {
}
```
## Register Migration Handler
## Specify the Migration in the Upgrade Handler
```go
// x/{moduleName}/module.go
...
func (am AppModule) RegisterServices(cfg module.Configurator) {
types.RegisterQueryServer(cfg.QueryServer(), am.keeper)
migrator := keeper.NewMigrator(am.keeper)
// app/upgrades/{upgradeVersion}/upgrades.go

import (
{module}migration "github.com/Stride-Labs/stride/v4/x/{module}/migrations/{new-consensus-version}"
)

if err := cfg.RegisterMigration(types.ModuleName, 1, migrator.Migrate1to2); err != nil {
panic(fmt.Errorf("failed to migrate %s to {upgradeVersion}: %w", types.ModuleName, err))
// CreateUpgradeHandler creates an SDK upgrade handler for {upgradeVersion}
func CreateUpgradeHandler(
mm *module.Manager,
configurator module.Configurator,
cdc codec.Codec,
{module}StoreKey,
) upgradetypes.UpgradeHandler {
return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
if err := {module}migration.MigrateStore(ctx, {module}StoreKey, cdc); err != nil {
return vm, sdkerrors.Wrapf(err, "unable to migrate {module} store")
}
vm[{moduleName}] = mm.GetVersionMap()[{moduleName}]
return mm.RunMigrations(ctx, configurator, vm)
}
}
```
```
## Add Additional Parameters to `CreateUpgradeHandler` Invocation
```go
// app/upgrades.go
...
{upgradeVersion}.CreateUpgradeHandler(app.mm, app.configurator, app.appCodec, app.{module}Keeper),
...
```
40 changes: 7 additions & 33 deletions app/upgrades/v3/upgrades_test.go
@@ -1,7 +1,6 @@
package v3_test

import (
"fmt"
"testing"

"github.com/stretchr/testify/suite"
Expand All @@ -28,39 +27,14 @@ func TestKeeperTestSuite(t *testing.T) {
}

func (suite *UpgradeTestSuite) TestUpgrade() {
testCases := []struct {
msg string
preUpdate func()
update func()
postUpdate func()
expPass bool
}{
{
"Test that upgrade does not panic",
func() {
suite.Setup()
},
func() {
suite.ConfirmUpgradeSucceededs("v3", dummyUpgradeHeight)
suite.Setup()

// make sure claim record was set
afterCtx := suite.Ctx.WithBlockHeight(dummyUpgradeHeight)
for _, identifier := range airdropIdentifiers {
claimRecords := suite.App.ClaimKeeper.GetClaimRecords(afterCtx, identifier)
suite.Require().NotEqual(0, len(claimRecords))
}
},
func() {
},
true,
},
}
suite.ConfirmUpgradeSucceededs("v3", dummyUpgradeHeight)

for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
tc.preUpdate()
tc.update()
tc.postUpdate()
})
// make sure claim record was set
afterCtx := suite.Ctx.WithBlockHeight(dummyUpgradeHeight)
for _, identifier := range airdropIdentifiers {
claimRecords := suite.App.ClaimKeeper.GetClaimRecords(afterCtx, identifier)
suite.Require().NotEqual(0, len(claimRecords))
}
}
31 changes: 2 additions & 29 deletions app/upgrades/v4/upgrades_test.go
@@ -1,7 +1,6 @@
package v4_test

import (
"fmt"
"testing"

"github.com/stretchr/testify/suite"
Expand All @@ -24,32 +23,6 @@ func TestKeeperTestSuite(t *testing.T) {
}

func (suite *UpgradeTestSuite) TestUpgrade() {
testCases := []struct {
msg string
preUpdate func()
update func()
postUpdate func()
expPass bool
}{
{
"Test that upgrade does not panic",
func() {
suite.Setup()
},
func() {
suite.ConfirmUpgradeSucceededs("v4", dummyUpgradeHeight)
},
func() {
},
true,
},
}

for _, tc := range testCases {
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
tc.preUpdate()
tc.update()
tc.postUpdate()
})
}
suite.Setup()
suite.ConfirmUpgradeSucceededs("v4", dummyUpgradeHeight)
}
67 changes: 58 additions & 9 deletions app/upgrades/v5/upgrades.go
@@ -1,41 +1,90 @@
package v4
package v5

import (
"github.com/cosmos/cosmos-sdk/codec"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/types/module"
authz "github.com/cosmos/cosmos-sdk/x/authz"
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"

claimmigration "github.com/Stride-Labs/stride/v4/x/claim/migrations/v2"
claimtypes "github.com/Stride-Labs/stride/v4/x/claim/types"
icacallbacksmigration "github.com/Stride-Labs/stride/v4/x/icacallbacks/migrations/v2"
icacallbacktypes "github.com/Stride-Labs/stride/v4/x/icacallbacks/types"
interchainquerykeeper "github.com/Stride-Labs/stride/v4/x/interchainquery/keeper"
recordsmigration "github.com/Stride-Labs/stride/v4/x/records/migrations/v2"
recordtypes "github.com/Stride-Labs/stride/v4/x/records/types"
stakeibckeeper "github.com/Stride-Labs/stride/v4/x/stakeibc/keeper"
stakeibcmigration "github.com/Stride-Labs/stride/v4/x/stakeibc/migrations/v2"
stakeibctypes "github.com/Stride-Labs/stride/v4/x/stakeibc/types"
)

// Note: ensure these values are properly set before running upgrade
var (
UpgradeName = "v5"

// This query used an old query ID format and got stuck after the format was updated
StaleQueryId = "60b8e09dc7a65938cd6e6e5728b8aa0ca3726ffbe5511946a4f08ced316174ab"
)

// CreateUpgradeHandler creates an SDK upgrade handler for v5
func CreateUpgradeHandler(
mm *module.Manager,
configurator module.Configurator,
cdc codec.Codec,
interchainqueryKeeper interchainquerykeeper.Keeper,
stakeibcKeeper stakeibckeeper.Keeper,
claimStoreKey storetypes.StoreKey,
icacallbackStorekey storetypes.StoreKey,
recordStoreKey storetypes.StoreKey,
stakeibcStoreKey storetypes.StoreKey,
) upgradetypes.UpgradeHandler {
return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) {
// Remove authz from store as it causes an issue with state sync
delete(vm, authz.ModuleName)

// Remove a stale query from the interchainquery store
// This query used an old query ID format and got stuck after the format was updated
staleQueryId := "60b8e09dc7a65938cd6e6e5728b8aa0ca3726ffbe5511946a4f08ced316174ab"
interchainqueryKeeper.DeleteQuery(ctx, staleQueryId)

// Add the SafetyMaxSlashPercent param to the stakeibc param store
stakeibcParams := stakeibcKeeper.GetParams(ctx)
stakeibcParams.SafetyMaxSlashPercent = stakeibctypes.DefaultSafetyMaxSlashPercent
stakeibcKeeper.SetParams(ctx, stakeibcParams)
interchainqueryKeeper.DeleteQuery(ctx, StaleQueryId)

// To add the SafetyMaxSlashPercent param to the stakeibc param store,
// we just re-initialize all the params with their default value
// The alternative would be to migrate the entire paramstore, but since each param is still
// set to it's default value, this is a safer/less error-prone approach
stakeibcKeeper.SetParams(ctx, stakeibctypes.DefaultParams())

// The following modules need state migrations as a result of a change from uints to sdk.Ints
// - claim
// - icacallbacks
// - records
// - stakeibc
if err := claimmigration.MigrateStore(ctx, claimStoreKey, cdc); err != nil {
return vm, sdkerrors.Wrapf(err, "unable to migrate claim store")
}
if err := icacallbacksmigration.MigrateStore(ctx, icacallbackStorekey, cdc); err != nil {
return vm, sdkerrors.Wrapf(err, "unable to migrate icacallbacks store")
}
if err := recordsmigration.MigrateStore(ctx, recordStoreKey, cdc); err != nil {
return vm, sdkerrors.Wrapf(err, "unable to migrate records store")
}
if err := stakeibcmigration.MigrateStore(ctx, stakeibcStoreKey, cdc); err != nil {
return vm, sdkerrors.Wrapf(err, "unable to migrate stakeibc store")
}

// `RunMigrations` (below) checks the old consensus version of each module (found in
// the store) and compares it against the updated consensus version in the binary
// If the old and new consensus versions are not the same, it attempts to call that
// module's migration function that must be registered ahead of time
//
// Since the migrations above were executed directly (instead of being registered
// and invoked through a Migrator), we need to set the module versions in the versionMap
// to the new version, to prevent RunMigrations from attempting to re-run each migrations
currentVersions := mm.GetVersionMap()
vm[claimtypes.ModuleName] = currentVersions[claimtypes.ModuleName]
vm[icacallbacktypes.ModuleName] = currentVersions[icacallbacktypes.ModuleName]
vm[recordtypes.ModuleName] = currentVersions[recordtypes.ModuleName]
vm[stakeibctypes.ModuleName] = currentVersions[stakeibctypes.ModuleName]

return mm.RunMigrations(ctx, configurator, vm)
}
Expand Down

0 comments on commit f635c1a

Please sign in to comment.