Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: avoid panic when migrate param for newly added host #6167

Merged
merged 17 commits into from
Apr 22, 2024
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Bug Fixes

* (apps/27-interchain-accounts) [\#6167](https://github.com/cosmos/ibc-go/pull/6167) Avoid panic when migrate param for newly added host.
crodriguezvega marked this conversation as resolved.
Show resolved Hide resolved

damiannolan marked this conversation as resolved.
Show resolved Hide resolved

## [v8.2.0](https://github.com/cosmos/ibc-go/releases/tag/v8.2.0) - 2024-04-05

### Dependencies
Expand Down
17 changes: 13 additions & 4 deletions modules/apps/27-interchain-accounts/host/keeper/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/host/types"
icatypes "github.com/cosmos/ibc-go/v8/modules/apps/27-interchain-accounts/types"
)

// Migrator is a struct for handling in-place state migrations.
Expand All @@ -18,14 +19,22 @@ func NewMigrator(k *Keeper) Migrator {
}
}

// SetLegacySubspace sets the legacy parameter subspace for the Migrator.
func (m Migrator) SetLegacySubspace(legacySubspace icatypes.ParamSubspace) {
m.keeper.legacySubspace = legacySubspace
}

// MigrateParams migrates the host submodule's parameters from the x/params to self store.
func (m Migrator) MigrateParams(ctx sdk.Context) error {
if m.keeper != nil {
var params types.Params
m.keeper.legacySubspace.GetParamSet(ctx, &params)

if err := params.Validate(); err != nil {
return err
if m.keeper.legacySubspace == nil {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to clarify when icahost was added in your upgrade it was created with a nil legacy subspace? @mmsqe

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we bypass param migrate with a mockSubspace, but we could change to nil when generic fix is backported

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, thank you! In that case this should be fine.

I'm curious about a case in which an actual params subspace is created and passed but which does not have any params stored in the param set from a previous version. As genesis would already have been run for the ica module but not setup default params I would imagine it to be empty. I assume in that case params.Validate() should error below, and this would technically misconfiguration by the chain's app wiring.

Copy link
Contributor

@DimitrisJim DimitrisJim Apr 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does it error in that case? 🤔 An empty legacySubspace would init params as {true, []string{}} which shouldn't fail validation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Aha, yea I believe you're right @DimitrisJim. With RegisterParamSet(&Params{}), right?

That's probably fine behaviour imo - given this would probably be the result of misconfig anyways - a param's change would need to be done for allowing msgs in []string then. This is a pretty edge case scenario either way. Most chains deploy host first anyways, and controller later

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wondering if this migration code would be safer and cover edge cases such as described above (this would at least init params with all msgs allowed instead of the empty string slice, its a bit more explicit than relying on a side effect of RegisterParamSet):

if m.keeper != nil {
        params := types.DefaultParams()
	if m.keeper.legacySubspace != nil {
		m.keeper.legacySubspace.GetParamSetIfExists(ctx, &params)
	}

	if err := params.Validate(); err != nil {
		return err
	}

	m.keeper.SetParams(ctx, params)
	m.keeper.Logger(ctx).Info("successfully migrated ica/host submodule to self-manage params")
}

Any thoughts? Happy to stick with the current changes tho if agreed.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reads clearer to me! Would we want to use IfExists variant though? I'd assume we'd want to panic if we try to get something and it doesn't exist.

One sidenote here, should we be doing same sanity checks for controller?

Copy link
Contributor Author

@mmsqe mmsqe Apr 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we want to align IfExists for controller in this PR?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd assume we'd want to panic if we try to get something and it doesn't exist.

I'm not sure, and I don't feel particularly strongly about this - if it doesn't exist we've at least assigned safe defaults via types.DefaultParams rather than panicking. Do you have any feedback here @mmsqe, as someone maintaining a chain?

One sidenote here, should we be doing same sanity checks for controller?

@mmsqe yes I think it would be nice to align the controller migration code as well, thank you! 🙏

params = types.DefaultParams()
} else {
m.keeper.legacySubspace.GetParamSet(ctx, &params)
if err := params.Validate(); err != nil {
return err
}
}
m.keeper.SetParams(ctx, params)
m.keeper.Logger(ctx).Info("successfully migrated ica/host submodule to self-manage params")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,10 @@ import (

func (suite *KeeperTestSuite) TestMigratorMigrateParams() {
testCases := []struct {
msg string
malleate func()
expectedParams icahosttypes.Params
msg string
malleate func()
expectedParams icahosttypes.Params
useDefaultParams bool
}{
{
"success: default params",
Expand All @@ -21,6 +22,13 @@ func (suite *KeeperTestSuite) TestMigratorMigrateParams() {
subspace.SetParamSet(suite.chainA.GetContext(), &params) // set params
},
icahosttypes.DefaultParams(),
false,
},
{
"success: no params",
func() {},
icahosttypes.DefaultParams(),
true,
},
}

Expand All @@ -33,6 +41,9 @@ func (suite *KeeperTestSuite) TestMigratorMigrateParams() {
tc.malleate() // explicitly set params

migrator := icahostkeeper.NewMigrator(&suite.chainA.GetSimApp().ICAHostKeeper)
if tc.useDefaultParams {
migrator.SetLegacySubspace(nil)
}
err := migrator.MigrateParams(suite.chainA.GetContext())
suite.Require().NoError(err)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,7 @@ type PortKeeper interface {
// ParamSubspace defines the expected Subspace interface for module parameters.
type ParamSubspace interface {
GetParamSet(ctx sdk.Context, ps paramtypes.ParamSet)
Has(ctx sdk.Context, key []byte) bool
Get(ctx sdk.Context, key []byte, ptr interface{})
Set(ctx sdk.Context, key []byte, value interface{})
}
Loading