From 18caefe9693a268e46acfdcf42db5b51f1379023 Mon Sep 17 00:00:00 2001 From: insumity Date: Fri, 4 Oct 2024 18:14:52 +0200 Subject: [PATCH] feat!: migrate to allocate previously allocated rewards, and distribute unaccounted denoms (#3361) * init commit * Update app/upgrades/v21/upgrades.go Co-authored-by: Simon Noetzlin * took into account comments * bump ICS * took into account comments * run make format * run make format * fix linter * bump ics version to v6.2.0-rc0 * downgrade error to log (upgrade works only on mainnet) --------- Co-authored-by: MSalopek Co-authored-by: Simon Noetzlin Co-authored-by: mpoke --- app/upgrades/v21/upgrades.go | 94 +++++++++++++++++++- app/upgrades/v21/upgrades_test.go | 18 ++++ cmd/gaiad/cmd/testnet_set_local_validator.go | 5 +- go.mod | 2 +- go.sum | 4 +- tests/interchain/cosmwasm_test.go | 1 - tests/interchain/permissionless_test.go | 2 +- 7 files changed, 118 insertions(+), 8 deletions(-) diff --git a/app/upgrades/v21/upgrades.go b/app/upgrades/v21/upgrades.go index 83d323fb5e..b7dcb599b1 100644 --- a/app/upgrades/v21/upgrades.go +++ b/app/upgrades/v21/upgrades.go @@ -2,16 +2,40 @@ package v21 import ( "context" + "fmt" + providerkeeper "github.com/cosmos/interchain-security/v6/x/ccv/provider/keeper" + providertypes "github.com/cosmos/interchain-security/v6/x/ccv/provider/types" + + errorsmod "cosmossdk.io/errors" + "cosmossdk.io/math" upgradetypes "cosmossdk.io/x/upgrade/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/module" + authkeeper "github.com/cosmos/cosmos-sdk/x/auth/keeper" + bankkeeper "github.com/cosmos/cosmos-sdk/x/bank/keeper" govkeeper "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/gaia/v21/app/keepers" ) +// Neutron and Stride denoms that were not whitelisted but the consumer rewards pool contains amounts of those denoms. +// Price in $ for each denom corresponds to an approximation fo the current amount stored in the consumer rewards pool +// as of 27.09.2024. Only denoms with amounts more than $10 are included. +const ( + NeutronUusdc = "ibc/4E0D0854C0F846150FA8389D75EA5B5129B17703D7F4992D0356B4FE7C013D42" // ~$40 + NeutronUtia = "ibc/7054742D02E4F28B7DB5B44D97A496CF5AD16C2AE6948028A5FD57DCE7C5E271" // ~$300 + + StrideStutia = "ibc/17DABEBAC71C388DA064A3D54FB7E68BAF0687965EC39DEADA1FB78C0F1447E6" // ~$18,000 + StrideStadym = "ibc/3F0A41ECB6FAF27E315583DBF39B5B69A7149D23959A0E4B319F7EF5C618DCD7" // ~$800 + StrideStaISLM = "ibc/61A6F21D6AFF9835F66056461F1CAE24AA3323820259856B485FE7C063CA4FA6" // ~$1650 + StrideStuband = "ibc/E9401AC885592AC2023E0FB9BA7C8BC66D346CEE04CED8E9F545F3C25290708A" // ~$300 + StrideStadydx = "ibc/EEFD952A6DE346F2649039E99A16430B05FFEDF628A4DE99F34BB4B5F6A9346E" // ~$21,000 + StrideStusaga = "ibc/F918765AC289257B35DECC52BD92EBCDBA3C139658BD6F2670D70A6E10B97F58" // ~$300 +) + +// CreateUpgradeHandler returns an upgrade handler for Gaia v21. func CreateUpgradeHandler( mm *module.Manager, configurator module.Configurator, @@ -23,7 +47,15 @@ func CreateUpgradeHandler( vm, err := mm.RunMigrations(ctx, configurator, vm) if err != nil { - return vm, err + return vm, errorsmod.Wrapf(err, "running module migrations") + } + + ctx.Logger().Info("allocating rewards of Neutron and Stride unaccounted denoms") + err = AllocateNeutronAndStrideUnaccountedDenoms(ctx, keepers.ProviderKeeper, keepers.BankKeeper, keepers.AccountKeeper) + if err != nil { + // migration can only work on cosmoshub-4 + // all testchains except for mainnet export fork will fail this + ctx.Logger().Error("Error allocating rewards of Neutron and Stride unaccounted denoms:", "message", err.Error()) } err = InitializeConstitutionCollection(ctx, *keepers.GovKeeper) @@ -36,6 +68,66 @@ func CreateUpgradeHandler( } } +// AllocateRewards allocates all the `denoms` that reside in the `address` and are meant for the chain with `consumerID` +func AllocateRewards(ctx sdk.Context, providerKeeper providerkeeper.Keeper, bankKeeper bankkeeper.Keeper, address sdk.AccAddress, consumerID string, denoms []string) error { + for _, denom := range denoms { + coinRewards := bankKeeper.GetBalance(ctx, address, denom) + decCoinRewards := sdk.DecCoins{sdk.DecCoin{Denom: coinRewards.Denom, Amount: math.LegacyNewDecFromInt(coinRewards.Amount)}} + consumerRewardsAllocation := providertypes.ConsumerRewardsAllocation{Rewards: decCoinRewards} + + err := providerKeeper.SetConsumerRewardsAllocationByDenom(ctx, consumerID, denom, consumerRewardsAllocation) + if err != nil { + return err + } + } + return nil +} + +// HasexpectedChainIDSanityCheck returns true if the chain with the provided `consumerID` is of a chain with the `expectedChainID` +func HasExpectedChainIDSanityCheck(ctx sdk.Context, providerKeeper providerkeeper.Keeper, consumerID string, expectedChainID string) bool { + actualChainID, err := providerKeeper.GetConsumerChainId(ctx, consumerID) + if err != nil { + return false + } + if expectedChainID != actualChainID { + return false + } + return true +} + +// AllocateNeutronAndStrideUnaccountedDenoms allocates previously unaccounted denoms to the Stride and Neutron consumer chains +func AllocateNeutronAndStrideUnaccountedDenoms(ctx sdk.Context, providerKeeper providerkeeper.Keeper, bankKeeper bankkeeper.Keeper, accountKeeper authkeeper.AccountKeeper) error { + consumerRewardsPoolAddress := accountKeeper.GetModuleAccount(ctx, providertypes.ConsumerRewardsPool).GetAddress() + + const NeutronconsumerID = "0" + const NeutronChainID = "neutron-1" + + if !HasExpectedChainIDSanityCheck(ctx, providerKeeper, NeutronconsumerID, NeutronChainID) { + return fmt.Errorf("failed sanity check: consumer id (%s) does not correspond to chain id (%s)", NeutronconsumerID, NeutronChainID) + } + + neutronUnaccountedDenoms := []string{NeutronUusdc, NeutronUtia} + err := AllocateRewards(ctx, providerKeeper, bankKeeper, consumerRewardsPoolAddress, NeutronconsumerID, neutronUnaccountedDenoms) + if err != nil { + return fmt.Errorf("cannot allocate rewards for consumer id (%s): %w", NeutronconsumerID, err) + } + + const StrideconsumerID = "1" + const StrideChainID = "stride-1" + + if !HasExpectedChainIDSanityCheck(ctx, providerKeeper, StrideconsumerID, StrideChainID) { + return fmt.Errorf("failed sanity check: consumer id (%s) does not correspond to chain id (%s)", StrideconsumerID, StrideChainID) + } + + strideUnaccountedDenoms := []string{StrideStutia, StrideStadym, StrideStaISLM, StrideStuband, StrideStadydx, StrideStusaga} + err = AllocateRewards(ctx, providerKeeper, bankKeeper, consumerRewardsPoolAddress, StrideconsumerID, strideUnaccountedDenoms) + if err != nil { + return fmt.Errorf("cannot allocate rewards for consumer id (%s): %w", StrideconsumerID, err) + } + + return nil +} + // setting the default constitution for the chain // this is in line with cosmos-sdk v5 gov migration: https://github.com/cosmos/cosmos-sdk/blob/v0.50.10/x/gov/migrations/v5/store.go#L57 func InitializeConstitutionCollection(ctx sdk.Context, govKeeper govkeeper.Keeper) error { diff --git a/app/upgrades/v21/upgrades_test.go b/app/upgrades/v21/upgrades_test.go index fb7c309267..aaf31861a2 100644 --- a/app/upgrades/v21/upgrades_test.go +++ b/app/upgrades/v21/upgrades_test.go @@ -11,6 +11,24 @@ import ( v21 "github.com/cosmos/gaia/v21/app/upgrades/v21" ) +func TestHasExpectedChainIDSanityCheck(t *testing.T) { + gaiaApp := helpers.Setup(t) + ctx := gaiaApp.NewUncachedContext(true, tmproto.Header{}) + + pk := gaiaApp.ProviderKeeper + + // no such consumer chain + consumerID := "0" + require.False(t, v21.HasExpectedChainIDSanityCheck(ctx, pk, consumerID, "chain-1")) + + // consumer chain does not have `chain-1` id + pk.SetConsumerChainId(ctx, consumerID, "chain-2") + require.False(t, v21.HasExpectedChainIDSanityCheck(ctx, pk, consumerID, "chain-1")) + + pk.SetConsumerChainId(ctx, consumerID, "chain-1") + require.True(t, v21.HasExpectedChainIDSanityCheck(ctx, pk, consumerID, "chain-1")) +} + func TestInitializeConstitutionCollection(t *testing.T) { gaiaApp := helpers.Setup(t) ctx := gaiaApp.NewUncachedContext(true, tmproto.Header{}) diff --git a/cmd/gaiad/cmd/testnet_set_local_validator.go b/cmd/gaiad/cmd/testnet_set_local_validator.go index a62a3d9254..0532c8483b 100644 --- a/cmd/gaiad/cmd/testnet_set_local_validator.go +++ b/cmd/gaiad/cmd/testnet_set_local_validator.go @@ -19,10 +19,11 @@ import ( "github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" "github.com/cosmos/cosmos-sdk/server" servertypes "github.com/cosmos/cosmos-sdk/server/types" - gaia "github.com/cosmos/gaia/v21/app" "github.com/spf13/cast" "github.com/spf13/cobra" + gaia "github.com/cosmos/gaia/v21/app" + "cosmossdk.io/log" "github.com/cometbft/cometbft/crypto" tmd25519 "github.com/cometbft/cometbft/crypto/ed25519" @@ -269,7 +270,7 @@ func updateApplicationState(app *gaia.GaiaApp, args valArgs) error { // PROVIDER app.ProviderKeeper.DeleteLastProviderConsensusValSet(appCtx) - // GOVERNANCE + // GOVERNANCE shortVotingPeriod := time.Second * 20 expeditedVotingPeriod := time.Second * 10 params, err := app.GovKeeper.Params.Get(appCtx) diff --git a/go.mod b/go.mod index 897fd23cf2..d0816fdc3f 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/cosmos/ibc-apps/modules/rate-limiting/v8 v8.0.0 github.com/cosmos/ibc-go/modules/capability v1.0.1 github.com/cosmos/ibc-go/v8 v8.5.1 - github.com/cosmos/interchain-security/v6 v6.1.0 + github.com/cosmos/interchain-security/v6 v6.2.0-rc0 github.com/google/gofuzz v1.2.0 github.com/gorilla/mux v1.8.1 github.com/ory/dockertest/v3 v3.11.0 diff --git a/go.sum b/go.sum index 92fff64ada..47033b4d4d 100644 --- a/go.sum +++ b/go.sum @@ -443,8 +443,8 @@ github.com/cosmos/ibc-go/v8 v8.5.1 h1:3JleEMKBjRKa3FeTKt4fjg22za/qygLBo7mDkoYTNB github.com/cosmos/ibc-go/v8 v8.5.1/go.mod h1:P5hkAvq0Qbg0h18uLxDVA9q1kOJ0l36htMsskiNwXbo= github.com/cosmos/ics23/go v0.11.0 h1:jk5skjT0TqX5e5QJbEnwXIS2yI2vnmLOgpQPeM5RtnU= github.com/cosmos/ics23/go v0.11.0/go.mod h1:A8OjxPE67hHST4Icw94hOxxFEJMBG031xIGF/JHNIY0= -github.com/cosmos/interchain-security/v6 v6.1.0 h1:ycTpT+If90nSEvRVu86ThPJxNtcmnOMjJmFC9ptd/yo= -github.com/cosmos/interchain-security/v6 v6.1.0/go.mod h1:+5zIZEzkL4yNHB/UWXCu75t6GeEgEmWHbz5OnBWiL0o= +github.com/cosmos/interchain-security/v6 v6.2.0-rc0 h1:RjGfEDSnOlsgXG4g5FSr5PBUE4V5N1wfCH09vLqrMDE= +github.com/cosmos/interchain-security/v6 v6.2.0-rc0/go.mod h1:8Ke3cbEBBMImBkWPfF1bxPFg5ZqYOxZPjpnh0ItxQMQ= github.com/cosmos/keyring v1.2.0 h1:8C1lBP9xhImmIabyXW4c3vFjjLiBdGCmfLUfeZlV1Yo= github.com/cosmos/keyring v1.2.0/go.mod h1:fc+wB5KTk9wQ9sDx0kFXB3A0MaeGHM9AwRStKOQ5vOA= github.com/cosmos/ledger-cosmos-go v0.13.3 h1:7ehuBGuyIytsXbd4MP43mLeoN2LTOEnk5nvue4rK+yM= diff --git a/tests/interchain/cosmwasm_test.go b/tests/interchain/cosmwasm_test.go index 9d3bbb76af..fa0d8fbf77 100644 --- a/tests/interchain/cosmwasm_test.go +++ b/tests/interchain/cosmwasm_test.go @@ -80,7 +80,6 @@ func (s *CosmWasmSuite) TestCantInstantiateWithoutProp() { } func (s *CosmWasmSuite) TestCreateNewContract() { - _, contractAddr := s.storeInstantiateProposal(initState) count := s.getContractCount(contractAddr) diff --git a/tests/interchain/permissionless_test.go b/tests/interchain/permissionless_test.go index 4087cfcd36..948177436d 100644 --- a/tests/interchain/permissionless_test.go +++ b/tests/interchain/permissionless_test.go @@ -360,8 +360,8 @@ func (s *PermissionlessConsumersSuite) TestChangePowerShaping() { s.Require().NoError(err) s.Require().Equal(consumer.ValidatorWallets[i].ValConsAddress, valCons) } - } + func (s *PermissionlessConsumersSuite) TestConsumerCommissionRate() { s.UpgradeChain() cfg := s.consumerCfg