diff --git a/simapp/app.go b/simapp/app.go index 86830256f16b..da06b9edbaf6 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -288,8 +288,11 @@ func NewSimApp( // NOTE: The genutils moodule must occur after staking so that pools are // properly initialized with tokens from genesis accounts. + // NOTE: Capability module must occur first so that it can initialize any capabilities + // so that other modules that want to create or claim capabilities afterwards in InitChain + // can do so safely. app.mm.SetOrderInitGenesis( - auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName, + capability.ModuleName, auth.ModuleName, distr.ModuleName, staking.ModuleName, bank.ModuleName, slashing.ModuleName, gov.ModuleName, mint.ModuleName, crisis.ModuleName, ibc.ModuleName, genutil.ModuleName, evidence.ModuleName, transfer.ModuleName, ) @@ -338,6 +341,8 @@ func NewSimApp( // Initialize and seal the capability keeper so all persistent capabilities // are loaded in-memory and prevent any further modules from creating scoped // sub-keepers. + // This must be done during creation of baseapp rather than in InitChain so + // that in-memory capabilities get regenerated on app restart ctx := app.BaseApp.NewContext(true, abci.Header{}) app.CapabilityKeeper.InitializeAndSeal(ctx) diff --git a/x/capability/keeper/keeper.go b/x/capability/keeper/keeper.go index 47e0b0257e47..48c07ac77678 100644 --- a/x/capability/keeper/keeper.go +++ b/x/capability/keeper/keeper.go @@ -130,6 +130,18 @@ func (k *Keeper) InitializeAndSeal(ctx sdk.Context) { k.sealed = true } +// InitializeIndex sets the index to one in InitChain +// Since it is an exported function, we check that index is indeed unset, before initializing +func (k Keeper) InitializeIndex(ctx sdk.Context) { + // set the global index to start at 1 if it is unset + index := k.GetLatestIndex(ctx) + if index != 0 { + return + } + store := ctx.KVStore(k.storeKey) + store.Set(types.KeyIndex, types.IndexToKey(1)) +} + // GetLatestIndex returns the latest index of the CapabilityKeeper func (k Keeper) GetLatestIndex(ctx sdk.Context) uint64 { store := ctx.KVStore(k.storeKey) diff --git a/x/capability/keeper/keeper_test.go b/x/capability/keeper/keeper_test.go index 6f5214bc03f9..ba3d58d053df 100644 --- a/x/capability/keeper/keeper_test.go +++ b/x/capability/keeper/keeper_test.go @@ -21,6 +21,7 @@ type KeeperTestSuite struct { suite.Suite ctx sdk.Context + app *simapp.SimApp keeper *keeper.Keeper } @@ -32,6 +33,7 @@ func (suite *KeeperTestSuite) SetupTest() { // create new keeper so we can define custom scoping before init and seal keeper := keeper.NewKeeper(cdc, app.GetKey(capability.StoreKey), app.GetMemKey(capability.MemStoreKey)) + suite.app = app suite.ctx = app.BaseApp.NewContext(checkTx, abci.Header{Height: 1}) suite.keeper = keeper } @@ -93,6 +95,16 @@ func (suite *KeeperTestSuite) TestNewCapability() { suite.Require().Nil(cap) } +func (suite *KeeperTestSuite) TestOriginalCapabilityKeeper() { + got, ok := suite.app.ScopedIBCKeeper.GetCapability(suite.ctx, "invalid") + suite.Require().False(ok) + suite.Require().Nil(got) + + port, ok := suite.app.ScopedIBCKeeper.GetCapability(suite.ctx, "ports/transfer") + suite.Require().True(ok) + suite.Require().NotNil(port) +} + func (suite *KeeperTestSuite) TestAuthenticateCapability() { sk1 := suite.keeper.ScopeToModule(bank.ModuleName) sk2 := suite.keeper.ScopeToModule(staking.ModuleName) diff --git a/x/capability/module.go b/x/capability/module.go index 1ee89573c4b4..c2a3fb18ecdc 100644 --- a/x/capability/module.go +++ b/x/capability/module.go @@ -98,7 +98,10 @@ func (am AppModule) RegisterInvariants(_ sdk.InvariantRegistry) {} // InitGenesis performs the capability module's genesis initialization It returns // no validator updates. -func (am AppModule) InitGenesis(_ sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate { +func (am AppModule) InitGenesis(ctx sdk.Context, _ codec.JSONMarshaler, _ json.RawMessage) []abci.ValidatorUpdate { + // Initialize global index to 1 + am.keeper.InitializeIndex(ctx) + return []abci.ValidatorUpdate{} }