From 75ca9204e73beaaa66be9eebdd84aaa6c6fb301c Mon Sep 17 00:00:00 2001 From: sampocs Date: Mon, 18 Sep 2023 01:57:52 -0500 Subject: [PATCH] v15 upgrade handler (#941) --- app/upgrades.go | 13 +++ app/upgrades/v15/upgrades.go | 76 ++++++++++++++++ app/upgrades/v15/upgrades_test.go | 145 ++++++++++++++++++++++++++++++ 3 files changed, 234 insertions(+) create mode 100644 app/upgrades/v15/upgrades.go create mode 100644 app/upgrades/v15/upgrades_test.go diff --git a/app/upgrades.go b/app/upgrades.go index 407e297284..5b4ffd35c4 100644 --- a/app/upgrades.go +++ b/app/upgrades.go @@ -18,6 +18,7 @@ import ( v12 "github.com/Stride-Labs/stride/v14/app/upgrades/v12" v13 "github.com/Stride-Labs/stride/v14/app/upgrades/v13" v14 "github.com/Stride-Labs/stride/v14/app/upgrades/v14" + v15 "github.com/Stride-Labs/stride/v14/app/upgrades/v15" v2 "github.com/Stride-Labs/stride/v14/app/upgrades/v2" v3 "github.com/Stride-Labs/stride/v14/app/upgrades/v3" v4 "github.com/Stride-Labs/stride/v14/app/upgrades/v4" @@ -172,6 +173,7 @@ func (app *StrideApp) setupUpgradeHandlers(appOpts servertypes.AppOptions) { app.StakeibcKeeper, ), ) + // v14 upgrade handler app.UpgradeKeeper.SetUpgradeHandler( v14.UpgradeName, @@ -191,6 +193,17 @@ func (app *StrideApp) setupUpgradeHandlers(appOpts servertypes.AppOptions) { ), ) + // v15 upgrade handler + app.UpgradeKeeper.SetUpgradeHandler( + v15.UpgradeName, + v15.CreateUpgradeHandler( + app.mm, + app.configurator, + app.InterchainqueryKeeper, + app.StakeibcKeeper, + ), + ) + upgradeInfo, err := app.UpgradeKeeper.ReadUpgradeInfoFromDisk() if err != nil { panic(fmt.Errorf("Failed to read upgrade info from disk: %w", err)) diff --git a/app/upgrades/v15/upgrades.go b/app/upgrades/v15/upgrades.go new file mode 100644 index 0000000000..e67672578d --- /dev/null +++ b/app/upgrades/v15/upgrades.go @@ -0,0 +1,76 @@ +package v15 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types" + + icqkeeper "github.com/Stride-Labs/stride/v14/x/interchainquery/keeper" + stakeibckeeper "github.com/Stride-Labs/stride/v14/x/stakeibc/keeper" +) + +var ( + UpgradeName = "v15" + + EvmosChainId = "evmos_9001-2" + EvmosOuterMinRedemptionRate = sdk.MustNewDecFromStr("1.290") + EvmosInnerMinRedemptionRate = sdk.MustNewDecFromStr("1.318") + EvmosMaxRedemptionRate = sdk.MustNewDecFromStr("1.500") + + RedemptionRateOuterMinAdjustment = sdk.MustNewDecFromStr("0.05") + RedemptionRateInnerMinAdjustment = sdk.MustNewDecFromStr("0.03") + RedemptionRateInnerMaxAdjustment = sdk.MustNewDecFromStr("0.05") + RedemptionRateOuterMaxAdjustment = sdk.MustNewDecFromStr("0.10") +) + +// CreateUpgradeHandler creates an SDK upgrade handler for v15 +func CreateUpgradeHandler( + mm *module.Manager, + configurator module.Configurator, + icqKeeper icqkeeper.Keeper, + stakeibcKeeper stakeibckeeper.Keeper, +) upgradetypes.UpgradeHandler { + return func(ctx sdk.Context, _ upgradetypes.Plan, vm module.VersionMap) (module.VersionMap, error) { + ctx.Logger().Info("Starting upgrade v15...") + + // Set host zone redemption rate bounds based on a percentage of their current rate + ctx.Logger().Info("Updating redemption rate bounds...") + for _, hostZone := range stakeibcKeeper.GetAllHostZone(ctx) { + if hostZone.ChainId == EvmosChainId { + hostZone.MinRedemptionRate = EvmosOuterMinRedemptionRate + hostZone.MinInnerRedemptionRate = EvmosInnerMinRedemptionRate + hostZone.MaxInnerRedemptionRate = EvmosMaxRedemptionRate + hostZone.MaxRedemptionRate = EvmosMaxRedemptionRate + + stakeibcKeeper.SetHostZone(ctx, hostZone) + } else { + outerMinDelta := hostZone.RedemptionRate.Mul(RedemptionRateOuterMinAdjustment) + innerMinDelta := hostZone.RedemptionRate.Mul(RedemptionRateInnerMinAdjustment) + innerMaxDelta := hostZone.RedemptionRate.Mul(RedemptionRateInnerMaxAdjustment) + outerMaxDelta := hostZone.RedemptionRate.Mul(RedemptionRateOuterMaxAdjustment) + + outerMin := hostZone.RedemptionRate.Sub(outerMinDelta) + innerMin := hostZone.RedemptionRate.Sub(innerMinDelta) + innerMax := hostZone.RedemptionRate.Add(innerMaxDelta) + outerMax := hostZone.RedemptionRate.Add(outerMaxDelta) + + hostZone.MinRedemptionRate = outerMin + hostZone.MinInnerRedemptionRate = innerMin + hostZone.MaxInnerRedemptionRate = innerMax + hostZone.MaxRedemptionRate = outerMax + + stakeibcKeeper.SetHostZone(ctx, hostZone) + } + } + + // Clear all stale delegator shares queries + ctx.Logger().Info("Deleting stale ICQs...") + for _, query := range icqKeeper.AllQueries(ctx) { + if query.CallbackId == stakeibckeeper.ICQCallbackID_Delegation { + icqKeeper.DeleteQuery(ctx, query.Id) + } + } + + return mm.RunMigrations(ctx, configurator, vm) + } +} diff --git a/app/upgrades/v15/upgrades_test.go b/app/upgrades/v15/upgrades_test.go new file mode 100644 index 0000000000..25532dad8d --- /dev/null +++ b/app/upgrades/v15/upgrades_test.go @@ -0,0 +1,145 @@ +package v15_test + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/suite" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/Stride-Labs/stride/v14/app/apptesting" + v15 "github.com/Stride-Labs/stride/v14/app/upgrades/v15" + icqtypes "github.com/Stride-Labs/stride/v14/x/interchainquery/types" + stakeibckeeper "github.com/Stride-Labs/stride/v14/x/stakeibc/keeper" + stakeibctypes "github.com/Stride-Labs/stride/v14/x/stakeibc/types" +) + +type UpgradeTestSuite struct { + apptesting.AppTestHelper +} + +func (s *UpgradeTestSuite) SetupTest() { + s.Setup() +} + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(UpgradeTestSuite)) +} + +type UpdateRedemptionRateBounds struct { + CurrentRedemptionRate sdk.Dec + ExpectedMinOuterRedemptionRate sdk.Dec + ExpectedMinInnerRedemptionRate sdk.Dec + ExpectedMaxInnerRedemptionRate sdk.Dec + ExpectedMaxOuterRedemptionRate sdk.Dec +} + +func (s *UpgradeTestSuite) TestUpgrade() { + dummyUpgradeHeight := int64(5) + + // Setup the store before the ugprade + checkRedemptionRatesAfterUpgrade := s.SetupRedemptionRatesBeforeUpgrade() + checkQueriesAfterUpgrade := s.SetupQueriesBeforeUpgrade() + + // Run the upgrade to set the bounds and clear pending queries + s.ConfirmUpgradeSucceededs("v15", dummyUpgradeHeight) + + // Check the store after the upgrade + checkRedemptionRatesAfterUpgrade() + checkQueriesAfterUpgrade() +} + +func (s *UpgradeTestSuite) SetupRedemptionRatesBeforeUpgrade() func() { + // Define test cases consisting of an initial redemption rate and expected bounds + testCases := []UpdateRedemptionRateBounds{ + { + CurrentRedemptionRate: sdk.MustNewDecFromStr("1.0"), + ExpectedMinOuterRedemptionRate: sdk.MustNewDecFromStr("0.95"), // 1 - 5% = 0.95 + ExpectedMinInnerRedemptionRate: sdk.MustNewDecFromStr("0.97"), // 1 - 3% = 0.97 + ExpectedMaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.05"), // 1 + 5% = 1.05 + ExpectedMaxOuterRedemptionRate: sdk.MustNewDecFromStr("1.10"), // 1 + 10% = 1.1 + }, + { + CurrentRedemptionRate: sdk.MustNewDecFromStr("1.1"), + ExpectedMinOuterRedemptionRate: sdk.MustNewDecFromStr("1.045"), // 1.1 - 5% = 1.045 + ExpectedMinInnerRedemptionRate: sdk.MustNewDecFromStr("1.067"), // 1.1 - 3% = 1.067 + ExpectedMaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.155"), // 1.1 + 5% = 1.155 + ExpectedMaxOuterRedemptionRate: sdk.MustNewDecFromStr("1.210"), // 1.1 + 10% = 1.21 + }, + { + CurrentRedemptionRate: sdk.MustNewDecFromStr("1.25"), + ExpectedMinOuterRedemptionRate: sdk.MustNewDecFromStr("1.1875"), // 1.25 - 5% = 1.1875 + ExpectedMinInnerRedemptionRate: sdk.MustNewDecFromStr("1.2125"), // 1.25 - 3% = 1.2125 + ExpectedMaxInnerRedemptionRate: sdk.MustNewDecFromStr("1.3125"), // 1.25 + 5% = 1.3125 + ExpectedMaxOuterRedemptionRate: sdk.MustNewDecFromStr("1.3750"), // 1.25 + 10% = 1.375 + }, + } + + // Create a host zone for each test case + for i, tc := range testCases { + chainId := fmt.Sprintf("chain-%d", i) + + hostZone := stakeibctypes.HostZone{ + ChainId: chainId, + RedemptionRate: tc.CurrentRedemptionRate, + } + s.App.StakeibcKeeper.SetHostZone(s.Ctx, hostZone) + } + + // Create an evmos host zone + s.App.StakeibcKeeper.SetHostZone(s.Ctx, stakeibctypes.HostZone{ + ChainId: v15.EvmosChainId, + }) + + // Return callback function to chck that bounds were set + return func() { + // Confirm the correct bounds were set + for i, tc := range testCases { + chainId := fmt.Sprintf("chain-%d", i) + + hostZone, found := s.App.StakeibcKeeper.GetHostZone(s.Ctx, chainId) + s.Require().True(found) + + s.Require().Equal(tc.ExpectedMinOuterRedemptionRate, hostZone.MinRedemptionRate, "min outer") + s.Require().Equal(tc.ExpectedMinInnerRedemptionRate, hostZone.MinInnerRedemptionRate, "min inner") + s.Require().Equal(tc.ExpectedMaxInnerRedemptionRate, hostZone.MaxInnerRedemptionRate, "max inner") + s.Require().Equal(tc.ExpectedMaxOuterRedemptionRate, hostZone.MaxRedemptionRate, "max outer") + } + + // Confirm evmos' custom bounds were set + evmosHostZone, found := s.App.StakeibcKeeper.GetHostZone(s.Ctx, v15.EvmosChainId) + s.Require().True(found) + + s.Require().Equal(v15.EvmosOuterMinRedemptionRate, evmosHostZone.MinRedemptionRate, "min outer") + s.Require().Equal(v15.EvmosInnerMinRedemptionRate, evmosHostZone.MinInnerRedemptionRate, "min inner") + s.Require().Equal(v15.EvmosMaxRedemptionRate, evmosHostZone.MaxInnerRedemptionRate, "max inner") + s.Require().Equal(v15.EvmosMaxRedemptionRate, evmosHostZone.MaxRedemptionRate, "max outer") + } +} + +func (s *UpgradeTestSuite) SetupQueriesBeforeUpgrade() func() { + // Set pending queries of different types + queries := []icqtypes.Query{ + {Id: "1", CallbackId: stakeibckeeper.ICQCallbackID_Validator}, + {Id: "2", CallbackId: stakeibckeeper.ICQCallbackID_Delegation}, // deleted + {Id: "3", CallbackId: stakeibckeeper.ICQCallbackID_Delegation}, // deleted + {Id: "4", CallbackId: stakeibckeeper.ICQCallbackID_WithdrawalBalance}, + } + expectedQueriesAfterUpgrade := []string{"1", "4"} + + for _, query := range queries { + s.App.InterchainqueryKeeper.SetQuery(s.Ctx, query) + } + + // Return callback function to check that queries were removed + return func() { + queryIds := []string{} + for _, query := range s.App.InterchainqueryKeeper.AllQueries(s.Ctx) { + queryIds = append(queryIds, query.Id) + } + + s.Require().Len(queryIds, 2) + s.Require().ElementsMatch(queryIds, expectedQueriesAfterUpgrade) + } +}