From e27213e35405733dacad9af6495b9ef2da879ef4 Mon Sep 17 00:00:00 2001 From: Hanjun Kim Date: Mon, 9 Dec 2024 09:14:39 +0800 Subject: [PATCH] feat: add v3 upgrade handler (#214) ## Description This PR adds v3 software upgrade handler which does the following: - Remove invalid IBC denoms from the various modules' parameters (x/operators, x/services, x/restaking) - Update the x/liquidvesting params to remove the trusted delegates following #215. - Update the jail duration time to be increased from 10 minutes to 1 hour (600s). Closes: MILK-158 --- ### Author Checklist *All items are required. Please add a note to the item if the item is not applicable and please add links to any relevant follow up issues.* I have... - [ ] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] added `!` to the type prefix if API or client breaking change - [ ] targeted the correct branch (see [PR Targeting](https://github.com/milkyway-labs/milkyway/blob/master/CONTRIBUTING.md#pr-targeting)) - [ ] provided a link to the relevant issue or specification - [ ] followed the guidelines for [building modules](https://docs.cosmos.network/v0.44/building-modules/intro.html) - [ ] included the necessary unit and integration [tests](https://github.com/milkyway-labs/milkyway/blob/master/CONTRIBUTING.md#testing) - [ ] added a changelog entry to `CHANGELOG.md` - [ ] included comments for [documenting Go code](https://blog.golang.org/godoc) - [ ] updated the relevant documentation or specification - [ ] reviewed "Files changed" and left comments if necessary - [ ] confirmed all CI checks have passed ### Reviewers Checklist *All items are required. Please add a note if the item is not applicable and please add your handle next to the items reviewed if you only reviewed selected items.* I have... - [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title - [ ] confirmed `!` in the type prefix if API or client breaking change - [ ] confirmed all author checklist items have been addressed - [ ] reviewed state machine logic - [ ] reviewed API design and naming - [ ] reviewed documentation is accurate - [ ] reviewed tests and test coverage - [ ] manually tested (if applicable) --------- Co-authored-by: Manuel <6245917+manu0466@users.noreply.github.com> --- ...a1c693ce56479f5540732dc0beeb6a42ffb2f.yaml | 6 + app/app.go | 5 +- app/upgrades/v3/constants.go | 18 +++ app/upgrades/v3/upgrades.go | 123 +++++++++++++++ app/upgrades/v3/upgrades_test.go | 144 ++++++++++++++++++ x/liquidvesting/types/params.go | 2 +- x/rewards/keeper/params.go | 27 ++++ 7 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 .changeset/entries/9b11f5b2d332b3d204834d1325da1c693ce56479f5540732dc0beeb6a42ffb2f.yaml create mode 100644 app/upgrades/v3/constants.go create mode 100644 app/upgrades/v3/upgrades.go create mode 100644 app/upgrades/v3/upgrades_test.go create mode 100644 x/rewards/keeper/params.go diff --git a/.changeset/entries/9b11f5b2d332b3d204834d1325da1c693ce56479f5540732dc0beeb6a42ffb2f.yaml b/.changeset/entries/9b11f5b2d332b3d204834d1325da1c693ce56479f5540732dc0beeb6a42ffb2f.yaml new file mode 100644 index 00000000..342d6866 --- /dev/null +++ b/.changeset/entries/9b11f5b2d332b3d204834d1325da1c693ce56479f5540732dc0beeb6a42ffb2f.yaml @@ -0,0 +1,6 @@ +type: feat +module: none +pull_request: 214 +description: Implement v3 upgrade handler +backward_compatible: true +date: 2024-12-06T09:24:52.695953Z diff --git a/app/app.go b/app/app.go index afec56aa..4281d5c6 100644 --- a/app/app.go +++ b/app/app.go @@ -68,6 +68,7 @@ import ( milkywayabci "github.com/milkyway-labs/milkyway/v3/app/abci" "github.com/milkyway-labs/milkyway/v3/app/keepers" "github.com/milkyway-labs/milkyway/v3/app/upgrades" + v3 "github.com/milkyway-labs/milkyway/v3/app/upgrades/v3" _ "github.com/milkyway-labs/milkyway/v3/client/docs/statik" liquidvestingtypes "github.com/milkyway-labs/milkyway/v3/x/liquidvesting/types" ) @@ -76,7 +77,9 @@ var ( // DefaultNodeHome default home directories for the application daemon DefaultNodeHome string - Upgrades []upgrades.Upgrade + Upgrades = []upgrades.Upgrade{ + v3.Upgrade, + } ) var ( diff --git a/app/upgrades/v3/constants.go b/app/upgrades/v3/constants.go new file mode 100644 index 00000000..c9154ca3 --- /dev/null +++ b/app/upgrades/v3/constants.go @@ -0,0 +1,18 @@ +package v3 + +import ( + storetypes "cosmossdk.io/store/types" + + "github.com/milkyway-labs/milkyway/v3/app/upgrades" +) + +const UpgradeName = "v3" + +var Upgrade = upgrades.Upgrade{ + UpgradeName: UpgradeName, + CreateUpgradeHandler: CreateUpgradeHandler, + StoreUpgrades: storetypes.StoreUpgrades{ + Added: []string{}, + Deleted: []string{}, + }, +} diff --git a/app/upgrades/v3/upgrades.go b/app/upgrades/v3/upgrades.go new file mode 100644 index 00000000..0aa0f83b --- /dev/null +++ b/app/upgrades/v3/upgrades.go @@ -0,0 +1,123 @@ +package v3 + +import ( + "context" + "slices" + "time" + + upgradetypes "cosmossdk.io/x/upgrade/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + + "github.com/milkyway-labs/milkyway/v3/app/keepers" + "github.com/milkyway-labs/milkyway/v3/utils" + operatorskeeper "github.com/milkyway-labs/milkyway/v3/x/operators/keeper" + restakingkeeper "github.com/milkyway-labs/milkyway/v3/x/restaking/keeper" + rewardskeeper "github.com/milkyway-labs/milkyway/v3/x/rewards/keeper" + serviceskeeper "github.com/milkyway-labs/milkyway/v3/x/services/keeper" +) + +func CreateUpgradeHandler( + mm *module.Manager, + configuration module.Configurator, + keepers *keepers.AppKeepers, +) upgradetypes.UpgradeHandler { + return func(ctx context.Context, plan upgradetypes.Plan, fromVM module.VersionMap) (module.VersionMap, error) { + vm, err := mm.RunMigrations(ctx, configuration, fromVM) + if err != nil { + return nil, err + } + + denomsToRemove := []string{ + "ibc/9ACD338BC3B488E0F50A54DE9A844C8326AF0739D917922A9CE04D42AD66017E", // miscalculated TIA + "ibc/84FBEC4BBB48BD7CC534ED7518F339CCF6C45529DC00C7BFB8605C9EE7D68AFC", // miscalculated stTIA + } + + err = removeDenomsFromOperatorsModule(ctx, keepers.OperatorsKeeper, denomsToRemove) + if err != nil { + return nil, err + } + + err = removeDenomsFromServicesModule(ctx, keepers.ServicesKeeper, denomsToRemove) + if err != nil { + return nil, err + } + + err = removeDenomsFromRestakingModule(ctx, keepers.RestakingKeeper, denomsToRemove) + if err != nil { + return nil, err + } + + err = removeDenomsFromRewardsModule(ctx, keepers.RewardsKeeper, denomsToRemove) + if err != nil { + return nil, err + } + + // Set trusted delegate for liquid vesting module. + liquidVestingParams, err := keepers.LiquidVestingKeeper.GetParams(ctx) + if err != nil { + return nil, err + } + err = keepers.LiquidVestingKeeper.SetParams(ctx, liquidVestingParams) + if err != nil { + return nil, err + } + + // Increase downtime jail duration from 1 minute to 1 hour. + slashingParams, err := keepers.SlashingKeeper.GetParams(ctx) + if err != nil { + return nil, err + } + slashingParams.DowntimeJailDuration = time.Hour + err = keepers.SlashingKeeper.SetParams(ctx, slashingParams) + if err != nil { + return nil, err + } + + return vm, nil + } +} + +func removeDenomsFromOperatorsModule(ctx context.Context, ok *operatorskeeper.Keeper, denomsToRemove []string) error { + params, err := ok.GetParams(ctx) + if err != nil { + return err + } + params.OperatorRegistrationFee = utils.Filter(params.OperatorRegistrationFee, func(coin sdk.Coin) bool { + return !slices.Contains(denomsToRemove, coin.Denom) + }) + return ok.SetParams(ctx, params) +} + +func removeDenomsFromServicesModule(ctx context.Context, sk *serviceskeeper.Keeper, denomsToRemove []string) error { + params, err := sk.GetParams(ctx) + if err != nil { + return err + } + params.ServiceRegistrationFee = utils.Filter(params.ServiceRegistrationFee, func(coin sdk.Coin) bool { + return !slices.Contains(denomsToRemove, coin.Denom) + }) + return sk.SetParams(ctx, params) +} + +func removeDenomsFromRestakingModule(ctx context.Context, rk *restakingkeeper.Keeper, denomsToRemove []string) error { + params, err := rk.GetParams(ctx) + if err != nil { + return err + } + params.AllowedDenoms = utils.Filter(params.AllowedDenoms, func(denom string) bool { + return !slices.Contains(denomsToRemove, denom) + }) + return rk.SetParams(ctx, params) +} + +func removeDenomsFromRewardsModule(ctx context.Context, rk *rewardskeeper.Keeper, denomsToRemove []string) error { + params, err := rk.GetParams(ctx) + if err != nil { + return err + } + params.RewardsPlanCreationFee = utils.Filter(params.RewardsPlanCreationFee, func(coin sdk.Coin) bool { + return !slices.Contains(denomsToRemove, coin.Denom) + }) + return rk.SetParams(ctx, params) +} diff --git a/app/upgrades/v3/upgrades_test.go b/app/upgrades/v3/upgrades_test.go new file mode 100644 index 00000000..0eff0d4c --- /dev/null +++ b/app/upgrades/v3/upgrades_test.go @@ -0,0 +1,144 @@ +package v3_test + +import ( + "testing" + "time" + + "cosmossdk.io/core/appmodule" + "cosmossdk.io/core/header" + "cosmossdk.io/x/upgrade" + upgradetypes "cosmossdk.io/x/upgrade/types" + tmproto "github.com/cometbft/cometbft/proto/tendermint/types" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/stretchr/testify/suite" + + milkywayapp "github.com/milkyway-labs/milkyway/v3/app" + "github.com/milkyway-labs/milkyway/v3/app/helpers" + v3 "github.com/milkyway-labs/milkyway/v3/app/upgrades/v3" +) + +func TestUpgradeTestSuite(t *testing.T) { + suite.Run(t, new(UpgradeTestSuite)) +} + +type UpgradeTestSuite struct { + suite.Suite + + App *milkywayapp.MilkyWayApp + Ctx sdk.Context + UpgradeModule appmodule.HasPreBlocker +} + +func (suite *UpgradeTestSuite) SetupTest() { + suite.App = helpers.Setup(suite.T()) + suite.Ctx = suite.App.NewUncachedContext(true, tmproto.Header{}) + suite.Ctx = suite.Ctx.WithHeaderInfo(header.Info{Height: 1}) + suite.UpgradeModule = upgrade.NewAppModule(suite.App.UpgradeKeeper, suite.App.AccountKeeper.AddressCodec()) +} + +func (suite *UpgradeTestSuite) TestUpgradeV3() { + operatorsParams, err := suite.App.OperatorsKeeper.GetParams(suite.Ctx) + suite.Require().NoError(err) + operatorsParams.OperatorRegistrationFee = sdk.NewCoins( + sdk.NewInt64Coin("ibc/16065EE5282C5217685C8F084FC44864C25C706AC37356B0D62811D50B96920F", 1000000), + sdk.NewInt64Coin("ibc/6C349F0EB135C5FA99301758F35B87DB88403D690E5E314AB080401FEE4066E5", 1000000), + sdk.NewInt64Coin("ibc/84FBEC4BBB48BD7CC534ED7518F339CCF6C45529DC00C7BFB8605C9EE7D68AFC", 1000000), + sdk.NewInt64Coin("ibc/8D4FC51F696E03711B9B37A5787FB89BD2DDBAF788813478B002D552A12F9157", 1000000), + sdk.NewInt64Coin("ibc/9ACD338BC3B488E0F50A54DE9A844C8326AF0739D917922A9CE04D42AD66017E", 1000000), + ) + err = suite.App.OperatorsKeeper.SetParams(suite.Ctx, operatorsParams) + suite.Require().NoError(err) + + servicesParams, err := suite.App.ServicesKeeper.GetParams(suite.Ctx) + suite.Require().NoError(err) + servicesParams.ServiceRegistrationFee = sdk.NewCoins( + sdk.NewInt64Coin("ibc/16065EE5282C5217685C8F084FC44864C25C706AC37356B0D62811D50B96920F", 1000000), + sdk.NewInt64Coin("ibc/6C349F0EB135C5FA99301758F35B87DB88403D690E5E314AB080401FEE4066E5", 1000000), + sdk.NewInt64Coin("ibc/84FBEC4BBB48BD7CC534ED7518F339CCF6C45529DC00C7BFB8605C9EE7D68AFC", 1000000), + sdk.NewInt64Coin("ibc/8D4FC51F696E03711B9B37A5787FB89BD2DDBAF788813478B002D552A12F9157", 1000000), + sdk.NewInt64Coin("ibc/9ACD338BC3B488E0F50A54DE9A844C8326AF0739D917922A9CE04D42AD66017E", 1000000), + ) + err = suite.App.ServicesKeeper.SetParams(suite.Ctx, servicesParams) + suite.Require().NoError(err) + + restakingParams, err := suite.App.RestakingKeeper.GetParams(suite.Ctx) + suite.Require().NoError(err) + restakingParams.AllowedDenoms = []string{ + "ibc/16065EE5282C5217685C8F084FC44864C25C706AC37356B0D62811D50B96920F", + "ibc/6C349F0EB135C5FA99301758F35B87DB88403D690E5E314AB080401FEE4066E5", + "ibc/84FBEC4BBB48BD7CC534ED7518F339CCF6C45529DC00C7BFB8605C9EE7D68AFC", + "ibc/8D4FC51F696E03711B9B37A5787FB89BD2DDBAF788813478B002D552A12F9157", + "ibc/9ACD338BC3B488E0F50A54DE9A844C8326AF0739D917922A9CE04D42AD66017E", + "locked/ibc/F1183DB3D428313A6FD329DF18219F9D6B83257D07D292EA9EC1D877E89EC2B0", + } + err = suite.App.RestakingKeeper.SetParams(suite.Ctx, restakingParams) + suite.Require().NoError(err) + + rewardsParams, err := suite.App.RewardsKeeper.GetParams(suite.Ctx) + suite.Require().NoError(err) + rewardsParams.RewardsPlanCreationFee = sdk.NewCoins( + sdk.NewInt64Coin("ibc/16065EE5282C5217685C8F084FC44864C25C706AC37356B0D62811D50B96920F", 1000000), + sdk.NewInt64Coin("ibc/6C349F0EB135C5FA99301758F35B87DB88403D690E5E314AB080401FEE4066E5", 1000000), + sdk.NewInt64Coin("ibc/84FBEC4BBB48BD7CC534ED7518F339CCF6C45529DC00C7BFB8605C9EE7D68AFC", 1000000), + sdk.NewInt64Coin("ibc/8D4FC51F696E03711B9B37A5787FB89BD2DDBAF788813478B002D552A12F9157", 1000000), + sdk.NewInt64Coin("ibc/9ACD338BC3B488E0F50A54DE9A844C8326AF0739D917922A9CE04D42AD66017E", 1000000), + ) + err = suite.App.RewardsKeeper.SetParams(suite.Ctx, rewardsParams) + suite.Require().NoError(err) + + suite.performUpgrade() + + operatorsParams, err = suite.App.OperatorsKeeper.GetParams(suite.Ctx) + suite.Require().NoError(err) + suite.Require().Equal(sdk.NewCoins( + sdk.NewInt64Coin("ibc/16065EE5282C5217685C8F084FC44864C25C706AC37356B0D62811D50B96920F", 1000000), + sdk.NewInt64Coin("ibc/6C349F0EB135C5FA99301758F35B87DB88403D690E5E314AB080401FEE4066E5", 1000000), + sdk.NewInt64Coin("ibc/8D4FC51F696E03711B9B37A5787FB89BD2DDBAF788813478B002D552A12F9157", 1000000), + ), operatorsParams.OperatorRegistrationFee) + + servicesParams, err = suite.App.ServicesKeeper.GetParams(suite.Ctx) + suite.Require().NoError(err) + suite.Require().Equal(sdk.NewCoins( + sdk.NewInt64Coin("ibc/16065EE5282C5217685C8F084FC44864C25C706AC37356B0D62811D50B96920F", 1000000), + sdk.NewInt64Coin("ibc/6C349F0EB135C5FA99301758F35B87DB88403D690E5E314AB080401FEE4066E5", 1000000), + sdk.NewInt64Coin("ibc/8D4FC51F696E03711B9B37A5787FB89BD2DDBAF788813478B002D552A12F9157", 1000000), + ), servicesParams.ServiceRegistrationFee) + + restakingParams, err = suite.App.RestakingKeeper.GetParams(suite.Ctx) + suite.Require().NoError(err) + suite.Require().Equal([]string{ + "ibc/16065EE5282C5217685C8F084FC44864C25C706AC37356B0D62811D50B96920F", + "ibc/6C349F0EB135C5FA99301758F35B87DB88403D690E5E314AB080401FEE4066E5", + "ibc/8D4FC51F696E03711B9B37A5787FB89BD2DDBAF788813478B002D552A12F9157", + "locked/ibc/F1183DB3D428313A6FD329DF18219F9D6B83257D07D292EA9EC1D877E89EC2B0", + }, restakingParams.AllowedDenoms) + + rewardsParams, err = suite.App.RewardsKeeper.GetParams(suite.Ctx) + suite.Require().NoError(err) + suite.Require().Equal(sdk.NewCoins( + sdk.NewInt64Coin("ibc/16065EE5282C5217685C8F084FC44864C25C706AC37356B0D62811D50B96920F", 1000000), + sdk.NewInt64Coin("ibc/6C349F0EB135C5FA99301758F35B87DB88403D690E5E314AB080401FEE4066E5", 1000000), + sdk.NewInt64Coin("ibc/8D4FC51F696E03711B9B37A5787FB89BD2DDBAF788813478B002D552A12F9157", 1000000), + ), rewardsParams.RewardsPlanCreationFee) + + _, err = suite.App.LiquidVestingKeeper.GetParams(suite.Ctx) + suite.Require().NoError(err) + + slashingParams, err := suite.App.SlashingKeeper.GetParams(suite.Ctx) + suite.Require().NoError(err) + suite.Require().Equal(time.Hour, slashingParams.DowntimeJailDuration) +} + +func (suite *UpgradeTestSuite) performUpgrade() { + upgradeHeight := suite.Ctx.HeaderInfo().Height + 1 + plan := upgradetypes.Plan{Name: v3.UpgradeName, Height: upgradeHeight} + err := suite.App.UpgradeKeeper.ScheduleUpgrade(suite.Ctx, plan) + suite.Require().NoError(err) + _, err = suite.App.UpgradeKeeper.GetUpgradePlan(suite.Ctx) + suite.Require().NoError(err) + + suite.Ctx = suite.Ctx.WithHeaderInfo(header.Info{Height: upgradeHeight}) + // PreBlocker triggers the upgrade + _, err = suite.UpgradeModule.PreBlock(suite.Ctx) + suite.Require().NoError(err) +} diff --git a/x/liquidvesting/types/params.go b/x/liquidvesting/types/params.go index 8c37eff3..17c40d44 100644 --- a/x/liquidvesting/types/params.go +++ b/x/liquidvesting/types/params.go @@ -1,7 +1,7 @@ package types import ( - fmt "fmt" + "fmt" "slices" "cosmossdk.io/math" diff --git a/x/rewards/keeper/params.go b/x/rewards/keeper/params.go new file mode 100644 index 00000000..9c89d3e8 --- /dev/null +++ b/x/rewards/keeper/params.go @@ -0,0 +1,27 @@ +package keeper + +import ( + "context" + "errors" + + "cosmossdk.io/collections" + + "github.com/milkyway-labs/milkyway/v3/x/rewards/types" +) + +// SetParams sets module parameters +func (k *Keeper) SetParams(ctx context.Context, params types.Params) error { + return k.Params.Set(ctx, params) +} + +// GetParams returns the module parameters +func (k *Keeper) GetParams(ctx context.Context) (p types.Params, err error) { + p, err = k.Params.Get(ctx) + if err != nil { + if errors.Is(err, collections.ErrNotFound) { + return types.DefaultParams(), nil + } + return types.Params{}, err + } + return p, nil +}