mirror of
https://github.com/0glabs/0g-chain.git
synced 2025-01-14 09:15:17 +00:00
Add upgrade handler and upgrade e2e tests (#1739)
- Add upgrade handler for mainnet, testnet, and e2e test - Set validator minimum commission to 5% - Initialize `x/community` parameters - Add `banktypes.MsgSend` authz grant for `x/kavadist` for gov proposals - Set `x/gov` Quorum param to 20% - Set `x/incentive` earn rewards param for bkava to 600K KAVA per year
This commit is contained in:
parent
667e532aaa
commit
577f39b998
241
app/upgrades_test.go
Normal file
241
app/upgrades_test.go
Normal file
@ -0,0 +1,241 @@
|
|||||||
|
package app_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
sdkmath "cosmossdk.io/math"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||||
|
"github.com/evmos/ethermint/crypto/ethsecp256k1"
|
||||||
|
"github.com/kava-labs/kava/app"
|
||||||
|
incentivetypes "github.com/kava-labs/kava/x/incentive/types"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
|
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
|
||||||
|
tmtime "github.com/tendermint/tendermint/types/time"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestUpgradeCommunityParams_Mainnet(t *testing.T) {
|
||||||
|
require.Equal(
|
||||||
|
t,
|
||||||
|
sdkmath.LegacyZeroDec().String(),
|
||||||
|
app.CommunityParams_Mainnet.StakingRewardsPerSecond.String(),
|
||||||
|
)
|
||||||
|
|
||||||
|
require.Equal(
|
||||||
|
t,
|
||||||
|
// Manually confirmed
|
||||||
|
"317097.919837645865043125",
|
||||||
|
app.CommunityParams_Mainnet.UpgradeTimeSetStakingRewardsPerSecond.String(),
|
||||||
|
"mainnet kava per second should be correct",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpgradeCommunityParams_Testnet(t *testing.T) {
|
||||||
|
require.Equal(
|
||||||
|
t,
|
||||||
|
sdkmath.LegacyZeroDec().String(),
|
||||||
|
app.CommunityParams_Testnet.StakingRewardsPerSecond.String(),
|
||||||
|
)
|
||||||
|
|
||||||
|
require.Equal(
|
||||||
|
t,
|
||||||
|
// Manually confirmed
|
||||||
|
"475646879756.468797564687975646",
|
||||||
|
app.CommunityParams_Testnet.UpgradeTimeSetStakingRewardsPerSecond.String(),
|
||||||
|
"testnet kava per second should be correct",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateValidatorMinimumCommission(t *testing.T) {
|
||||||
|
tApp := app.NewTestApp()
|
||||||
|
tApp.InitializeFromGenesisStates()
|
||||||
|
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: tmtime.Now()})
|
||||||
|
|
||||||
|
sk := tApp.GetStakingKeeper()
|
||||||
|
stakingParams := sk.GetParams(ctx)
|
||||||
|
stakingParams.MinCommissionRate = sdk.ZeroDec()
|
||||||
|
sk.SetParams(ctx, stakingParams)
|
||||||
|
|
||||||
|
// Set some validators with varying commission rates
|
||||||
|
|
||||||
|
vals := []struct {
|
||||||
|
name string
|
||||||
|
operatorAddr sdk.ValAddress
|
||||||
|
consPriv *ethsecp256k1.PrivKey
|
||||||
|
commissionRateMin sdk.Dec
|
||||||
|
commissionRateMax sdk.Dec
|
||||||
|
shouldBeUpdated bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "zero commission rate",
|
||||||
|
operatorAddr: sdk.ValAddress("val0"),
|
||||||
|
consPriv: generateConsKey(t),
|
||||||
|
commissionRateMin: sdk.ZeroDec(),
|
||||||
|
commissionRateMax: sdk.ZeroDec(),
|
||||||
|
shouldBeUpdated: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "0.01 commission rate",
|
||||||
|
operatorAddr: sdk.ValAddress("val1"),
|
||||||
|
consPriv: generateConsKey(t),
|
||||||
|
commissionRateMin: sdk.MustNewDecFromStr("0.01"),
|
||||||
|
commissionRateMax: sdk.MustNewDecFromStr("0.01"),
|
||||||
|
shouldBeUpdated: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "0.05 commission rate",
|
||||||
|
operatorAddr: sdk.ValAddress("val2"),
|
||||||
|
consPriv: generateConsKey(t),
|
||||||
|
commissionRateMin: sdk.MustNewDecFromStr("0.05"),
|
||||||
|
commissionRateMax: sdk.MustNewDecFromStr("0.05"),
|
||||||
|
shouldBeUpdated: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "0.06 commission rate",
|
||||||
|
operatorAddr: sdk.ValAddress("val3"),
|
||||||
|
consPriv: generateConsKey(t),
|
||||||
|
commissionRateMin: sdk.MustNewDecFromStr("0.06"),
|
||||||
|
commissionRateMax: sdk.MustNewDecFromStr("0.06"),
|
||||||
|
shouldBeUpdated: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "0.5 commission rate",
|
||||||
|
operatorAddr: sdk.ValAddress("val4"),
|
||||||
|
consPriv: generateConsKey(t),
|
||||||
|
commissionRateMin: sdk.MustNewDecFromStr("0.5"),
|
||||||
|
commissionRateMax: sdk.MustNewDecFromStr("0.5"),
|
||||||
|
shouldBeUpdated: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range vals {
|
||||||
|
val, err := stakingtypes.NewValidator(
|
||||||
|
v.operatorAddr,
|
||||||
|
v.consPriv.PubKey(),
|
||||||
|
stakingtypes.Description{},
|
||||||
|
)
|
||||||
|
require.NoError(t, err)
|
||||||
|
val.Commission.Rate = v.commissionRateMin
|
||||||
|
val.Commission.MaxRate = v.commissionRateMax
|
||||||
|
|
||||||
|
err = sk.SetValidatorByConsAddr(ctx, val)
|
||||||
|
require.NoError(t, err)
|
||||||
|
sk.SetValidator(ctx, val)
|
||||||
|
}
|
||||||
|
|
||||||
|
require.NotPanics(
|
||||||
|
t, func() {
|
||||||
|
app.UpdateValidatorMinimumCommission(ctx, tApp.App)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
stakingParamsAfter := sk.GetParams(ctx)
|
||||||
|
require.Equal(t, stakingParamsAfter.MinCommissionRate, app.ValidatorMinimumCommission)
|
||||||
|
|
||||||
|
// Check that all validators have a commission rate >= 5%
|
||||||
|
for _, val := range vals {
|
||||||
|
t.Run(val.name, func(t *testing.T) {
|
||||||
|
validator, found := sk.GetValidator(ctx, val.operatorAddr)
|
||||||
|
require.True(t, found, "validator should be found")
|
||||||
|
|
||||||
|
require.True(
|
||||||
|
t,
|
||||||
|
validator.GetCommission().GTE(app.ValidatorMinimumCommission),
|
||||||
|
"commission rate should be >= 5%",
|
||||||
|
)
|
||||||
|
|
||||||
|
require.True(
|
||||||
|
t,
|
||||||
|
validator.Commission.MaxRate.GTE(app.ValidatorMinimumCommission),
|
||||||
|
"commission rate max should be >= 5%, got %s",
|
||||||
|
validator.Commission.MaxRate,
|
||||||
|
)
|
||||||
|
|
||||||
|
if val.shouldBeUpdated {
|
||||||
|
require.Equal(
|
||||||
|
t,
|
||||||
|
ctx.BlockTime(),
|
||||||
|
validator.Commission.UpdateTime,
|
||||||
|
"commission update time should be set to block time",
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
require.Equal(
|
||||||
|
t,
|
||||||
|
time.Unix(0, 0).UTC(),
|
||||||
|
validator.Commission.UpdateTime,
|
||||||
|
"commission update time should not be changed -- default value is 0",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestUpdateIncentiveParams(t *testing.T) {
|
||||||
|
tApp := app.NewTestApp()
|
||||||
|
tApp.InitializeFromGenesisStates()
|
||||||
|
ctx := tApp.NewContext(true, tmproto.Header{Height: 1, Time: tmtime.Now()})
|
||||||
|
|
||||||
|
ik := tApp.GetIncentiveKeeper()
|
||||||
|
params := ik.GetParams(ctx)
|
||||||
|
|
||||||
|
startPeriod := time.Date(2021, 10, 26, 15, 0, 0, 0, time.UTC)
|
||||||
|
endPeriod := time.Date(2022, 10, 26, 15, 0, 0, 0, time.UTC)
|
||||||
|
|
||||||
|
params.EarnRewardPeriods = incentivetypes.MultiRewardPeriods{
|
||||||
|
incentivetypes.NewMultiRewardPeriod(
|
||||||
|
true,
|
||||||
|
"bkava",
|
||||||
|
startPeriod,
|
||||||
|
endPeriod,
|
||||||
|
sdk.NewCoins(
|
||||||
|
sdk.NewCoin("ukava", sdk.NewInt(159459)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
ik.SetParams(ctx, params)
|
||||||
|
|
||||||
|
beforeParams := ik.GetParams(ctx)
|
||||||
|
require.Equal(t, params, beforeParams, "initial incentive params should be set")
|
||||||
|
|
||||||
|
// -- UPGRADE
|
||||||
|
app.UpdateIncentiveParams(ctx, tApp.App)
|
||||||
|
|
||||||
|
// -- After
|
||||||
|
afterParams := ik.GetParams(ctx)
|
||||||
|
|
||||||
|
require.Len(
|
||||||
|
t,
|
||||||
|
afterParams.EarnRewardPeriods[0].RewardsPerSecond,
|
||||||
|
1,
|
||||||
|
"bkava earn reward period should only contain 1 coin",
|
||||||
|
)
|
||||||
|
require.Equal(
|
||||||
|
t,
|
||||||
|
// Manual calculation of
|
||||||
|
// 600,000 * 1000,000 / (365 * 24 * 60 * 60)
|
||||||
|
sdk.NewCoin("ukava", sdkmath.NewInt(19025)),
|
||||||
|
afterParams.EarnRewardPeriods[0].RewardsPerSecond[0],
|
||||||
|
"bkava earn reward period should be updated",
|
||||||
|
)
|
||||||
|
|
||||||
|
// Check that other params are not changed
|
||||||
|
afterParams.EarnRewardPeriods[0].RewardsPerSecond[0] = beforeParams.EarnRewardPeriods[0].RewardsPerSecond[0]
|
||||||
|
require.Equal(
|
||||||
|
t,
|
||||||
|
beforeParams,
|
||||||
|
afterParams,
|
||||||
|
"other param values should not be changed",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
func generateConsKey(
|
||||||
|
t *testing.T,
|
||||||
|
) *ethsecp256k1.PrivKey {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
key, err := ethsecp256k1.GenerateKey()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
return key
|
||||||
|
}
|
256
tests/e2e/e2e_upgrade_community_test.go
Normal file
256
tests/e2e/e2e_upgrade_community_test.go
Normal file
@ -0,0 +1,256 @@
|
|||||||
|
package e2e_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||||
|
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
|
||||||
|
|
||||||
|
"github.com/kava-labs/kava/app"
|
||||||
|
"github.com/kava-labs/kava/tests/util"
|
||||||
|
communitytypes "github.com/kava-labs/kava/x/community/types"
|
||||||
|
kavadisttypes "github.com/kava-labs/kava/x/kavadist/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (suite *IntegrationTestSuite) TestUpgradeCommunityParams() {
|
||||||
|
suite.SkipIfUpgradeDisabled()
|
||||||
|
|
||||||
|
beforeUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight - 1)
|
||||||
|
afterUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight)
|
||||||
|
|
||||||
|
// Before params
|
||||||
|
kavaDistParamsBefore, err := suite.Kava.Kavadist.Params(beforeUpgradeCtx, &kavadisttypes.QueryParamsRequest{})
|
||||||
|
suite.NoError(err)
|
||||||
|
mintParamsBefore, err := suite.Kava.Mint.Params(beforeUpgradeCtx, &minttypes.QueryParamsRequest{})
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
// Before parameters
|
||||||
|
suite.Run("x/community and x/kavadist parameters before upgrade", func() {
|
||||||
|
_, err = suite.Kava.Community.Params(beforeUpgradeCtx, &communitytypes.QueryParamsRequest{})
|
||||||
|
suite.Error(err, "x/community should not have params before upgrade")
|
||||||
|
|
||||||
|
suite.Require().True(
|
||||||
|
kavaDistParamsBefore.Params.Active,
|
||||||
|
"x/kavadist should be active before upgrade",
|
||||||
|
)
|
||||||
|
|
||||||
|
suite.Require().True(
|
||||||
|
mintParamsBefore.Params.InflationMax.IsPositive(),
|
||||||
|
"x/mint inflation max should be positive before upgrade",
|
||||||
|
)
|
||||||
|
suite.Require().True(
|
||||||
|
mintParamsBefore.Params.InflationMin.IsPositive(),
|
||||||
|
"x/mint inflation min should be positive before upgrade",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
// After upgrade, Before switchover - parameters
|
||||||
|
suite.Run("x/kavadist, x/mint, x/community parameters after upgrade, before switchover", func() {
|
||||||
|
kavaDistParamsAfter, err := suite.Kava.Kavadist.Params(afterUpgradeCtx, &kavadisttypes.QueryParamsRequest{})
|
||||||
|
suite.NoError(err)
|
||||||
|
mintParamsAfter, err := suite.Kava.Mint.Params(afterUpgradeCtx, &minttypes.QueryParamsRequest{})
|
||||||
|
suite.NoError(err)
|
||||||
|
communityParamsAfter, err := suite.Kava.Community.Params(afterUpgradeCtx, &communitytypes.QueryParamsRequest{})
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
suite.Equal(
|
||||||
|
kavaDistParamsBefore.Params,
|
||||||
|
kavaDistParamsAfter.Params,
|
||||||
|
"x/kavadist should be unaffected after upgrade",
|
||||||
|
)
|
||||||
|
|
||||||
|
suite.Equal(
|
||||||
|
mintParamsBefore.Params,
|
||||||
|
mintParamsAfter.Params,
|
||||||
|
"x/mint params should be unaffected after upgrade",
|
||||||
|
)
|
||||||
|
|
||||||
|
expectedParams := app.CommunityParams_E2E
|
||||||
|
// Make UpgradeTimeDisableInflation match so that we ignore it, because
|
||||||
|
// referencing app.CommunityParams_E2E in this test files is different
|
||||||
|
// from the one set in the upgrade handler. At least check that it is
|
||||||
|
// set to a non-zero value in the assertion below
|
||||||
|
expectedParams.UpgradeTimeDisableInflation = communityParamsAfter.Params.UpgradeTimeDisableInflation
|
||||||
|
|
||||||
|
suite.False(
|
||||||
|
communityParamsAfter.Params.UpgradeTimeDisableInflation.IsZero(),
|
||||||
|
"x/community switchover time should be set after upgrade",
|
||||||
|
)
|
||||||
|
suite.Equal(
|
||||||
|
expectedParams,
|
||||||
|
communityParamsAfter.Params,
|
||||||
|
"x/community params should be set to E2E params after upgrade",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
suite.Require().Eventually(
|
||||||
|
func() bool {
|
||||||
|
// Get x/community for switchover time
|
||||||
|
params, err := suite.Kava.Community.Params(
|
||||||
|
context.Background(),
|
||||||
|
&communitytypes.QueryParamsRequest{},
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// Check that switchover time is set to zero, e.g. switchover happened
|
||||||
|
return params.Params.UpgradeTimeDisableInflation.Equal(time.Time{})
|
||||||
|
},
|
||||||
|
20*time.Second, 1*time.Second,
|
||||||
|
"switchover should happen and x/community params should be updated",
|
||||||
|
)
|
||||||
|
|
||||||
|
// Fetch exact block when inflation stop event emitted
|
||||||
|
_, switchoverHeight, err := suite.Kava.GetBeginBlockEventsFromQuery(
|
||||||
|
context.Background(),
|
||||||
|
fmt.Sprintf(
|
||||||
|
"%s.%s EXISTS",
|
||||||
|
communitytypes.EventTypeInflationStop,
|
||||||
|
communitytypes.AttributeKeyInflationDisableTime,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
suite.Require().NotZero(switchoverHeight)
|
||||||
|
|
||||||
|
beforeSwitchoverCtx := util.CtxAtHeight(switchoverHeight - 1)
|
||||||
|
afterSwitchoverCtx := util.CtxAtHeight(switchoverHeight)
|
||||||
|
|
||||||
|
suite.Run("x/kavadist, x/mint, x/community parameters after upgrade, after switchover", func() {
|
||||||
|
kavaDistParamsAfter, err := suite.Kava.Kavadist.Params(
|
||||||
|
afterSwitchoverCtx,
|
||||||
|
&kavadisttypes.QueryParamsRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
mintParamsAfter, err := suite.Kava.Mint.Params(
|
||||||
|
afterSwitchoverCtx,
|
||||||
|
&minttypes.QueryParamsRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
communityParamsAfter, err := suite.Kava.Community.Params(
|
||||||
|
afterSwitchoverCtx,
|
||||||
|
&communitytypes.QueryParamsRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
suite.False(
|
||||||
|
kavaDistParamsAfter.Params.Active,
|
||||||
|
"x/kavadist should be disabled after upgrade",
|
||||||
|
)
|
||||||
|
|
||||||
|
suite.True(
|
||||||
|
mintParamsAfter.Params.InflationMax.IsZero(),
|
||||||
|
"x/mint inflation max should be zero after switchover",
|
||||||
|
)
|
||||||
|
suite.True(
|
||||||
|
mintParamsAfter.Params.InflationMin.IsZero(),
|
||||||
|
"x/mint inflation min should be zero after switchover",
|
||||||
|
)
|
||||||
|
|
||||||
|
suite.Equal(
|
||||||
|
time.Time{},
|
||||||
|
communityParamsAfter.Params.UpgradeTimeDisableInflation,
|
||||||
|
"x/community switchover time should be reset",
|
||||||
|
)
|
||||||
|
|
||||||
|
suite.Equal(
|
||||||
|
communityParamsAfter.Params.UpgradeTimeSetStakingRewardsPerSecond,
|
||||||
|
communityParamsAfter.Params.StakingRewardsPerSecond,
|
||||||
|
"x/community staking rewards per second should match upgrade time staking rewards per second",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
suite.Run("x/kavadist, x/distribution, x/community balances after switchover", func() {
|
||||||
|
// Before balances - community pool fund consolidation
|
||||||
|
kavaDistBalBefore, err := suite.Kava.Kavadist.Balance(
|
||||||
|
beforeSwitchoverCtx,
|
||||||
|
&kavadisttypes.QueryBalanceRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
distrBalBefore, err := suite.Kava.Distribution.CommunityPool(
|
||||||
|
beforeSwitchoverCtx,
|
||||||
|
&distrtypes.QueryCommunityPoolRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
distrBalCoinsBefore, distrDustBefore := distrBalBefore.Pool.TruncateDecimal()
|
||||||
|
beforeCommPoolBalance, err := suite.Kava.Community.Balance(
|
||||||
|
beforeSwitchoverCtx,
|
||||||
|
&communitytypes.QueryBalanceRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
// After balances
|
||||||
|
kavaDistBalAfter, err := suite.Kava.Kavadist.Balance(
|
||||||
|
afterSwitchoverCtx,
|
||||||
|
&kavadisttypes.QueryBalanceRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
distrBalAfter, err := suite.Kava.Distribution.CommunityPool(
|
||||||
|
afterSwitchoverCtx,
|
||||||
|
&distrtypes.QueryCommunityPoolRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
afterCommPoolBalance, err := suite.Kava.Community.Balance(
|
||||||
|
afterSwitchoverCtx,
|
||||||
|
&communitytypes.QueryBalanceRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
expectedKavadistBal := sdk.NewCoins(sdk.NewCoin(
|
||||||
|
"ukava",
|
||||||
|
kavaDistBalBefore.Coins.AmountOf("ukava"),
|
||||||
|
))
|
||||||
|
suite.Equal(
|
||||||
|
expectedKavadistBal,
|
||||||
|
kavaDistBalAfter.Coins,
|
||||||
|
"x/kavadist balance should persist the ukava amount and move all other funds",
|
||||||
|
)
|
||||||
|
expectedKavadistTransferred := kavaDistBalBefore.Coins.Sub(expectedKavadistBal...)
|
||||||
|
|
||||||
|
// very low ukava balance after (ignoring dust in x/distribution)
|
||||||
|
// a small amount of tx fees can still end up here.
|
||||||
|
// dust should stay in x/distribution, but may not be the same so it's unchecked
|
||||||
|
distrCoinsAfter, distrDustAfter := distrBalAfter.Pool.TruncateDecimal()
|
||||||
|
suite.Empty(distrCoinsAfter, "expected no coins in x/distribution community pool")
|
||||||
|
|
||||||
|
// Fetch block results for paid staking rewards in the block
|
||||||
|
blockRes, err := suite.Kava.TmSignClient.BlockResults(
|
||||||
|
context.Background(),
|
||||||
|
&switchoverHeight,
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
stakingRewardPaidEvents := util.FilterEventsByType(
|
||||||
|
blockRes.BeginBlockEvents,
|
||||||
|
communitytypes.EventTypeStakingRewardsPaid,
|
||||||
|
)
|
||||||
|
suite.Require().Len(stakingRewardPaidEvents, 1, "there should be only 1 staking reward paid event")
|
||||||
|
stakingRewardAmount := sdk.NewCoins()
|
||||||
|
for _, attr := range stakingRewardPaidEvents[0].Attributes {
|
||||||
|
if string(attr.Key) == communitytypes.AttributeKeyStakingRewardAmount {
|
||||||
|
stakingRewardAmount, err = sdk.ParseCoinsNormalized(string(attr.Value))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expectedCommunityBal := beforeCommPoolBalance.Coins.
|
||||||
|
Add(distrBalCoinsBefore...).
|
||||||
|
Add(expectedKavadistTransferred...).
|
||||||
|
Sub(stakingRewardAmount...) // Remove staking rewards paid in the block
|
||||||
|
|
||||||
|
// x/kavadist and x/distribution community pools should be moved to x/community
|
||||||
|
suite.Equal(
|
||||||
|
expectedCommunityBal,
|
||||||
|
afterCommPoolBalance.Coins,
|
||||||
|
)
|
||||||
|
|
||||||
|
suite.Equal(
|
||||||
|
distrDustBefore,
|
||||||
|
distrDustAfter,
|
||||||
|
"x/distribution community pool dust should be unchanged",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
291
tests/e2e/e2e_upgrade_gov_and_authz_test.go
Normal file
291
tests/e2e/e2e_upgrade_gov_and_authz_test.go
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
package e2e_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
query "github.com/cosmos/cosmos-sdk/types/query"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/authz"
|
||||||
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
|
govv1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1"
|
||||||
|
|
||||||
|
"github.com/kava-labs/kava/tests/e2e/testutil"
|
||||||
|
"github.com/kava-labs/kava/tests/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
govModuleAcc = "kava10d07y265gmmuvt4z0w9aw880jnsr700jxh8cq5"
|
||||||
|
communityModuleAcc = "kava17d2wax0zhjrrecvaszuyxdf5wcu5a0p4qlx3t5"
|
||||||
|
kavadistModuleAcc = "kava1cj7njkw2g9fqx4e768zc75dp9sks8u9znxrf0w"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (suite *IntegrationTestSuite) TestGovParamChanges() {
|
||||||
|
suite.SkipIfUpgradeDisabled()
|
||||||
|
|
||||||
|
beforeUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight - 1)
|
||||||
|
afterUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight)
|
||||||
|
|
||||||
|
// fetch gov parameters before upgrade
|
||||||
|
govBeforeParams, err := suite.Kava.Gov.Params(beforeUpgradeCtx, &govv1.QueryParamsRequest{ParamsType: "tallying"})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// assert expected gov quorum before upgrade
|
||||||
|
suite.NotEqual(govBeforeParams.TallyParams.Quorum, "0.200000000000000000")
|
||||||
|
|
||||||
|
govAfterParams, err := suite.Kava.Gov.Params(afterUpgradeCtx, &govv1.QueryParamsRequest{ParamsType: "tallying"})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// assert expected gov quorum after upgrade
|
||||||
|
suite.Equal(govAfterParams.TallyParams.Quorum, "0.200000000000000000")
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *IntegrationTestSuite) TestAuthzParamChanges() {
|
||||||
|
suite.SkipIfUpgradeDisabled()
|
||||||
|
|
||||||
|
beforeUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight - 1)
|
||||||
|
afterUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight)
|
||||||
|
|
||||||
|
// fetch authz grants before upgrade
|
||||||
|
authzBeforeGrants, err := suite.Kava.Authz.Grants(beforeUpgradeCtx, &authz.QueryGrantsRequest{Granter: kavadistModuleAcc, Grantee: govModuleAcc, Pagination: &query.PageRequest{Limit: 1000, CountTotal: true}})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
suite.Require().Equal(authzBeforeGrants.Pagination.Total, uint64(len(authzBeforeGrants.Grants)), "expected all grants to have been requested")
|
||||||
|
|
||||||
|
// no kavadist -> gov grants
|
||||||
|
suite.Equal(0, len(authzBeforeGrants.Grants))
|
||||||
|
|
||||||
|
// fetch authz grants after upgrade
|
||||||
|
authzAfterGrants, err := suite.Kava.Authz.Grants(afterUpgradeCtx, &authz.QueryGrantsRequest{Granter: kavadistModuleAcc, Grantee: govModuleAcc, Pagination: &query.PageRequest{Limit: 1000, CountTotal: true}})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
suite.Require().Equal(authzAfterGrants.Pagination.Total, uint64(len(authzAfterGrants.Grants)), "expected all grants to have been requested")
|
||||||
|
|
||||||
|
// one kavadist -> gov grants
|
||||||
|
suite.Require().Equal(1, len(authzAfterGrants.Grants))
|
||||||
|
|
||||||
|
grant := authzAfterGrants.Grants[0]
|
||||||
|
|
||||||
|
var authorization authz.Authorization
|
||||||
|
suite.Kava.EncodingConfig.Marshaler.UnpackAny(grant.Authorization, &authorization)
|
||||||
|
|
||||||
|
genericAuthorization, ok := authorization.(*authz.GenericAuthorization)
|
||||||
|
suite.Require().True(ok, "expected generic authorization")
|
||||||
|
|
||||||
|
// kavadist allows gov to MsgSend it's funds
|
||||||
|
suite.Equal(sdk.MsgTypeURL(&banktypes.MsgSend{}), genericAuthorization.Msg)
|
||||||
|
// no expiration
|
||||||
|
var expectedExpiration *time.Time
|
||||||
|
suite.Equal(expectedExpiration, grant.Expiration)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *IntegrationTestSuite) TestModuleAccountGovTransfers() {
|
||||||
|
suite.SkipIfUpgradeDisabled()
|
||||||
|
suite.SkipIfKvtoolDisabled()
|
||||||
|
|
||||||
|
// the module account (authority) that executes the transfers
|
||||||
|
govAcc := sdk.MustAccAddressFromBech32(govModuleAcc)
|
||||||
|
|
||||||
|
// module accounts for gov transfer test cases
|
||||||
|
communityAcc := sdk.MustAccAddressFromBech32(communityModuleAcc)
|
||||||
|
kavadistAcc := sdk.MustAccAddressFromBech32(kavadistModuleAcc)
|
||||||
|
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
sender sdk.AccAddress
|
||||||
|
receiver sdk.AccAddress
|
||||||
|
amount sdk.Coin
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "transfer from community to kavadist for incentive rewards",
|
||||||
|
sender: communityAcc,
|
||||||
|
receiver: kavadistAcc,
|
||||||
|
amount: ukava(100e6),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "transfer from kavadist to community",
|
||||||
|
sender: kavadistAcc,
|
||||||
|
receiver: communityAcc,
|
||||||
|
amount: ukava(50e6),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
suite.Run(tc.name, func() {
|
||||||
|
// create msg exec for transfer between modules
|
||||||
|
msg := banktypes.NewMsgSend(
|
||||||
|
tc.sender,
|
||||||
|
tc.receiver,
|
||||||
|
sdk.NewCoins(tc.amount),
|
||||||
|
)
|
||||||
|
execMsg := authz.NewMsgExec(govAcc, []sdk.Msg{msg})
|
||||||
|
|
||||||
|
// ensure proposal passes
|
||||||
|
passBlock := suite.submitAndPassProposal([]sdk.Msg{&execMsg})
|
||||||
|
transfers := suite.getBankTransferAmountAtBlock(passBlock, tc.sender, tc.receiver)
|
||||||
|
|
||||||
|
suite.Require().Containsf(
|
||||||
|
transfers,
|
||||||
|
tc.amount,
|
||||||
|
"expected transfer of %s to be included in bank transfer events: %s",
|
||||||
|
tc.amount,
|
||||||
|
transfers,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (suite *IntegrationTestSuite) submitAndPassProposal(msgs []sdk.Msg) int64 {
|
||||||
|
govParamsRes, err := suite.Kava.Gov.Params(context.Background(), &govv1.QueryParamsRequest{
|
||||||
|
ParamsType: govv1.ParamDeposit,
|
||||||
|
})
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
kavaAcc := suite.Kava.GetAccount(testutil.FundedAccountName)
|
||||||
|
|
||||||
|
proposalMsg, err := govv1.NewMsgSubmitProposal(
|
||||||
|
msgs,
|
||||||
|
govParamsRes.DepositParams.MinDeposit,
|
||||||
|
kavaAcc.SdkAddress.String(),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
gasLimit := 1e6
|
||||||
|
fee := ukava(1000)
|
||||||
|
|
||||||
|
req := util.KavaMsgRequest{
|
||||||
|
Msgs: []sdk.Msg{proposalMsg},
|
||||||
|
GasLimit: uint64(gasLimit),
|
||||||
|
FeeAmount: sdk.NewCoins(fee),
|
||||||
|
Memo: "this is a proposal please accept me",
|
||||||
|
}
|
||||||
|
res := kavaAcc.SignAndBroadcastKavaTx(req)
|
||||||
|
suite.Require().NoError(res.Err)
|
||||||
|
|
||||||
|
// Wait for proposal to be submitted
|
||||||
|
txRes, err := util.WaitForSdkTxCommit(suite.Kava.Tx, res.Result.TxHash, 6*time.Second)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
var govRes govv1.MsgSubmitProposalResponse
|
||||||
|
suite.decodeTxMsgResponse(txRes, &govRes)
|
||||||
|
|
||||||
|
// 2. Vote for proposal from whale account
|
||||||
|
whale := suite.Kava.GetAccount(testutil.FundedAccountName)
|
||||||
|
voteMsg := govv1.NewMsgVote(
|
||||||
|
whale.SdkAddress,
|
||||||
|
govRes.ProposalId,
|
||||||
|
govv1.OptionYes,
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
|
||||||
|
voteReq := util.KavaMsgRequest{
|
||||||
|
Msgs: []sdk.Msg{voteMsg},
|
||||||
|
GasLimit: uint64(gasLimit),
|
||||||
|
FeeAmount: sdk.NewCoins(fee),
|
||||||
|
Memo: "voting",
|
||||||
|
}
|
||||||
|
voteRes := whale.SignAndBroadcastKavaTx(voteReq)
|
||||||
|
suite.Require().NoError(voteRes.Err)
|
||||||
|
|
||||||
|
_, err = util.WaitForSdkTxCommit(suite.Kava.Tx, voteRes.Result.TxHash, 6*time.Second)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// 3. Wait until proposal passes
|
||||||
|
suite.Require().Eventually(func() bool {
|
||||||
|
proposalRes, err := suite.Kava.Gov.Proposal(context.Background(), &govv1.QueryProposalRequest{
|
||||||
|
ProposalId: govRes.ProposalId,
|
||||||
|
})
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
switch status := proposalRes.Proposal.Status; status {
|
||||||
|
case govv1.StatusDepositPeriod, govv1.StatusVotingPeriod:
|
||||||
|
return false
|
||||||
|
case govv1.StatusPassed:
|
||||||
|
return true
|
||||||
|
case govv1.StatusFailed, govv1.StatusRejected:
|
||||||
|
suite.Failf("proposal failed", "proposal failed with status %s", status.String())
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}, 60*time.Second, 1*time.Second)
|
||||||
|
|
||||||
|
page := 1
|
||||||
|
perPage := 100
|
||||||
|
|
||||||
|
// Get the block the proposal was passed in
|
||||||
|
passBlock, err := suite.Kava.TmSignClient.BlockSearch(
|
||||||
|
context.Background(),
|
||||||
|
fmt.Sprintf(
|
||||||
|
"active_proposal.proposal_result = 'proposal_passed' AND active_proposal.proposal_id = %d",
|
||||||
|
govRes.ProposalId,
|
||||||
|
),
|
||||||
|
&page,
|
||||||
|
&perPage,
|
||||||
|
"asc",
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
suite.Require().Equal(1, len(passBlock.Blocks), "passed proposal should be searchable")
|
||||||
|
|
||||||
|
return passBlock.Blocks[len(passBlock.Blocks)-1].Block.Height
|
||||||
|
}
|
||||||
|
|
||||||
|
// getBankTransferAmountAtBlock returns the amount of coins transferred between
|
||||||
|
// the given accounts in the block at the given height. Note that this returns
|
||||||
|
// a slice of sdk.Coin that can contain multiple coins of the SAME denom -- ie. NOT sdk.Coins
|
||||||
|
func (suite *IntegrationTestSuite) getBankTransferAmountAtBlock(
|
||||||
|
blockHeight int64,
|
||||||
|
sender sdk.AccAddress,
|
||||||
|
receiver sdk.AccAddress,
|
||||||
|
) []sdk.Coin {
|
||||||
|
// Fetch block results for paid staking rewards in the block
|
||||||
|
blockRes, err := suite.Kava.TmSignClient.BlockResults(
|
||||||
|
context.Background(),
|
||||||
|
&blockHeight,
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
transferEvents := util.FilterEventsByType(
|
||||||
|
blockRes.EndBlockEvents, // gov proposals applied in EndBlocker
|
||||||
|
banktypes.EventTypeTransfer,
|
||||||
|
)
|
||||||
|
suite.Require().NotEmpty(transferEvents, "there should be at least 1 bank transfer event")
|
||||||
|
|
||||||
|
transfers := []sdk.Coin{}
|
||||||
|
|
||||||
|
event:
|
||||||
|
for _, event := range transferEvents {
|
||||||
|
if event.Type != banktypes.EventTypeTransfer {
|
||||||
|
suite.FailNowf(
|
||||||
|
"unexpected event type %s in block results",
|
||||||
|
event.Type,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, attr := range event.Attributes {
|
||||||
|
suite.T().Logf("event attr: %s = %s", string(attr.Key), string(attr.Value))
|
||||||
|
|
||||||
|
if string(attr.Key) == banktypes.AttributeKeyRecipient {
|
||||||
|
if string(attr.Value) != receiver.String() {
|
||||||
|
continue event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(attr.Key) == banktypes.AttributeKeySender {
|
||||||
|
if string(attr.Value) != sender.String() {
|
||||||
|
continue event
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if string(attr.Key) == sdk.AttributeKeyAmount {
|
||||||
|
amount, err := sdk.ParseCoinNormalized(string(attr.Value))
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
transfers = append(transfers, amount)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return transfers
|
||||||
|
}
|
65
tests/e2e/e2e_upgrade_incentive_test.go
Normal file
65
tests/e2e/e2e_upgrade_incentive_test.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package e2e_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
sdkmath "cosmossdk.io/math"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
|
||||||
|
"github.com/kava-labs/kava/tests/util"
|
||||||
|
incentivetypes "github.com/kava-labs/kava/x/incentive/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (suite *IntegrationTestSuite) TestUpgradeIncentiveParams() {
|
||||||
|
suite.SkipIfUpgradeDisabled()
|
||||||
|
|
||||||
|
beforeUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight - 1)
|
||||||
|
afterUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight)
|
||||||
|
|
||||||
|
// Before params
|
||||||
|
incentiveParamsBefore, err := suite.Kava.Incentive.Params(
|
||||||
|
beforeUpgradeCtx,
|
||||||
|
&incentivetypes.QueryParamsRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
incentiveParamsAfter, err := suite.Kava.Incentive.Params(
|
||||||
|
afterUpgradeCtx,
|
||||||
|
&incentivetypes.QueryParamsRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
|
||||||
|
suite.Run("x/incentive parameters before upgrade", func() {
|
||||||
|
suite.Require().Len(
|
||||||
|
incentiveParamsBefore.Params.EarnRewardPeriods,
|
||||||
|
1,
|
||||||
|
"x/incentive should have 1 earn reward period before upgrade",
|
||||||
|
)
|
||||||
|
|
||||||
|
suite.Require().Equal(
|
||||||
|
sdk.NewCoins(sdk.NewCoin("ukava", sdk.NewInt(159_459))),
|
||||||
|
incentiveParamsBefore.Params.EarnRewardPeriods[0].RewardsPerSecond,
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
suite.Run("x/incentive parameters after upgrade", func() {
|
||||||
|
suite.Require().Len(
|
||||||
|
incentiveParamsAfter.Params.EarnRewardPeriods,
|
||||||
|
1,
|
||||||
|
"x/incentive should have 1 earn reward period before upgrade",
|
||||||
|
)
|
||||||
|
|
||||||
|
suite.Require().Equal(
|
||||||
|
// Manual calculation of
|
||||||
|
// 600,000 * 1000,000 / (365 * 24 * 60 * 60)
|
||||||
|
sdk.NewCoins(sdk.NewCoin("ukava", sdkmath.NewInt(19025))),
|
||||||
|
incentiveParamsAfter.Params.EarnRewardPeriods[0].RewardsPerSecond,
|
||||||
|
)
|
||||||
|
|
||||||
|
// No other changes
|
||||||
|
incentiveParamsAfter.Params.EarnRewardPeriods[0].RewardsPerSecond = incentiveParamsBefore.Params.EarnRewardPeriods[0].RewardsPerSecond
|
||||||
|
suite.Require().Equal(
|
||||||
|
incentiveParamsBefore,
|
||||||
|
incentiveParamsAfter,
|
||||||
|
"other param values should not be changed",
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
474
tests/e2e/e2e_upgrade_inflation_test.go
Normal file
474
tests/e2e/e2e_upgrade_inflation_test.go
Normal file
@ -0,0 +1,474 @@
|
|||||||
|
package e2e_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strconv"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
sdkmath "cosmossdk.io/math"
|
||||||
|
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
|
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
|
||||||
|
minttypes "github.com/cosmos/cosmos-sdk/x/mint/types"
|
||||||
|
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||||
|
abci "github.com/tendermint/tendermint/abci/types"
|
||||||
|
coretypes "github.com/tendermint/tendermint/rpc/core/types"
|
||||||
|
|
||||||
|
"github.com/kava-labs/kava/tests/util"
|
||||||
|
communitytypes "github.com/kava-labs/kava/x/community/types"
|
||||||
|
kavadisttypes "github.com/kava-labs/kava/x/kavadist/types"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (suite *IntegrationTestSuite) TestUpgradeInflation_Disable() {
|
||||||
|
suite.SkipIfUpgradeDisabled()
|
||||||
|
|
||||||
|
afterUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight)
|
||||||
|
|
||||||
|
// Get x/community for switchover time
|
||||||
|
params, err := suite.Kava.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.Kava.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.Kava.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.Kava.Mint.Params(
|
||||||
|
beforeSwitchoverCtx,
|
||||||
|
&minttypes.QueryParamsRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
kavaDistParams, err := suite.Kava.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.Kava.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.Kava.Mint.Params(
|
||||||
|
afterSwitchoverCtx,
|
||||||
|
&minttypes.QueryParamsRequest{},
|
||||||
|
)
|
||||||
|
suite.NoError(err)
|
||||||
|
kavaDistParams, err := suite.Kava.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.Kava.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.Kava.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.Kava.Bank.SupplyOf(
|
||||||
|
util.CtxAtHeight(queryHeight),
|
||||||
|
&types.QuerySupplyOfRequest{
|
||||||
|
Denom: suite.Kava.StakingDenom,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.NotZero(supply1.Amount, "ukava supply should be non-zero")
|
||||||
|
|
||||||
|
// Next block
|
||||||
|
queryHeight += 1
|
||||||
|
supply2, err := suite.Kava.Bank.SupplyOf(
|
||||||
|
util.CtxAtHeight(queryHeight),
|
||||||
|
&types.QuerySupplyOfRequest{
|
||||||
|
Denom: suite.Kava.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.Kava.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.Kava.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.Kava.Bank.SupplyOf(
|
||||||
|
util.CtxAtHeight(queryHeight),
|
||||||
|
&types.QuerySupplyOfRequest{
|
||||||
|
Denom: suite.Kava.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.Kava.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.Kava.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.Kava.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.Kava.Bank.Balance(
|
||||||
|
context.Background(),
|
||||||
|
&types.QueryBalanceRequest{
|
||||||
|
Address: accAddr.String(),
|
||||||
|
Denom: suite.Kava.StakingDenom,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
suite.Require().False(balBefore.Balance.IsZero(), "val staking denom balance should be non-zero")
|
||||||
|
|
||||||
|
delegationRewards, err := suite.Kava.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.Kava.Keyring.(unsafeExporter).ExportPrivateKeyObject(
|
||||||
|
"validator",
|
||||||
|
)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
acc := suite.Kava.AddNewSigningAccountFromPrivKey(
|
||||||
|
"validator",
|
||||||
|
key,
|
||||||
|
"",
|
||||||
|
suite.Kava.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.Kava.Tx, res.Result.TxHash, 6*time.Second)
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
balAfter, err := suite.Kava.Bank.Balance(
|
||||||
|
context.Background(),
|
||||||
|
&types.QueryBalanceRequest{
|
||||||
|
Address: accAddr.String(),
|
||||||
|
Denom: suite.Kava.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.Kava.StakingDenom).
|
||||||
|
LTE(balIncrease.Amount),
|
||||||
|
"claimed rewards should be >= queried delegation rewards, got claimed %s vs queried %s",
|
||||||
|
balIncrease.Amount.String(),
|
||||||
|
queriedRewardsCoins.AmountOf(suite.Kava.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)
|
||||||
|
}
|
103
tests/e2e/e2e_upgrade_min_commission_test.go
Normal file
103
tests/e2e/e2e_upgrade_min_commission_test.go
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
package e2e_test
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
sdkmath "cosmossdk.io/math"
|
||||||
|
"github.com/cosmos/cosmos-sdk/client/grpc/tmservice"
|
||||||
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
|
"github.com/cosmos/cosmos-sdk/x/staking/types"
|
||||||
|
|
||||||
|
"github.com/kava-labs/kava/tests/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (suite *IntegrationTestSuite) TestValMinCommission() {
|
||||||
|
suite.SkipIfUpgradeDisabled()
|
||||||
|
|
||||||
|
beforeUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight - 1)
|
||||||
|
afterUpgradeCtx := util.CtxAtHeight(suite.UpgradeHeight)
|
||||||
|
|
||||||
|
suite.Run("before upgrade", func() {
|
||||||
|
// Before params
|
||||||
|
beforeParams, err := suite.Kava.Staking.Params(beforeUpgradeCtx, &types.QueryParamsRequest{})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
suite.Require().Equal(
|
||||||
|
sdkmath.LegacyZeroDec().String(),
|
||||||
|
beforeParams.Params.MinCommissionRate.String(),
|
||||||
|
"min commission rate should be 0%% before upgrade",
|
||||||
|
)
|
||||||
|
|
||||||
|
// Before validators
|
||||||
|
beforeValidators, err := suite.Kava.Staking.Validators(beforeUpgradeCtx, &types.QueryValidatorsRequest{})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
for _, val := range beforeValidators.Validators {
|
||||||
|
// In kvtool gentx, the commission rate is set to 0, with max of 0.01
|
||||||
|
expectedRate := sdkmath.LegacyZeroDec()
|
||||||
|
expectedRateMax := sdkmath.LegacyMustNewDecFromStr("0.01")
|
||||||
|
|
||||||
|
suite.Require().Equalf(
|
||||||
|
expectedRate.String(),
|
||||||
|
val.Commission.CommissionRates.Rate.String(),
|
||||||
|
"validator %s should have commission rate of %s before upgrade",
|
||||||
|
val.OperatorAddress,
|
||||||
|
expectedRate,
|
||||||
|
)
|
||||||
|
|
||||||
|
suite.Require().Equalf(
|
||||||
|
expectedRateMax.String(),
|
||||||
|
val.Commission.CommissionRates.MaxRate.String(),
|
||||||
|
"validator %s should have max commission rate of %s before upgrade",
|
||||||
|
val.OperatorAddress,
|
||||||
|
expectedRateMax,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
suite.Run("after upgrade", func() {
|
||||||
|
block, err := suite.Kava.Tm.GetBlockByHeight(context.Background(), &tmservice.GetBlockByHeightRequest{
|
||||||
|
Height: suite.UpgradeHeight,
|
||||||
|
})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
// After params
|
||||||
|
afterParams, err := suite.Kava.Staking.Params(afterUpgradeCtx, &types.QueryParamsRequest{})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
expectedMinRate := sdk.MustNewDecFromStr("0.05")
|
||||||
|
|
||||||
|
suite.Require().Equal(
|
||||||
|
expectedMinRate.String(),
|
||||||
|
afterParams.Params.MinCommissionRate.String(),
|
||||||
|
"min commission rate should be 5%% after upgrade",
|
||||||
|
)
|
||||||
|
|
||||||
|
// After validators
|
||||||
|
afterValidators, err := suite.Kava.Staking.Validators(afterUpgradeCtx, &types.QueryValidatorsRequest{})
|
||||||
|
suite.Require().NoError(err)
|
||||||
|
|
||||||
|
for _, val := range afterValidators.Validators {
|
||||||
|
|
||||||
|
suite.Require().Truef(
|
||||||
|
val.Commission.CommissionRates.Rate.GTE(expectedMinRate),
|
||||||
|
"validator %s should have commission rate of at least 5%%",
|
||||||
|
val.OperatorAddress,
|
||||||
|
)
|
||||||
|
|
||||||
|
suite.Require().Truef(
|
||||||
|
val.Commission.CommissionRates.MaxRate.GTE(expectedMinRate),
|
||||||
|
"validator %s should have max commission rate of at least 5%%",
|
||||||
|
val.OperatorAddress,
|
||||||
|
)
|
||||||
|
|
||||||
|
suite.Require().Truef(
|
||||||
|
val.Commission.UpdateTime.Equal(block.SdkBlock.Header.Time),
|
||||||
|
"validator %s should have commission update time set to block time, expected %s, got %s",
|
||||||
|
val.OperatorAddress,
|
||||||
|
block.SdkBlock.Header.Time,
|
||||||
|
val.Commission.UpdateTime,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
@ -14,6 +14,7 @@ import (
|
|||||||
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
||||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||||
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
||||||
|
authz "github.com/cosmos/cosmos-sdk/x/authz"
|
||||||
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
|
||||||
evmhd "github.com/evmos/ethermint/crypto/hd"
|
evmhd "github.com/evmos/ethermint/crypto/hd"
|
||||||
|
|
||||||
@ -26,6 +27,13 @@ import (
|
|||||||
"github.com/kava-labs/kava/client/grpc"
|
"github.com/kava-labs/kava/client/grpc"
|
||||||
"github.com/kava-labs/kava/tests/e2e/runner"
|
"github.com/kava-labs/kava/tests/e2e/runner"
|
||||||
"github.com/kava-labs/kava/tests/util"
|
"github.com/kava-labs/kava/tests/util"
|
||||||
|
cdptypes "github.com/kava-labs/kava/x/cdp/types"
|
||||||
|
committeetypes "github.com/kava-labs/kava/x/committee/types"
|
||||||
|
communitytypes "github.com/kava-labs/kava/x/community/types"
|
||||||
|
earntypes "github.com/kava-labs/kava/x/earn/types"
|
||||||
|
evmutiltypes "github.com/kava-labs/kava/x/evmutil/types"
|
||||||
|
incentivetypes "github.com/kava-labs/kava/x/incentive/types"
|
||||||
|
kavadisttypes "github.com/kava-labs/kava/x/kavadist/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Chain wraps query clients & accounts for a network
|
// Chain wraps query clients & accounts for a network
|
||||||
@ -43,6 +51,25 @@ type Chain struct {
|
|||||||
|
|
||||||
EncodingConfig kavaparams.EncodingConfig
|
EncodingConfig kavaparams.EncodingConfig
|
||||||
|
|
||||||
|
Auth authtypes.QueryClient
|
||||||
|
Authz authz.QueryClient
|
||||||
|
Bank banktypes.QueryClient
|
||||||
|
Cdp cdptypes.QueryClient
|
||||||
|
Committee committeetypes.QueryClient
|
||||||
|
Community communitytypes.QueryClient
|
||||||
|
Distribution distrtypes.QueryClient
|
||||||
|
Incentive incentivetypes.QueryClient
|
||||||
|
Kavadist kavadisttypes.QueryClient
|
||||||
|
Earn earntypes.QueryClient
|
||||||
|
Evm evmtypes.QueryClient
|
||||||
|
Evmutil evmutiltypes.QueryClient
|
||||||
|
Gov govv1types.QueryClient
|
||||||
|
Mint minttypes.QueryClient
|
||||||
|
Staking stakingtypes.QueryClient
|
||||||
|
Tm tmservice.ServiceClient
|
||||||
|
Tx txtypes.ServiceClient
|
||||||
|
Upgrade upgradetypes.QueryClient
|
||||||
|
|
||||||
TmSignClient tmclient.SignClient
|
TmSignClient tmclient.SignClient
|
||||||
|
|
||||||
Grpc *grpc.KavaGrpcClient
|
Grpc *grpc.KavaGrpcClient
|
||||||
@ -91,6 +118,25 @@ func NewChain(t *testing.T, details *runner.ChainDetails, fundedAccountMnemonic
|
|||||||
return chain, err
|
return chain, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chain.Auth = authtypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Authz = authz.NewQueryClient(grpcConn)
|
||||||
|
chain.Bank = banktypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Cdp = cdptypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Committee = committeetypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Community = communitytypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Distribution = distrtypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Incentive = incentivetypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Kavadist = kavadisttypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Earn = earntypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Evm = evmtypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Evmutil = evmutiltypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Gov = govv1types.NewQueryClient(grpcConn)
|
||||||
|
chain.Mint = minttypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Staking = stakingtypes.NewQueryClient(grpcConn)
|
||||||
|
chain.Tm = tmservice.NewServiceClient(grpcConn)
|
||||||
|
chain.Tx = txtypes.NewServiceClient(grpcConn)
|
||||||
|
chain.Upgrade = upgradetypes.NewQueryClient(grpcConn)
|
||||||
|
|
||||||
// initialize accounts map
|
// initialize accounts map
|
||||||
chain.accounts = make(map[string]*SigningAccount)
|
chain.accounts = make(map[string]*SigningAccount)
|
||||||
// setup the signing account for the initially funded account (used to fund all other accounts)
|
// setup the signing account for the initially funded account (used to fund all other accounts)
|
||||||
@ -179,6 +225,21 @@ func (chain *Chain) QuerySdkForBalances(addr sdk.AccAddress) sdk.Coins {
|
|||||||
return res.Balances
|
return res.Balances
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// QuerySdkForBalancesAtHeight gets the balance of a particular address on this Chain, at the specified height.
|
||||||
|
func (chain *Chain) QuerySdkForBalancesAtHeight(
|
||||||
|
height int64,
|
||||||
|
addr sdk.AccAddress,
|
||||||
|
) sdk.Coins {
|
||||||
|
res, err := chain.Bank.AllBalances(
|
||||||
|
util.CtxAtHeight(height),
|
||||||
|
&banktypes.QueryAllBalancesRequest{
|
||||||
|
Address: addr.String(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
require.NoError(chain.t, err)
|
||||||
|
return res.Balances
|
||||||
|
}
|
||||||
|
|
||||||
// GetModuleBalances returns the balance of a requested module account
|
// GetModuleBalances returns the balance of a requested module account
|
||||||
func (chain *Chain) GetModuleBalances(moduleName string) sdk.Coins {
|
func (chain *Chain) GetModuleBalances(moduleName string) sdk.Coins {
|
||||||
addr := authtypes.NewModuleAddress(moduleName)
|
addr := authtypes.NewModuleAddress(moduleName)
|
||||||
|
Loading…
Reference in New Issue
Block a user