forked from shentufoundation/shentu
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement in-place store migration (shentufoundation#334)
* implement in-place store migration * fix consensus versions and add a test * update unit test * lint * remove tx hash from gov votes and add migration * remove tx hash from gov type Deposit * unit test fix * update upgrade name * separate migration logic from app.go * reorder upgrade handler and register legacy types for migration * APP: Fix Auth module MVA in-place migration (shentufoundation#344) * module level migration WIP * add auth migration again after first migration * changelog * Update CHANGELOG.md Co-authored-by: yoongbok-lee <52583590+yoongbok-lee@users.noreply.github.com>
- Loading branch information
1 parent
8efc823
commit d4b4428
Showing
40 changed files
with
3,528 additions
and
872 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,60 @@ | ||
package app | ||
|
||
import ( | ||
"fmt" | ||
storetypes "github.com/cosmos/cosmos-sdk/store/types" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/types/module" | ||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" | ||
"github.com/cosmos/cosmos-sdk/x/authz" | ||
sdkauthz "github.com/cosmos/cosmos-sdk/x/authz" | ||
"github.com/cosmos/cosmos-sdk/x/feegrant" | ||
sdkfeegrant "github.com/cosmos/cosmos-sdk/x/feegrant" | ||
upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" | ||
ibcconnectiontypes "github.com/cosmos/ibc-go/modules/core/03-connection/types" | ||
) | ||
|
||
func (app ShentuApp) setUpgradeHandler(cfg module.Configurator) {} | ||
const upgradeName = "Shentu-v230" | ||
|
||
func (app ShentuApp) setUpgradeHandler() { | ||
app.upgradeKeeper.SetUpgradeHandler( | ||
upgradeName, | ||
func(ctx sdk.Context, _ upgradetypes.Plan, _ module.VersionMap) (module.VersionMap, error) { | ||
app.ibcKeeper.ConnectionKeeper.SetParams(ctx, ibcconnectiontypes.DefaultParams()) | ||
|
||
fromVM := make(map[string]uint64) | ||
for moduleName := range app.mm.Modules { | ||
fromVM[moduleName] = 1 | ||
} | ||
// override versions for _new_ modules as to not skip InitGenesis | ||
fromVM[sdkauthz.ModuleName] = 0 | ||
fromVM[sdkfeegrant.ModuleName] = 0 | ||
|
||
temp, err := app.mm.RunMigrations(ctx, app.configurator, fromVM) | ||
|
||
if err != nil { | ||
return temp, err | ||
} | ||
|
||
authVM := make(map[string]uint64) | ||
authVM[authtypes.ModuleName] = 1 | ||
|
||
_, err = app.mm.RunMigrations(ctx, app.configurator, authVM) | ||
return temp, err | ||
}, | ||
) | ||
|
||
upgradeInfo, err := app.upgradeKeeper.ReadUpgradeInfoFromDisk() | ||
if err != nil { | ||
panic(fmt.Sprintf("failed to read upgrade info from disk %s", err)) | ||
} | ||
|
||
if upgradeInfo.Name == upgradeName && !app.upgradeKeeper.IsSkipHeight(upgradeInfo.Height) { | ||
storeUpgrades := storetypes.StoreUpgrades{ | ||
Added: []string{authz.ModuleName, feegrant.ModuleName}, | ||
} | ||
|
||
// configure store loader that checks if version == upgradeHeight and applies store upgrades | ||
app.SetStoreLoader(upgradetypes.UpgradeStoreLoader(upgradeInfo.Height, &storeUpgrades)) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
package simapp | ||
|
||
import ( | ||
"os" | ||
"testing" | ||
|
||
abci "github.com/tendermint/tendermint/abci/types" | ||
"github.com/tendermint/tendermint/libs/log" | ||
tmproto "github.com/tendermint/tendermint/proto/tendermint/types" | ||
dbm "github.com/tendermint/tm-db" | ||
"github.com/test-go/testify/require" | ||
|
||
"github.com/cosmos/cosmos-sdk/baseapp" | ||
"github.com/cosmos/cosmos-sdk/simapp" | ||
sdk "github.com/cosmos/cosmos-sdk/types" | ||
"github.com/cosmos/cosmos-sdk/types/module" | ||
"github.com/cosmos/cosmos-sdk/x/auth/vesting" | ||
authzmodule "github.com/cosmos/cosmos-sdk/x/authz/module" | ||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types" | ||
"github.com/cosmos/cosmos-sdk/x/capability" | ||
"github.com/cosmos/cosmos-sdk/x/crisis" | ||
"github.com/cosmos/cosmos-sdk/x/evidence" | ||
feegrantmodule "github.com/cosmos/cosmos-sdk/x/feegrant/module" | ||
"github.com/cosmos/cosmos-sdk/x/genutil" | ||
sdkparams "github.com/cosmos/cosmos-sdk/x/params" | ||
"github.com/cosmos/cosmos-sdk/x/upgrade" | ||
"github.com/cosmos/ibc-go/modules/apps/transfer" | ||
|
||
"github.com/certikfoundation/shentu/v2/x/auth" | ||
"github.com/certikfoundation/shentu/v2/x/cert" | ||
"github.com/certikfoundation/shentu/v2/x/cvm" | ||
"github.com/certikfoundation/shentu/v2/x/distribution" | ||
"github.com/certikfoundation/shentu/v2/x/gov" | ||
"github.com/certikfoundation/shentu/v2/x/mint" | ||
"github.com/certikfoundation/shentu/v2/x/oracle" | ||
"github.com/certikfoundation/shentu/v2/x/shield" | ||
"github.com/certikfoundation/shentu/v2/x/slashing" | ||
"github.com/certikfoundation/shentu/v2/x/staking" | ||
) | ||
|
||
func TestRunMigrations(t *testing.T) { | ||
db := dbm.NewMemDB() | ||
encCfg := MakeTestEncodingConfig() | ||
logger := log.NewTMLogger(log.NewSyncWriter(os.Stdout)) | ||
app := NewSimApp(logger, db, nil, true, map[int64]bool{}, DefaultNodeHome, 0, encCfg, simapp.EmptyAppOptions{}) | ||
|
||
// Create a new baseapp and configurator for the purpose of this test. | ||
bApp := baseapp.NewBaseApp(appName, logger, db, encCfg.TxConfig.TxDecoder()) | ||
bApp.SetCommitMultiStoreTracer(nil) | ||
bApp.SetInterfaceRegistry(encCfg.InterfaceRegistry) | ||
app.BaseApp = bApp | ||
app.configurator = module.NewConfigurator(app.appCodec, app.MsgServiceRouter(), app.GRPCQueryRouter()) | ||
|
||
// We register all modules on the Configurator, except x/bank. x/bank will | ||
// serve as the test subject on which we run the migration tests. | ||
// | ||
// The loop below is the same as calling `RegisterServices` on | ||
// ModuleManager, except that we skip x/bank. | ||
for _, module := range app.mm.Modules { | ||
if module.Name() == banktypes.ModuleName { | ||
continue | ||
} | ||
|
||
module.RegisterServices(app.configurator) | ||
} | ||
|
||
// Initialize the chain | ||
app.InitChain(abci.RequestInitChain{}) | ||
app.Commit() | ||
|
||
testCases := []struct { | ||
name string | ||
moduleName string | ||
forVersion uint64 | ||
expRegErr bool // errors while registering migration | ||
expRegErrMsg string | ||
expRunErr bool // errors while running migration | ||
expRunErrMsg string | ||
expCalled int | ||
}{ | ||
{ | ||
"cannot register migration for version 0", | ||
"bank", 0, | ||
true, "module migration versions should start at 1: invalid version", false, "", 0, | ||
}, | ||
{ | ||
"throws error on RunMigrations if no migration registered for bank", | ||
"", 1, | ||
false, "", true, "no migrations found for module bank: not found", 0, | ||
}, | ||
{ | ||
"can register and run migration handler for x/bank", | ||
"bank", 1, | ||
false, "", false, "", 1, | ||
}, | ||
{ | ||
"cannot register migration handler for same module & forVersion", | ||
"bank", 1, | ||
true, "another migration for module bank and version 1 already exists: internal logic error", false, "", 0, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
var err error | ||
|
||
// Since it's very hard to test actual in-place store migrations in | ||
// tests (due to the difficulty of maintaining multiple versions of a | ||
// module), we're just testing here that the migration logic is | ||
// called. | ||
called := 0 | ||
|
||
if tc.moduleName != "" { | ||
// Register migration for module from version `forVersion` to `forVersion+1`. | ||
err = app.configurator.RegisterMigration(tc.moduleName, tc.forVersion, func(sdk.Context) error { | ||
called++ | ||
|
||
return nil | ||
}) | ||
|
||
if tc.expRegErr { | ||
require.EqualError(t, err, tc.expRegErrMsg) | ||
|
||
return | ||
} | ||
} | ||
require.NoError(t, err) | ||
|
||
// Run migrations only for bank. That's why we put the initial | ||
// version for bank as 1, and for all other modules, we put as | ||
// their latest ConsensusVersion. | ||
_, err = app.mm.RunMigrations( | ||
app.NewContext(true, tmproto.Header{Height: app.LastBlockHeight()}), app.configurator, | ||
module.VersionMap{ | ||
"bank": 1, | ||
"cert": cert.AppModule{}.ConsensusVersion(), | ||
"cvm": cvm.AppModule{}.ConsensusVersion(), | ||
"oracle": oracle.AppModule{}.ConsensusVersion(), | ||
"shield": shield.AppModule{}.ConsensusVersion(), | ||
"auth": auth.AppModule{}.ConsensusVersion(), | ||
"authz": authzmodule.AppModule{}.ConsensusVersion(), | ||
"staking": staking.AppModule{}.ConsensusVersion(), | ||
"mint": mint.AppModule{}.ConsensusVersion(), | ||
"distribution": distribution.AppModule{}.ConsensusVersion(), | ||
"slashing": slashing.AppModule{}.ConsensusVersion(), | ||
"gov": gov.AppModule{}.ConsensusVersion(), | ||
"params": sdkparams.AppModule{}.ConsensusVersion(), | ||
"upgrade": upgrade.AppModule{}.ConsensusVersion(), | ||
"vesting": vesting.AppModule{}.ConsensusVersion(), | ||
"feegrant": feegrantmodule.AppModule{}.ConsensusVersion(), | ||
"evidence": evidence.AppModule{}.ConsensusVersion(), | ||
"crisis": crisis.AppModule{}.ConsensusVersion(), | ||
"genutil": genutil.AppModule{}.ConsensusVersion(), | ||
"capability": capability.AppModule{}.ConsensusVersion(), | ||
"transfer": transfer.AppModule{}.ConsensusVersion(), | ||
}, | ||
) | ||
if tc.expRunErr { | ||
require.EqualError(t, err, tc.expRunErrMsg) | ||
} else { | ||
require.NoError(t, err) | ||
// Make sure bank's migration is called. | ||
require.Equal(t, tc.expCalled, called) | ||
} | ||
}) | ||
} | ||
} |
Oops, something went wrong.