diff --git a/CHANGELOG.md b/CHANGELOG.md index 19934bee5..403d420ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -75,6 +75,7 @@ resulted in a panic when the tx execution mode was `CheckTx`. * (x/distribution) [\#5620](https://github.com/cosmos/cosmos-sdk/pull/5620) Fix nil pointer deref in distribution tax/rewward validation helpers. * (genesis) [\#5086](https://github.com/cosmos/cosmos-sdk/issues/5086) Ensure `gentxs` are always an empty array instead of `nil` * (types) [\#5741](https://github.com/cosmos/cosmos-sdk/issues/5741) Prevent ChainAnteDecorators() from panicking when empty AnteDecorator slice is supplied. +* (modules) [\#5569](https://github.com/cosmos/cosmos-sdk/issues/5569) `InitGenesis`, for the relevant modules, now ensures module accounts exist. ### State Machine Breaking diff --git a/simapp/app.go b/simapp/app.go index f6ee16948..e9c32a713 100644 --- a/simapp/app.go +++ b/simapp/app.go @@ -220,12 +220,12 @@ func NewSimApp( // must be passed by reference here. app.mm = module.NewManager( genutil.NewAppModule(app.AccountKeeper, app.StakingKeeper, app.BaseApp.DeliverTx), - auth.NewAppModule(app.AccountKeeper), + auth.NewAppModule(app.AccountKeeper, app.SupplyKeeper), bank.NewAppModule(app.BankKeeper, app.AccountKeeper), crisis.NewAppModule(&app.CrisisKeeper), supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper), gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), - mint.NewAppModule(app.MintKeeper), + mint.NewAppModule(app.MintKeeper, app.SupplyKeeper), slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, app.StakingKeeper), staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), @@ -255,11 +255,11 @@ func NewSimApp( // NOTE: this is not required apps that don't use the simulator for fuzz testing // transactions app.sm = module.NewSimulationManager( - auth.NewAppModule(app.AccountKeeper), + auth.NewAppModule(app.AccountKeeper, app.SupplyKeeper), bank.NewAppModule(app.BankKeeper, app.AccountKeeper), supply.NewAppModule(app.SupplyKeeper, app.BankKeeper, app.AccountKeeper), gov.NewAppModule(app.GovKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), - mint.NewAppModule(app.MintKeeper), + mint.NewAppModule(app.MintKeeper, app.SupplyKeeper), staking.NewAppModule(app.StakingKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper), distr.NewAppModule(app.DistrKeeper, app.AccountKeeper, app.BankKeeper, app.SupplyKeeper, app.StakingKeeper), slashing.NewAppModule(app.SlashingKeeper, app.AccountKeeper, app.BankKeeper, app.StakingKeeper), diff --git a/x/auth/genesis.go b/x/auth/genesis.go index 22db3557d..420bdba09 100644 --- a/x/auth/genesis.go +++ b/x/auth/genesis.go @@ -3,13 +3,14 @@ package auth import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth/exported" + "github.com/cosmos/cosmos-sdk/x/auth/types" ) // InitGenesis - Init store state from genesis data // // CONTRACT: old coins from the FeeCollectionKeeper need to be transferred through // a genesis port script to the new fee collector account -func InitGenesis(ctx sdk.Context, ak AccountKeeper, data GenesisState) { +func InitGenesis(ctx sdk.Context, ak AccountKeeper, sk types.SupplyKeeper, data GenesisState) { ak.SetParams(ctx, data.Params) data.Accounts = SanitizeGenesisAccounts(data.Accounts) @@ -17,6 +18,8 @@ func InitGenesis(ctx sdk.Context, ak AccountKeeper, data GenesisState) { acc := ak.NewAccount(ctx, a) ak.SetAccount(ctx, acc) } + + sk.GetModuleAccount(ctx, FeeCollectorName) } // ExportGenesis returns a GenesisState for a given context and keeper diff --git a/x/auth/module.go b/x/auth/module.go index c5adc5811..910a54a2b 100644 --- a/x/auth/module.go +++ b/x/auth/module.go @@ -77,13 +77,15 @@ type AppModule struct { AppModuleBasic accountKeeper AccountKeeper + supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(accountKeeper AccountKeeper) AppModule { +func NewAppModule(accountKeeper AccountKeeper, supplyKeeper types.SupplyKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, accountKeeper: accountKeeper, + supplyKeeper: supplyKeeper, } } @@ -116,7 +118,7 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.accountKeeper, genesisState) + InitGenesis(ctx, am.accountKeeper, am.supplyKeeper, genesisState) return []abci.ValidatorUpdate{} } diff --git a/x/auth/module_test.go b/x/auth/module_test.go new file mode 100644 index 000000000..b49c407b9 --- /dev/null +++ b/x/auth/module_test.go @@ -0,0 +1,27 @@ +package auth_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, types.Header{}) + + app.InitChain( + types.RequestInitChain{ + AppStateBytes: []byte("{}"), + ChainId: "test-chain-id", + }, + ) + + acc := app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(auth.FeeCollectorName)) + require.NotNil(t, acc) +} diff --git a/x/distribution/module_test.go b/x/distribution/module_test.go new file mode 100644 index 000000000..83bf1b0ef --- /dev/null +++ b/x/distribution/module_test.go @@ -0,0 +1,27 @@ +package distribution_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/x/distribution" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/supply" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/abci/types" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, types.Header{}) + + app.InitChain( + types.RequestInitChain{ + AppStateBytes: []byte("{}"), + ChainId: "test-chain-id", + }, + ) + + acc := app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(distribution.ModuleName)) + require.NotNil(t, acc) +} diff --git a/x/gov/module_test.go b/x/gov/module_test.go new file mode 100644 index 000000000..59794489f --- /dev/null +++ b/x/gov/module_test.go @@ -0,0 +1,29 @@ +package gov_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/x/gov" + + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, types.Header{}) + + app.InitChain( + types.RequestInitChain{ + AppStateBytes: []byte("{}"), + ChainId: "test-chain-id", + }, + ) + + acc := app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(gov.ModuleName)) + require.NotNil(t, acc) +} diff --git a/x/mint/genesis.go b/x/mint/genesis.go index 331852b43..44e0a5ee1 100644 --- a/x/mint/genesis.go +++ b/x/mint/genesis.go @@ -2,12 +2,15 @@ package mint import ( sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/mint/types" ) // InitGenesis new mint genesis -func InitGenesis(ctx sdk.Context, keeper Keeper, data GenesisState) { +func InitGenesis(ctx sdk.Context, keeper Keeper, supplyKeeper types.SupplyKeeper, data GenesisState) { keeper.SetMinter(ctx, data.Minter) keeper.SetParams(ctx, data.Params) + + supplyKeeper.GetModuleAccount(ctx, ModuleName) } // ExportGenesis returns a GenesisState for a given context and keeper. diff --git a/x/mint/module.go b/x/mint/module.go index 53bd8fff1..88c03dfea 100644 --- a/x/mint/module.go +++ b/x/mint/module.go @@ -5,6 +5,8 @@ import ( "fmt" "math/rand" + "github.com/cosmos/cosmos-sdk/x/mint/types" + "github.com/gorilla/mux" "github.com/spf13/cobra" @@ -74,14 +76,16 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { type AppModule struct { AppModuleBasic - keeper Keeper + keeper Keeper + supplyKeeper types.SupplyKeeper } // NewAppModule creates a new AppModule object -func NewAppModule(keeper Keeper) AppModule { +func NewAppModule(keeper Keeper, supplyKeeper types.SupplyKeeper) AppModule { return AppModule{ AppModuleBasic: AppModuleBasic{}, keeper: keeper, + supplyKeeper: supplyKeeper, } } @@ -114,7 +118,9 @@ func (am AppModule) NewQuerierHandler() sdk.Querier { func (am AppModule) InitGenesis(ctx sdk.Context, cdc codec.JSONMarshaler, data json.RawMessage) []abci.ValidatorUpdate { var genesisState GenesisState cdc.MustUnmarshalJSON(data, &genesisState) - InitGenesis(ctx, am.keeper, genesisState) + + InitGenesis(ctx, am.keeper, am.supplyKeeper, genesisState) + return []abci.ValidatorUpdate{} } diff --git a/x/mint/module_test.go b/x/mint/module_test.go new file mode 100644 index 000000000..8b283b032 --- /dev/null +++ b/x/mint/module_test.go @@ -0,0 +1,28 @@ +package mint_test + +import ( + "testing" + + "github.com/stretchr/testify/require" + + "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/mint" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, types.Header{}) + + app.InitChain( + types.RequestInitChain{ + AppStateBytes: []byte("{}"), + ChainId: "test-chain-id", + }, + ) + + acc := app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(mint.ModuleName)) + require.NotNil(t, acc) +} diff --git a/x/mint/types/expected_keepers.go b/x/mint/types/expected_keepers.go index ea2061916..104a28602 100644 --- a/x/mint/types/expected_keepers.go +++ b/x/mint/types/expected_keepers.go @@ -17,6 +17,7 @@ type SupplyKeeper interface { // TODO remove with genesis 2-phases refactor https://github.com/cosmos/cosmos-sdk/issues/2862 SetModuleAccount(sdk.Context, exported.ModuleAccountI) + GetModuleAccount(ctx sdk.Context, moduleName string) exported.ModuleAccountI SendCoinsFromModuleToAccount(ctx sdk.Context, senderModule string, recipientAddr sdk.AccAddress, amt sdk.Coins) error SendCoinsFromModuleToModule(ctx sdk.Context, senderModule, recipientModule string, amt sdk.Coins) error diff --git a/x/staking/module_test.go b/x/staking/module_test.go new file mode 100644 index 000000000..512d96e5a --- /dev/null +++ b/x/staking/module_test.go @@ -0,0 +1,31 @@ +package staking_test + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/x/staking" + + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" + "github.com/cosmos/cosmos-sdk/x/supply" +) + +func TestItCreatesModuleAccountOnInitBlock(t *testing.T) { + app := simapp.Setup(false) + ctx := app.BaseApp.NewContext(false, types.Header{}) + + app.InitChain( + types.RequestInitChain{ + AppStateBytes: []byte("{}"), + ChainId: "test-chain-id", + }, + ) + + acc := app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(staking.BondedPoolName)) + require.NotNil(t, acc) + + acc = app.AccountKeeper.GetAccount(ctx, supply.NewModuleAddress(staking.NotBondedPoolName)) + require.NotNil(t, acc) +} diff --git a/x/supply/keeper/account.go b/x/supply/keeper/account.go index 685308cf6..fdf8f9aff 100644 --- a/x/supply/keeper/account.go +++ b/x/supply/keeper/account.go @@ -49,7 +49,8 @@ func (k Keeper) GetModuleAccountAndPermissions(ctx sdk.Context, moduleName strin return maccI, perms } -// GetModuleAccount gets the module account from the auth account store +// GetModuleAccount gets the module account from the auth account store, if the account does not +// exist in the AccountKeeper, then it is created. func (k Keeper) GetModuleAccount(ctx sdk.Context, moduleName string) exported.ModuleAccountI { acc, _ := k.GetModuleAccountAndPermissions(ctx, moduleName) return acc