package e2e_test import ( cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types" ) // func (suite *IntegrationTestSuite) TestUpgradeInflation_Disable() { // suite.SkipIfUpgradeDisabled() // afterUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight) // // Get x/community for switchover time // params, err := suite.ZgChain.Community.Params(afterUpgradeCtx, &communitytypes.QueryParamsRequest{}) // suite.Require().NoError(err) // // Sleep until switchover time + 6 seconds for extra block // sleepDuration := time.Until(params.Params.UpgradeTimeDisableInflation.Add(6 * time.Second)) // time.Sleep(sleepDuration) // suite.Require().Eventually(func() bool { // communityParams, err := suite.ZgChain.Community.Params(afterUpgradeCtx, &communitytypes.QueryParamsRequest{}) // suite.Require().NoError(err) // // After params are set in x/community -- non-zero switchover time // return !communityParams.Params.UpgradeTimeDisableInflation.Equal(time.Time{}) // }, 20*time.Second, 3*time.Second) // // Fetch exact block when inflation stop event emitted // // This is run after the switchover, so we don't need to poll // _, switchoverHeight, err := suite.ZgChain.GetBeginBlockEventsFromQuery( // context.Background(), // fmt.Sprintf( // "%s.%s EXISTS", // communitytypes.EventTypeInflationStop, // communitytypes.AttributeKeyInflationDisableTime, // ), // ) // suite.Require().NoError(err) // suite.Require().NotZero(switchoverHeight) // // 1 block before switchover // beforeSwitchoverCtx := util.CtxAtHeight(switchoverHeight - 1) // afterSwitchoverCtx := util.CtxAtHeight(switchoverHeight) // suite.Run("x/mint, x/kavadist inflation before switchover", func() { // mintParams, err := suite.ZgChain.Mint.Params( // beforeSwitchoverCtx, // &minttypes.QueryParamsRequest{}, // ) // suite.NoError(err) // kavaDistParams, err := suite.ZgChain.Kavadist.Params( // beforeSwitchoverCtx, // &kavadisttypes.QueryParamsRequest{}, // ) // suite.NoError(err) // // Use .String() to compare Decs since x/mint uses the deprecated one, // // mismatch of types but same value. // suite.Equal( // sdkmath.LegacyMustNewDecFromStr("0.595000000000000000").String(), // mintParams.Params.InflationMin.String(), // "x/mint inflation min should be 59.5%% before switchover", // ) // suite.Equal( // sdkmath.LegacyMustNewDecFromStr("0.595000000000000000").String(), // mintParams.Params.InflationMax.String(), // "x/mint inflation max should be 59.5%% before switchover", // ) // suite.True( // kavaDistParams.Params.Active, // "x/kavadist should be active before switchover", // ) // }) // suite.Run("x/distribution community tax before switchover", func() { // distrParams, err := suite.ZgChain.Distribution.Params( // beforeSwitchoverCtx, // &distributiontypes.QueryParamsRequest{}, // ) // suite.NoError(err) // suite.Equal( // sdkmath.LegacyMustNewDecFromStr("0.949500000000000000").String(), // distrParams.Params.CommunityTax.String(), // "x/distribution community tax should be 94.95%% before switchover", // ) // }) // suite.Run("x/mint, x/kavadist inflation after switchover", func() { // mintParams, err := suite.ZgChain.Mint.Params( // afterSwitchoverCtx, // &minttypes.QueryParamsRequest{}, // ) // suite.NoError(err) // kavaDistParams, err := suite.ZgChain.Kavadist.Params( // afterSwitchoverCtx, // &kavadisttypes.QueryParamsRequest{}, // ) // suite.NoError(err) // suite.Equal( // sdkmath.LegacyZeroDec().String(), // mintParams.Params.InflationMin.String(), // "x/mint inflation min should be 0% after switchover", // ) // suite.Equal( // sdkmath.LegacyZeroDec().String(), // mintParams.Params.InflationMax.String(), // "x/mint inflation max should be 0% after switchover", // ) // suite.False( // kavaDistParams.Params.Active, // "x/kavadist should be inactive after switchover", // ) // }) // suite.Run("x/distribution community tax after switchover", func() { // distrParams, err := suite.ZgChain.Distribution.Params( // afterSwitchoverCtx, // &distributiontypes.QueryParamsRequest{}, // ) // suite.NoError(err) // suite.Equal( // sdkmath.LegacyZeroDec().String(), // distrParams.Params.CommunityTax.String(), // "x/distribution community tax should be 0%% before switchover", // ) // }) // // Ensure inflation was still active before switchover // suite.Run("positive mint events before switchover", func() { // // 1 block before switchover // queryHeight := switchoverHeight - 1 // block, err := suite.ZgChain.TmSignClient.BlockResults( // context.Background(), // &queryHeight, // ) // suite.Require().NoError(err) // // Mint events should only occur in begin block // mintEvents := util.FilterEventsByType(block.BeginBlockEvents, minttypes.EventTypeMint) // suite.Require().NotEmpty(mintEvents, "mint events should be emitted") // // Ensure mint amounts are non-zero // found := false // for _, event := range mintEvents { // for _, attribute := range event.Attributes { // // Bonded ratio and annual provisions unchecked // if string(attribute.Key) == minttypes.AttributeKeyInflation { // suite.Equal( // sdkmath.LegacyMustNewDecFromStr("0.595000000000000000").String(), // string(attribute.Value), // "inflation should be 59.5%% before switchover", // ) // } // if string(attribute.Key) == sdk.AttributeKeyAmount { // found = true // // Parse as native go int, not necessary to use sdk.Int // value, err := strconv.Atoi(string(attribute.Value)) // suite.Require().NoError(err) // suite.NotZero(value, "mint amount should be non-zero") // suite.Positive(value, "mint amount should be positive") // } // } // } // suite.True(found, "mint amount should be found") // }) // suite.Run("staking denom supply increases before switchover", func() { // queryHeight := switchoverHeight - 2 // supply1, err := suite.ZgChain.Bank.SupplyOf( // util.CtxAtHeight(queryHeight), // &types.QuerySupplyOfRequest{ // Denom: suite.ZgChain.StakingDenom, // }, // ) // suite.Require().NoError(err) // suite.NotZero(supply1.Amount, "ukava supply should be non-zero") // // Next block // queryHeight += 1 // supply2, err := suite.ZgChain.Bank.SupplyOf( // util.CtxAtHeight(queryHeight), // &types.QuerySupplyOfRequest{ // Denom: suite.ZgChain.StakingDenom, // }, // ) // suite.Require().NoError(err) // suite.NotZero(supply2.Amount, "ukava supply should be non-zero") // suite.Truef( // supply2.Amount.Amount.GT(supply1.Amount.Amount), // "ukava supply before switchover should increase between blocks, %s > %s", // supply2.Amount.Amount.String(), // ) // }) // // Check if inflation is ACTUALLY disabled... check if any coins are being // // minted in the blocks after switchover // suite.Run("no minting after switchover", func() { // kavaSupply := sdk.NewCoin(suite.ZgChain.StakingDenom, sdkmath.ZeroInt()) // // Next 5 blocks after switchover, ensure there's actually no more inflation // for i := 0; i < 5; i++ { // queryHeight := switchoverHeight + int64(i) // suite.Run( // fmt.Sprintf("x/mint events with 0 amount @ height=%d", queryHeight), // func() { // var block *coretypes.ResultBlockResults // suite.Require().Eventually(func() bool { // // Check begin block events // block, err = suite.ZgChain.TmSignClient.BlockResults( // context.Background(), // &queryHeight, // ) // return err == nil // }, 20*time.Second, 3*time.Second) // var mintEvents []abci.Event // // Mint events should only occur in begin block, but we just include // // everything else just in case anything changes in x/mint // mintEventsBegin := util.FilterEventsByType(block.BeginBlockEvents, minttypes.EventTypeMint) // mintEventsEnd := util.FilterEventsByType(block.EndBlockEvents, minttypes.EventTypeMint) // mintEventsTx := util.FilterTxEventsByType(block.TxsResults, minttypes.EventTypeMint) // mintEvents = append(mintEvents, mintEventsBegin...) // mintEvents = append(mintEvents, mintEventsEnd...) // mintEvents = append(mintEvents, mintEventsTx...) // suite.Require().NotEmpty(mintEvents, "mint events should still be emitted") // // Ensure mint amounts are 0 // found := false // for _, event := range mintEvents { // for _, attribute := range event.Attributes { // // Bonded ratio and annual provisions unchecked // if string(attribute.Key) == minttypes.AttributeKeyInflation { // suite.Equal(sdkmath.LegacyZeroDec().String(), string(attribute.Value)) // } // if string(attribute.Key) == sdk.AttributeKeyAmount { // found = true // suite.Equal(sdkmath.ZeroInt().String(), string(attribute.Value)) // } // } // } // suite.True(found, "mint amount should be found") // }, // ) // // Run this after the events check, since that one waits for the // // new block if necessary // suite.Run( // fmt.Sprintf("total staking denom supply should not change @ height=%d", queryHeight), // func() { // supplyRes, err := suite.ZgChain.Bank.SupplyOf( // util.CtxAtHeight(queryHeight), // &types.QuerySupplyOfRequest{ // Denom: suite.ZgChain.StakingDenom, // }, // ) // suite.Require().NoError(err) // if kavaSupply.IsZero() { // // First iteration, set supply // kavaSupply = supplyRes.Amount // } else { // suite.Require().Equal( // kavaSupply, // supplyRes.Amount, // "ukava supply should not change", // ) // } // }, // ) // } // }) // suite.Run("no staking rewards from x/community before switchover", func() { // // 1 block before switchover // queryHeight := switchoverHeight - 1 // block, err := suite.ZgChain.TmSignClient.BlockResults( // context.Background(), // &queryHeight, // ) // suite.Require().NoError(err) // // Events are not emitted if amount is 0 // stakingRewardEvents := util.FilterEventsByType(block.BeginBlockEvents, communitytypes.EventTypeStakingRewardsPaid) // suite.Require().Empty(stakingRewardEvents, "staking reward events should not be emitted") // }) // suite.Run("staking rewards pay out from x/community after switchover", func() { // for i := 0; i < 5; i++ { // // after switchover // queryHeight := switchoverHeight + int64(i) // block, err := suite.ZgChain.TmSignClient.BlockResults( // context.Background(), // &queryHeight, // ) // suite.Require().NoError(err) // stakingRewardEvents := util.FilterEventsByType( // block.BeginBlockEvents, // communitytypes.EventTypeStakingRewardsPaid, // ) // suite.Require().NotEmptyf( // stakingRewardEvents, // "staking reward events should be emitted at height=%d", // queryHeight, // ) // // Ensure amounts are non-zero // found := false // for _, attr := range stakingRewardEvents[0].Attributes { // if string(attr.Key) == communitytypes.AttributeKeyStakingRewardAmount { // coins, err := sdk.ParseCoinNormalized(string(attr.Value)) // suite.Require().NoError(err, "staking reward amount should be parsable coins") // suite.Truef( // coins.Amount.IsPositive(), // "staking reward amount should be a positive amount at height=%d", // queryHeight, // ) // found = true // } // } // suite.Truef( // found, // "staking reward amount should be found in events at height=%d", // queryHeight, // ) // } // }) // // Staking rewards can still be claimed // suite.Run("staking rewards claimable after switchover", func() { // suite.SkipIfKvtoolDisabled() // // Get the delegator of the only validator // validators, err := suite.ZgChain.Staking.Validators( // context.Background(), // &stakingtypes.QueryValidatorsRequest{}, // ) // suite.Require().NoError(err) // suite.Require().Positive(len(validators.Validators), "should only be at least 1 validator") // valAddr, err := sdk.ValAddressFromBech32(validators.Validators[0].OperatorAddress) // suite.Require().NoError(err) // accAddr := sdk.AccAddress(valAddr.Bytes()) // balBefore, err := suite.ZgChain.Bank.Balance( // context.Background(), // &types.QueryBalanceRequest{ // Address: accAddr.String(), // Denom: suite.ZgChain.StakingDenom, // }, // ) // suite.Require().NoError(err) // suite.Require().False(balBefore.Balance.IsZero(), "val staking denom balance should be non-zero") // delegationRewards, err := suite.ZgChain.Distribution.DelegationRewards( // context.Background(), // &distributiontypes.QueryDelegationRewardsRequest{ // ValidatorAddress: valAddr.String(), // DelegatorAddress: accAddr.String(), // }, // ) // suite.Require().NoError(err) // suite.False(delegationRewards.Rewards.Empty()) // suite.True(delegationRewards.Rewards.IsAllPositive(), "queried rewards should be positive") // withdrawRewardsMsg := distributiontypes.NewMsgWithdrawDelegatorReward( // accAddr, // valAddr, // ) // // Get the validator private key from kava keyring // key, err := suite.ZgChain.Keyring.(unsafeExporter).ExportPrivateKeyObject( // "validator", // ) // suite.Require().NoError(err) // acc := suite.ZgChain.AddNewSigningAccountFromPrivKey( // "validator", // key, // "", // suite.ZgChain.ChainID, // ) // gasLimit := int64(2e5) // fee := ukava(200) // req := util.KavaMsgRequest{ // Msgs: []sdk.Msg{withdrawRewardsMsg}, // GasLimit: uint64(gasLimit), // FeeAmount: sdk.NewCoins(fee), // Memo: "give me my money", // } // res := acc.SignAndBroadcastKavaTx(req) // _, err = util.WaitForSdkTxCommit(suite.ZgChain.Tx, res.Result.TxHash, 6*time.Second) // suite.Require().NoError(err) // balAfter, err := suite.ZgChain.Bank.Balance( // context.Background(), // &types.QueryBalanceRequest{ // Address: accAddr.String(), // Denom: suite.ZgChain.StakingDenom, // }, // ) // suite.Require().NoError(err) // suite.Require().False(balAfter.Balance.IsZero(), "val staking denom balance should be non-zero") // balIncrease := balAfter.Balance. // Sub(*balBefore.Balance). // Add(res.Tx.GetFee()[0]) // Add the fee back to balance to compare actual balances // queriedRewardsCoins, _ := delegationRewards.Rewards.TruncateDecimal() // suite.Require().Truef( // queriedRewardsCoins.AmountOf(suite.ZgChain.StakingDenom). // LTE(balIncrease.Amount), // "claimed rewards should be >= queried delegation rewards, got claimed %s vs queried %s", // balIncrease.Amount.String(), // queriedRewardsCoins.AmountOf(suite.ZgChain.StakingDenom).String(), // ) // }) // } // unsafeExporter is implemented by key stores that support unsafe export // of private keys' material. type unsafeExporter interface { // ExportPrivateKeyObject returns a private key in unarmored format. ExportPrivateKeyObject(uid string) (cryptotypes.PrivKey, error) }