diff --git a/x/ccv/consumer/keeper/keeper.go b/x/ccv/consumer/keeper/keeper.go index d24f5fbd39..479bcaf19b 100644 --- a/x/ccv/consumer/keeper/keeper.go +++ b/x/ccv/consumer/keeper/keeper.go @@ -92,6 +92,10 @@ func (k *Keeper) SetStandaloneStakingKeeper(sk ccv.StakingKeeper) { k.standaloneStakingKeeper = sk } +func (k *Keeper) SetParamSpace(ctx sdk.Context, ps paramtypes.Subspace) { + k.paramStore = ps +} + // Validates that the consumer keeper is initialized with non-zero and // non-nil values for all its fields. Otherwise this method will panic. func (k Keeper) mustValidateFields() { diff --git a/x/ccv/consumer/keeper/migration.go b/x/ccv/consumer/keeper/migration.go new file mode 100644 index 0000000000..60c1f9dcfb --- /dev/null +++ b/x/ccv/consumer/keeper/migration.go @@ -0,0 +1,72 @@ +package keeper + +import ( + "time" + + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/x/ccv/types" +) + +// Migrator is a struct for handling in-place store migrations. +type Migrator struct { + ccvConsumerParamSpace paramtypes.Subspace + ccvConsumerKeeper Keeper +} + +// NewMigrator returns a new Migrator. +func NewMigrator(ccvConsumerKeeper Keeper) Migrator { + return Migrator{ccvConsumerKeeper: ccvConsumerKeeper} +} + +func (m Migrator) Migratev1p0To1p3(ctx sdk.Context) error { + // Migrate params + MigrateParamsv1p0To1p3(ctx, m.ccvConsumerParamSpace) + + return nil +} + +// MigrateParamsv1p0To1p3 migrates the consumer CCV module params from v1.0.0 to v1.3.0, +// setting default values for new params. +func MigrateParamsv1p0To1p3(ctx sdk.Context, paramsSubspace paramtypes.Subspace) { + // Get old params + var enabled bool + paramsSubspace.Get(ctx, consumertypes.KeyEnabled, &enabled) + var blocksPerDistributionTransmission int64 + paramsSubspace.Get(ctx, consumertypes.KeyBlocksPerDistributionTransmission, &blocksPerDistributionTransmission) + var distributionTransmissionChannel string + paramsSubspace.Get(ctx, consumertypes.KeyDistributionTransmissionChannel, &distributionTransmissionChannel) + var providerFeePoolAddrStr string + paramsSubspace.Get(ctx, consumertypes.KeyProviderFeePoolAddrStr, &providerFeePoolAddrStr) + var ccvTimeoutPeriod time.Duration + paramsSubspace.Get(ctx, ccvtypes.KeyCCVTimeoutPeriod, &ccvTimeoutPeriod) + var transferTimeoutPeriod time.Duration + paramsSubspace.Get(ctx, consumertypes.KeyTransferTimeoutPeriod, &transferTimeoutPeriod) + var consumerRedistributionFrac string + paramsSubspace.Get(ctx, consumertypes.KeyConsumerRedistributionFrac, &consumerRedistributionFrac) + var historicalEntries int64 + paramsSubspace.Get(ctx, consumertypes.KeyHistoricalEntries, &historicalEntries) + var unbondingPeriod time.Duration + paramsSubspace.Get(ctx, consumertypes.KeyConsumerUnbondingPeriod, &unbondingPeriod) + + // Recycle old params, set new params to default values + defaultParams := consumertypes.DefaultParams() + newParams := consumertypes.NewParams( + enabled, + blocksPerDistributionTransmission, + distributionTransmissionChannel, + providerFeePoolAddrStr, + ccvTimeoutPeriod, + transferTimeoutPeriod, + consumerRedistributionFrac, + historicalEntries, + unbondingPeriod, + defaultParams.SoftOptOutThreshold, + defaultParams.RewardDenoms, + defaultParams.ProviderRewardDenoms, + ) + + // Persist new params + paramsSubspace.SetParamSet(ctx, &newParams) +} diff --git a/x/ccv/consumer/keeper/migration_test.go b/x/ccv/consumer/keeper/migration_test.go new file mode 100644 index 0000000000..542ef5fb80 --- /dev/null +++ b/x/ccv/consumer/keeper/migration_test.go @@ -0,0 +1,94 @@ +package keeper_test + +import ( + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/codec" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + "github.com/cosmos/cosmos-sdk/store" + storetypes "github.com/cosmos/cosmos-sdk/store/types" + sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + consumerkeeper "github.com/cosmos/interchain-security/x/ccv/consumer/keeper" + consumertypes "github.com/cosmos/interchain-security/x/ccv/consumer/types" + ccvtypes "github.com/cosmos/interchain-security/x/ccv/types" + "github.com/stretchr/testify/require" + "github.com/tendermint/tendermint/libs/log" + tmproto "github.com/tendermint/tendermint/proto/tendermint/types" + tmdb "github.com/tendermint/tm-db" +) + +func TestMigrateParamsv1p0To1p3(t *testing.T) { + // Setup raw store + db := tmdb.NewMemDB() + stateStore := store.NewCommitMultiStore(db) + storeKey := sdk.NewKVStoreKey(paramtypes.StoreKey) + memStoreKey := storetypes.NewMemoryStoreKey("mem_key") + stateStore.MountStoreWithDB(storeKey, sdk.StoreTypeIAVL, db) + stateStore.MountStoreWithDB(memStoreKey, sdk.StoreTypeMemory, nil) + require.NoError(t, stateStore.LoadLatestVersion()) + registry := codectypes.NewInterfaceRegistry() + cdc := codec.NewProtoCodec(registry) + ctx := sdk.NewContext(stateStore, tmproto.Header{}, false, log.NewNopLogger()) + require.NoError(t, stateStore.LoadLatestVersion()) + + // Create new empty subspace + subspace := paramtypes.NewSubspace(cdc, + codec.NewLegacyAmino(), + storeKey, + memStoreKey, + paramtypes.ModuleName, + ) + + // Note that new param key table is set in keeper constructor + subspace = subspace.WithKeyTable(consumertypes.ParamKeyTable()) + + // Set 9 params from v1.0.0 + subspace.Set(ctx, consumertypes.KeyEnabled, true) + subspace.Set(ctx, consumertypes.KeyBlocksPerDistributionTransmission, int64(10)) + subspace.Set(ctx, consumertypes.KeyDistributionTransmissionChannel, "channel-0") + subspace.Set(ctx, consumertypes.KeyProviderFeePoolAddrStr, "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz") + subspace.Set(ctx, ccvtypes.KeyCCVTimeoutPeriod, time.Hour) + subspace.Set(ctx, consumertypes.KeyTransferTimeoutPeriod, time.Hour) + subspace.Set(ctx, consumertypes.KeyConsumerRedistributionFrac, "0.5") + subspace.Set(ctx, consumertypes.KeyHistoricalEntries, int64(10)) + subspace.Set(ctx, consumertypes.KeyConsumerUnbondingPeriod, time.Hour) + + // Confirm 3 new params are not set + require.False(t, subspace.Has(ctx, consumertypes.KeySoftOptOutThreshold)) + require.False(t, subspace.Has(ctx, consumertypes.KeyRewardDenoms)) + require.False(t, subspace.Has(ctx, consumertypes.KeyProviderRewardDenoms)) + + // Run migration + consumerkeeper.MigrateParamsv1p0To1p3(ctx, subspace) + + // Use keeper to confirm params are set correctly + keeper := consumerkeeper.Keeper{} + keeper.SetParamSpace(ctx, subspace) + + params := keeper.GetParams(ctx) + require.Equal(t, true, params.Enabled) + require.Equal(t, int64(10), params.BlocksPerDistributionTransmission) + require.Equal(t, "channel-0", params.DistributionTransmissionChannel) + require.Equal(t, "cosmos17p3erf5gv2436fd4vyjwmudakts563a497syuz", params.ProviderFeePoolAddrStr) + require.Equal(t, time.Hour, params.CcvTimeoutPeriod) + require.Equal(t, time.Hour, params.TransferTimeoutPeriod) + require.Equal(t, "0.5", params.ConsumerRedistributionFraction) + require.Equal(t, int64(10), params.HistoricalEntries) + require.Equal(t, time.Hour, params.UnbondingPeriod) + // 3 new params are set to default values + require.Equal(t, "0.05", params.SoftOptOutThreshold) + require.Equal(t, []string(nil), params.RewardDenoms) + require.Equal(t, []string(nil), params.ProviderRewardDenoms) + + // Set new params to other values + params.SoftOptOutThreshold = "0.1" + params.RewardDenoms = []string{"untrn"} + params.ProviderRewardDenoms = []string{"uatom"} + keeper.SetParams(ctx, params) + + require.Equal(t, "0.1", keeper.GetSoftOptOutThreshold(ctx)) + require.Equal(t, []string{"untrn"}, keeper.GetRewardDenoms(ctx)) + require.Equal(t, []string{"uatom"}, keeper.GetProviderRewardDenoms(ctx)) +} diff --git a/x/ccv/consumer/types/params.go b/x/ccv/consumer/types/params.go index 55340b205f..56cb79e524 100644 --- a/x/ccv/consumer/types/params.go +++ b/x/ccv/consumer/types/params.go @@ -87,8 +87,8 @@ func NewParams(enabled bool, blocksPerDistributionTransmission int64, // DefaultParams is the default params for the consumer module func DefaultParams() Params { - var rewardDenoms []string - var provideRewardDenoms []string + rewardDenoms := []string{} + provideRewardDenoms := []string{} return NewParams( false, DefaultBlocksPerDistributionTransmission, @@ -113,10 +113,10 @@ func (p Params) Validate() error { if err := ccvtypes.ValidatePositiveInt64(p.BlocksPerDistributionTransmission); err != nil { return err } - if err := validateDistributionTransmissionChannel(p.DistributionTransmissionChannel); err != nil { + if err := ValidateDistributionTransmissionChannel(p.DistributionTransmissionChannel); err != nil { return err } - if err := validateProviderFeePoolAddrStr(p.ProviderFeePoolAddrStr); err != nil { + if err := ValidateProviderFeePoolAddrStr(p.ProviderFeePoolAddrStr); err != nil { return err } if err := ccvtypes.ValidateDuration(p.CcvTimeoutPeriod); err != nil { @@ -134,13 +134,13 @@ func (p Params) Validate() error { if err := ccvtypes.ValidateDuration(p.UnbondingPeriod); err != nil { return err } - if err := validateSoftOptOutThreshold(p.SoftOptOutThreshold); err != nil { + if err := ValidateSoftOptOutThreshold(p.SoftOptOutThreshold); err != nil { return err } - if err := validateDenoms(p.RewardDenoms); err != nil { + if err := ValidateDenoms(p.RewardDenoms); err != nil { return err } - if err := validateDenoms(p.ProviderRewardDenoms); err != nil { + if err := ValidateDenoms(p.ProviderRewardDenoms); err != nil { return err } return nil @@ -153,9 +153,9 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyBlocksPerDistributionTransmission, p.BlocksPerDistributionTransmission, ccvtypes.ValidatePositiveInt64), paramtypes.NewParamSetPair(KeyDistributionTransmissionChannel, - p.DistributionTransmissionChannel, validateDistributionTransmissionChannel), + p.DistributionTransmissionChannel, ValidateDistributionTransmissionChannel), paramtypes.NewParamSetPair(KeyProviderFeePoolAddrStr, - p.ProviderFeePoolAddrStr, validateProviderFeePoolAddrStr), + p.ProviderFeePoolAddrStr, ValidateProviderFeePoolAddrStr), paramtypes.NewParamSetPair(ccvtypes.KeyCCVTimeoutPeriod, p.CcvTimeoutPeriod, ccvtypes.ValidateDuration), paramtypes.NewParamSetPair(KeyTransferTimeoutPeriod, @@ -167,15 +167,15 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeyConsumerUnbondingPeriod, p.UnbondingPeriod, ccvtypes.ValidateDuration), paramtypes.NewParamSetPair(KeySoftOptOutThreshold, - p.SoftOptOutThreshold, validateSoftOptOutThreshold), + p.SoftOptOutThreshold, ValidateSoftOptOutThreshold), paramtypes.NewParamSetPair(KeyRewardDenoms, - p.RewardDenoms, validateDenoms), + p.RewardDenoms, ValidateDenoms), paramtypes.NewParamSetPair(KeyProviderRewardDenoms, - p.ProviderRewardDenoms, validateDenoms), + p.ProviderRewardDenoms, ValidateDenoms), } } -func validateDistributionTransmissionChannel(i interface{}) error { +func ValidateDistributionTransmissionChannel(i interface{}) error { // Accept empty string as valid, since this will be the default value on genesis if i == "" { return nil @@ -184,7 +184,7 @@ func validateDistributionTransmissionChannel(i interface{}) error { return ccvtypes.ValidateChannelIdentifier(i) } -func validateProviderFeePoolAddrStr(i interface{}) error { +func ValidateProviderFeePoolAddrStr(i interface{}) error { // Accept empty string as valid, since this will be the default value on genesis if i == "" { return nil @@ -193,7 +193,7 @@ func validateProviderFeePoolAddrStr(i interface{}) error { return ccvtypes.ValidateBech32(i) } -func validateSoftOptOutThreshold(i interface{}) error { +func ValidateSoftOptOutThreshold(i interface{}) error { str, ok := i.(string) if !ok { return fmt.Errorf("invalid parameter type: %T", i) @@ -211,7 +211,7 @@ func validateSoftOptOutThreshold(i interface{}) error { return nil } -func validateDenoms(i interface{}) error { +func ValidateDenoms(i interface{}) error { v, ok := i.([]string) if !ok { return fmt.Errorf("invalid parameter type: %T", i)