diff --git a/.changelog/unreleased/improvements/provider/1929-distribute-rewards-to-long-term-validating-validators.md b/.changelog/unreleased/improvements/provider/1929-distribute-rewards-to-long-term-validating-validators.md new file mode 100644 index 0000000000..b4ff9d6341 --- /dev/null +++ b/.changelog/unreleased/improvements/provider/1929-distribute-rewards-to-long-term-validating-validators.md @@ -0,0 +1,3 @@ +- Only start distributing rewards to validators after they have been validating + for a fixed number of blocks. Introduces the `NumberOfEpochsToStartReceivingRewards` param. + ([\#1929](https://github.com/cosmos/interchain-security/pull/1929)) diff --git a/.changelog/unreleased/state-breaking/provider/1929-distribute-rewards-to-long-term-validating-validators.md b/.changelog/unreleased/state-breaking/provider/1929-distribute-rewards-to-long-term-validating-validators.md new file mode 100644 index 0000000000..b4ff9d6341 --- /dev/null +++ b/.changelog/unreleased/state-breaking/provider/1929-distribute-rewards-to-long-term-validating-validators.md @@ -0,0 +1,3 @@ +- Only start distributing rewards to validators after they have been validating + for a fixed number of blocks. Introduces the `NumberOfEpochsToStartReceivingRewards` param. + ([\#1929](https://github.com/cosmos/interchain-security/pull/1929)) diff --git a/docs/docs/validators/withdraw_rewards.md b/docs/docs/validators/withdraw_rewards.md index 1a9ab1fb3c..15d27b3006 100644 --- a/docs/docs/validators/withdraw_rewards.md +++ b/docs/docs/validators/withdraw_rewards.md @@ -2,8 +2,17 @@ sidebar_position: 3 --- -# Withdrawing consumer chain validator rewards +# Consumer chain validator rewards +:::warning +A validator can only receive rewards from a consumer chain if the validator has been validating the consumer chain +for some time. Specifically, the validator has to be a consumer validator of the consumer chain for at least +`NumberOfEpochsToStartReceivingRewards * BlocksPerEpoch` blocks (run `interchain-security-pd query provider params` for +the actual values of the `NumberOfEpochsToStartReceivingRewards` and `BlocksPerEpoch` params). +::: + + +## Withdrawing rewards Here are example steps for withdrawing rewards from consumer chains in the provider chain :::info diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index 2a25eb533f..e31b3a150f 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -243,6 +243,9 @@ message Params { // The number of blocks that comprise an epoch. int64 blocks_per_epoch = 10; + + // The number of epochs a validator has to validate a consumer chain in order to start receiving rewards from that chain. + int64 number_of_epochs_to_start_receiving_rewards = 11; } // SlashAcks contains cons addresses of consumer chain validators @@ -360,6 +363,11 @@ message ConsumerValidator { int64 power = 2; // public key the validator uses on the consumer chain during this epoch tendermint.crypto.PublicKey consumer_public_key = 3; + // height the validator had when it FIRST became a consumer validator + // If a validator becomes a consumer validator at height `H` and is continuously a consumer validator for all the upcoming + // epochs, then the height of the validator SHOULD remain `H`. This height only resets to a different height if a validator + // stops being a consumer validator during an epoch and later becomes again a consumer validator. + int64 join_height = 4; } // ConsumerRewardsAllocation stores the rewards allocated by a consumer chain // to the consumer rewards pool. It is used to allocate the tokens to the consumer diff --git a/tests/integration/distribution.go b/tests/integration/distribution.go index 8229850a63..2bea909c75 100644 --- a/tests/integration/distribution.go +++ b/tests/integration/distribution.go @@ -705,9 +705,14 @@ func (s *CCVTestSuite) TestAllocateTokens() { totalRewards := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(100))} + // increase the block height so validators are eligible for consumer rewards (see `IsEligibleForConsumerRewards`) + numberOfBlocksToStartReceivingRewards := + providerKeeper.GetNumberOfEpochsToStartReceivingRewards(s.providerCtx()) * providerKeeper.GetBlocksPerEpoch(s.providerCtx()) + providerCtx := s.providerCtx().WithBlockHeight(numberOfBlocksToStartReceivingRewards + s.providerCtx().BlockHeight()) + // fund consumer rewards pool bankKeeper.SendCoinsFromAccountToModule( - s.providerCtx(), + providerCtx, s.providerChain.SenderAccount.GetAddress(), providertypes.ConsumerRewardsPool, totalRewards, @@ -718,7 +723,7 @@ func (s *CCVTestSuite) TestAllocateTokens() { for chainID := range s.consumerBundles { // update consumer allocation providerKeeper.SetConsumerRewardsAllocation( - s.providerCtx(), + providerCtx, chainID, providertypes.ConsumerRewardsAllocation{ Rewards: sdk.NewDecCoinsFromCoins(rewardsPerConsumer...), @@ -738,16 +743,16 @@ func (s *CCVTestSuite) TestAllocateTokens() { }, ) - valRewards := distributionKeeper.GetValidatorOutstandingRewards(s.providerCtx(), sdk.ValAddress(val.Address)) + valRewards := distributionKeeper.GetValidatorOutstandingRewards(providerCtx, sdk.ValAddress(val.Address)) lastValOutRewards[sdk.ValAddress(val.Address).String()] = valRewards.Rewards } // store community pool balance - lastCommPool := distributionKeeper.GetFeePoolCommunityCoins(s.providerCtx()) + lastCommPool := distributionKeeper.GetFeePoolCommunityCoins(providerCtx) // execute BeginBlock to trigger the token allocation providerKeeper.BeginBlockRD( - s.providerCtx(), + providerCtx, abci.RequestBeginBlock{ LastCommitInfo: abci.CommitInfo{ Votes: votes, @@ -760,7 +765,7 @@ func (s *CCVTestSuite) TestAllocateTokens() { // compute the expected validators token allocation by subtracting the community tax rewardsPerConsumerDec := sdk.NewDecCoinsFromCoins(rewardsPerConsumer...) - communityTax := distributionKeeper.GetCommunityTax(s.providerCtx()) + communityTax := distributionKeeper.GetCommunityTax(providerCtx) validatorsExpRewards := rewardsPerConsumerDec. MulDecTruncate(math.LegacyOneDec().Sub(communityTax)). // multiply by the number of consumers since all the validators opted in @@ -770,7 +775,7 @@ func (s *CCVTestSuite) TestAllocateTokens() { // verify the validator tokens allocation // note that the validators have the same voting power to keep things simple for _, val := range s.providerChain.Vals.Validators { - valRewards := distributionKeeper.GetValidatorOutstandingRewards(s.providerCtx(), sdk.ValAddress(val.Address)) + valRewards := distributionKeeper.GetValidatorOutstandingRewards(providerCtx, sdk.ValAddress(val.Address)) s.Require().Equal( valRewards.Rewards, lastValOutRewards[sdk.ValAddress(val.Address).String()].Add(perValExpReward...), @@ -778,7 +783,7 @@ func (s *CCVTestSuite) TestAllocateTokens() { } commPoolExpRewards := sdk.NewDecCoinsFromCoins(totalRewards...).Sub(validatorsExpRewards) - currCommPool := distributionKeeper.GetFeePoolCommunityCoins(s.providerCtx()) + currCommPool := distributionKeeper.GetFeePoolCommunityCoins(providerCtx) s.Require().Equal(currCommPool, (lastCommPool.Add(commPoolExpRewards...))) } @@ -935,7 +940,7 @@ func (s *CCVTestSuite) prepareRewardDist() { s.coordinator.CommitNBlocks(s.consumerChain, uint64(blocksToGo)) } -func (s *CCVTestSuite) TestAllocateTokensToValidator() { +func (s *CCVTestSuite) TestAllocateTokensToConsumerValidators() { providerKeeper := s.providerApp.GetProviderKeeper() distributionKeeper := s.providerApp.GetTestDistributionKeeper() bankKeeper := s.providerApp.GetTestBankKeeper() @@ -981,6 +986,10 @@ func (s *CCVTestSuite) TestAllocateTokensToValidator() { s.Run(tc.name, func() { ctx, _ := s.providerCtx().CacheContext() + // increase the block height so validators are eligible for consumer rewards (see `IsEligibleForConsumerRewards`) + ctx = ctx.WithBlockHeight(providerKeeper.GetNumberOfEpochsToStartReceivingRewards(ctx)*providerKeeper.GetBlocksPerEpoch(ctx) + + ctx.BlockHeight()) + // change the consumer valset consuVals := providerKeeper.GetConsumerValSet(ctx, chainID) providerKeeper.DeleteConsumerValSet(ctx, chainID) @@ -1061,6 +1070,114 @@ func (s *CCVTestSuite) TestAllocateTokensToValidator() { } } +// TestAllocateTokensToConsumerValidatorsWithDifferentValidatorHeights tests `AllocateTokensToConsumerValidators` with +// consumer validators that have different heights. Specifically, test that validators that have been consumer validators +// for some time receive rewards, while validators that recently became consumer validators do not receive rewards. +func (s *CCVTestSuite) TestAllocateTokensToConsumerValidatorsWithDifferentValidatorHeights() { + // Note this test is an adaptation of a `TestAllocateTokensToConsumerValidators` testcase. + providerKeeper := s.providerApp.GetProviderKeeper() + distributionKeeper := s.providerApp.GetTestDistributionKeeper() + bankKeeper := s.providerApp.GetTestBankKeeper() + + chainID := s.consumerChain.ChainID + + tokens := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyNewDecFromIntWithPrec(math.NewInt(999), 2))} + rate := sdk.OneDec() + expAllocated := sdk.DecCoins{sdk.NewDecCoinFromDec(sdk.DefaultBondDenom, math.LegacyNewDecFromIntWithPrec(math.NewInt(999), 2))} + + ctx, _ := s.providerCtx().CacheContext() + // If the provider chain has not yet reached `GetNumberOfEpochsToStartReceivingRewards * GetBlocksPerEpoch` block height, + // then all validators receive rewards (see `IsEligibleForConsumerRewards`). In this test, we want to check whether + // validators receive rewards or not based on how long they have been consumer validators. Because of this, we increase the block height. + ctx = ctx.WithBlockHeight(providerKeeper.GetNumberOfEpochsToStartReceivingRewards(ctx)*providerKeeper.GetBlocksPerEpoch(ctx) + 1) + + // update the consumer validators + consuVals := providerKeeper.GetConsumerValSet(ctx, chainID) + // first 2 validators were consumer validators since block height 1 and hence get rewards + consuVals[0].JoinHeight = 1 + consuVals[1].JoinHeight = 1 + // last 2 validators were consumer validators since block height 2 and hence do not get rewards because they + // have not been consumer validators for `GetNumberOfEpochsToStartReceivingRewards * GetBlocksPerEpoch` blocks + consuVals[2].JoinHeight = 2 + consuVals[3].JoinHeight = 2 + providerKeeper.SetConsumerValSet(ctx, chainID, consuVals) + + providerKeeper.DeleteConsumerValSet(ctx, chainID) + providerKeeper.SetConsumerValSet(ctx, chainID, consuVals) + consuVals = providerKeeper.GetConsumerValSet(ctx, chainID) + + // set the same consumer commission rate for all consumer validators + for _, v := range consuVals { + provAddr := providertypes.NewProviderConsAddress(sdk.ConsAddress(v.ProviderConsAddr)) + err := providerKeeper.SetConsumerCommissionRate( + ctx, + chainID, + provAddr, + rate, + ) + s.Require().NoError(err) + } + + // allocate tokens + res := providerKeeper.AllocateTokensToConsumerValidators( + ctx, + chainID, + tokens, + ) + + // check that the expected result is returned + s.Require().Equal(expAllocated, res) + + // rewards are expected to be allocated evenly between validators 3 and 4 + rewardsPerVal := expAllocated.QuoDec(sdk.NewDec(int64(2))) + + // assert that the rewards are allocated to the first 2 validators + for _, v := range consuVals[0:2] { + valAddr := sdk.ValAddress(v.ProviderConsAddr) + rewards := s.providerApp.GetTestDistributionKeeper().GetValidatorOutstandingRewards( + ctx, + valAddr, + ) + s.Require().Equal(rewardsPerVal, rewards.Rewards) + + // send rewards to the distribution module + valRewardsTrunc, _ := rewards.Rewards.TruncateDecimal() + err := bankKeeper.SendCoinsFromAccountToModule( + ctx, + s.providerChain.SenderAccount.GetAddress(), + distrtypes.ModuleName, + valRewardsTrunc) + s.Require().NoError(err) + + // check that validators can withdraw their rewards + withdrawnCoins, err := distributionKeeper.WithdrawValidatorCommission( + ctx, + valAddr, + ) + s.Require().NoError(err) + + // check that the withdrawn coins is equal to the entire reward amount + // times the set consumer commission rate + commission := rewards.Rewards.MulDec(rate) + c, _ := commission.TruncateDecimal() + s.Require().Equal(withdrawnCoins, c) + + // check that validators get rewards in their balance + s.Require().Equal(withdrawnCoins, bankKeeper.GetAllBalances(ctx, sdk.AccAddress(valAddr))) + } + + // assert that no rewards are allocated to the last 2 validators because they have not been consumer validators + // for at least `GetNumberOfEpochsToStartReceivingRewards * GetBlocksPerEpoch` blocks + for _, v := range consuVals[2:4] { + valAddr := sdk.ValAddress(v.ProviderConsAddr) + rewards := s.providerApp.GetTestDistributionKeeper().GetValidatorOutstandingRewards( + ctx, + valAddr, + ) + s.Require().Zero(rewards.Rewards) + } +} + // TestMultiConsumerRewardsDistribution tests the rewards distribution of multiple consumers chains func (s *CCVTestSuite) TestMultiConsumerRewardsDistribution() { s.SetupAllCCVChannels() diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index 7d875b7c38..2259e472d1 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -127,6 +127,15 @@ func (k Keeper) AllocateTokens(ctx sdk.Context) { } } +// IsEligibleForConsumerRewards returns `true` if the validator with `consumerValidatorHeight` has been a consumer +// validator for a long period of time and hence is eligible to receive rewards, and false otherwise +func (k Keeper) IsEligibleForConsumerRewards(ctx sdk.Context, consumerValidatorHeight int64) bool { + numberOfBlocksToStartReceivingRewards := k.GetNumberOfEpochsToStartReceivingRewards(ctx) * k.GetBlocksPerEpoch(ctx) + + // a validator is eligible for rewards if it has been a consumer validator for `NumberOfEpochsToStartReceivingRewards` epochs + return (ctx.BlockHeight() - consumerValidatorHeight) >= numberOfBlocksToStartReceivingRewards +} + // AllocateTokensToConsumerValidators allocates tokens // to the given consumer chain's validator set func (k Keeper) AllocateTokensToConsumerValidators( @@ -147,6 +156,11 @@ func (k Keeper) AllocateTokensToConsumerValidators( // Allocate tokens by iterating over the consumer validators for _, consumerVal := range k.GetConsumerValSet(ctx, chainID) { + // if a validator is not eligible, this means that the other eligible validators would get more rewards + if !k.IsEligibleForConsumerRewards(ctx, consumerVal.JoinHeight) { + continue + } + consAddr := sdk.ConsAddress(consumerVal.ProviderConsAddr) // get the validator tokens fraction using its voting power @@ -240,6 +254,12 @@ func (k Keeper) GetConsumerRewardsPool(ctx sdk.Context) sdk.Coins { func (k Keeper) ComputeConsumerTotalVotingPower(ctx sdk.Context, chainID string) (totalPower int64) { // sum the consumer validators set voting powers for _, v := range k.GetConsumerValSet(ctx, chainID) { + + // only consider the voting power of a validator that would receive rewards (i.e., validator has been validating for a number of blocks) + if !k.IsEligibleForConsumerRewards(ctx, v.JoinHeight) { + continue + } + totalPower += v.Power } diff --git a/x/ccv/provider/keeper/distribution_test.go b/x/ccv/provider/keeper/distribution_test.go index d95ae598c0..2c80b418b0 100644 --- a/x/ccv/provider/keeper/distribution_test.go +++ b/x/ccv/provider/keeper/distribution_test.go @@ -23,6 +23,14 @@ func TestComputeConsumerTotalVotingPower(t *testing.T) { keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() + // `ComputeConsumerTotalVotingPower` used in this test retrieves the blocks per epoch, so we need to set this param + params := providertypes.DefaultParams() + params.BlocksPerEpoch = 1 + keeper.SetParams(ctx, params) + + // increase the block height so validators are eligible for consumer rewards (see `IsEligibleForConsumerRewards`) + ctx = ctx.WithBlockHeight(params.NumberOfEpochsToStartReceivingRewards * params.BlocksPerEpoch) + createVal := func(power int64) tmtypes.Validator { signer := tmtypes.NewMockPV() val := tmtypes.NewValidator(signer.PrivKey.PubKey(), power) @@ -270,3 +278,21 @@ func TestGetConsumerRewardsAllocationNil(t *testing.T) { } require.Equal(t, expectedRewardAllocation, alloc) } + +func TestIsEligibleForConsumerRewards(t *testing.T) { + keeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + params := providertypes.DefaultParams() + params.NumberOfEpochsToStartReceivingRewards = 10 + params.BlocksPerEpoch = 5 + keeper.SetParams(ctx, params) + + numberOfBlocks := params.NumberOfEpochsToStartReceivingRewards * params.BlocksPerEpoch + + require.False(t, keeper.IsEligibleForConsumerRewards(ctx.WithBlockHeight(numberOfBlocks-1), 0)) + require.True(t, keeper.IsEligibleForConsumerRewards(ctx.WithBlockHeight(numberOfBlocks), 0)) + require.True(t, keeper.IsEligibleForConsumerRewards(ctx.WithBlockHeight(numberOfBlocks+1), 0)) + require.True(t, keeper.IsEligibleForConsumerRewards(ctx.WithBlockHeight(numberOfBlocks+1), 1)) + require.False(t, keeper.IsEligibleForConsumerRewards(ctx.WithBlockHeight(numberOfBlocks+1), 2)) +} diff --git a/x/ccv/provider/keeper/params.go b/x/ccv/provider/keeper/params.go index f74baf656e..b5854e5b59 100644 --- a/x/ccv/provider/keeper/params.go +++ b/x/ccv/provider/keeper/params.go @@ -85,6 +85,14 @@ func (k Keeper) GetBlocksPerEpoch(ctx sdk.Context) int64 { return b } +// GetNumberOfEpochsToStartReceivingRewards returns the number of epochs needed by a validator to continuously validate +// to start receiving rewards +func (k Keeper) GetNumberOfEpochsToStartReceivingRewards(ctx sdk.Context) int64 { + var b int64 + k.paramSpace.Get(ctx, types.KeyNumberOfEpochsToStartReceivingRewards, &b) + return b +} + // GetParams returns the paramset for the provider module func (k Keeper) GetParams(ctx sdk.Context) types.Params { return types.NewParams( @@ -97,6 +105,7 @@ func (k Keeper) GetParams(ctx sdk.Context) types.Params { k.GetSlashMeterReplenishFraction(ctx), k.GetConsumerRewardDenomRegistrationFee(ctx), k.GetBlocksPerEpoch(ctx), + k.GetNumberOfEpochsToStartReceivingRewards(ctx), ) } diff --git a/x/ccv/provider/keeper/params_test.go b/x/ccv/provider/keeper/params_test.go index 88175431c0..9dd10076a6 100644 --- a/x/ccv/provider/keeper/params_test.go +++ b/x/ccv/provider/keeper/params_test.go @@ -49,6 +49,7 @@ func TestParams(t *testing.T) { Amount: sdk.NewInt(10000000), }, 600, + 24, ) providerKeeper.SetParams(ctx, newParams) params = providerKeeper.GetParams(ctx) diff --git a/x/ccv/provider/keeper/proposal_test.go b/x/ccv/provider/keeper/proposal_test.go index a7e26534b5..09942f82f1 100644 --- a/x/ccv/provider/keeper/proposal_test.go +++ b/x/ccv/provider/keeper/proposal_test.go @@ -839,7 +839,8 @@ func TestMakeConsumerGenesis(t *testing.T) { Denom: "stake", Amount: sdk.NewInt(1000000), }, - BlocksPerEpoch: 600, + BlocksPerEpoch: 600, + NumberOfEpochsToStartReceivingRewards: 24, } providerKeeper.SetParams(ctx, moduleParams) defer ctrl.Finish() diff --git a/x/ccv/provider/keeper/relay_test.go b/x/ccv/provider/keeper/relay_test.go index a4fe6e60ff..c71a53d13d 100644 --- a/x/ccv/provider/keeper/relay_test.go +++ b/x/ccv/provider/keeper/relay_test.go @@ -87,6 +87,55 @@ func TestQueueVSCPackets(t *testing.T) { } } +// TestQueueVSCPacketsDoesNotResetConsumerValidatorsHeights checks that the heights of consumer validators are not +// getting incorrectly updated +func TestQueueVSCPacketsDoesNotResetConsumerValidatorsHeights(t *testing.T) { + providerKeeper, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + chainHeight := int64(987654321) + ctx = ctx.WithBlockHeight(chainHeight) + providerKeeper.SetParams(ctx, providertypes.DefaultParams()) + + // mock 2 bonded validators + valA := createStakingValidator(ctx, mocks, 1, 1) + valAConsAddr, _ := valA.GetConsAddr() + valAPubKey, _ := valA.TmConsPublicKey() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valAConsAddr).Return(valA, true).AnyTimes() + valB := createStakingValidator(ctx, mocks, 2, 2) + valBConsAddr, _ := valB.GetConsAddr() + mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valBConsAddr).Return(valB, true).AnyTimes() + testkeeper.SetupMocksForLastBondedValidatorsExpectation(mocks.MockStakingKeeper, 2, []stakingtypes.Validator{valA, valB}, []int64{1, 2}, -1) + + // set a consumer client, so we have a consumer chain (i.e., `k.GetAllConsumerChains(ctx)` is non empty) + providerKeeper.SetConsumerClientId(ctx, "chainID", "clientID") + + // opt in validator A and set as a consumer validator + providerKeeper.SetOptedIn(ctx, "chainID", providertypes.NewProviderConsAddress(valAConsAddr)) + consumerValidatorA := types.ConsumerValidator{ + ProviderConsAddr: valAConsAddr, + Power: 1, + ConsumerPublicKey: &valAPubKey, + JoinHeight: 123456789, + } + providerKeeper.SetConsumerValidator(ctx, "chainID", consumerValidatorA) + + // Opt in validator B. Note that validator B is not a consumer validator and hence would become a consumer + // validator for the first time after the `QueueVSCPackets` call. + providerKeeper.SetOptedIn(ctx, "chainID", providertypes.NewProviderConsAddress(valBConsAddr)) + + providerKeeper.QueueVSCPackets(ctx) + + // the height of consumer validator A should not be modified because A was already a consumer validator + cv, _ := providerKeeper.GetConsumerValidator(ctx, "chainID", providertypes.NewProviderConsAddress(valAConsAddr)) + require.Equal(t, consumerValidatorA.JoinHeight, cv.JoinHeight, "the consumer validator's height was erroneously modified") + + // the height of consumer validator B is set to be the same as the one of the current chain height because this + // consumer validator becomes a consumer validator for the first time (i.e., was not a consumer validator in the previous epoch) + cv, _ = providerKeeper.GetConsumerValidator(ctx, "chainID", providertypes.NewProviderConsAddress(valBConsAddr)) + require.Equal(t, chainHeight, cv.JoinHeight, "the consumer validator's height was not correctly set") +} + // TestOnRecvVSCMaturedPacket tests the OnRecvVSCMaturedPacket method of the keeper. // // Note: Handling logic itself is not tested here. diff --git a/x/ccv/provider/keeper/validator_set_update.go b/x/ccv/provider/keeper/validator_set_update.go index 9ba2c961ab..de46e880ab 100644 --- a/x/ccv/provider/keeper/validator_set_update.go +++ b/x/ccv/provider/keeper/validator_set_update.go @@ -72,6 +72,23 @@ func (k Keeper) IsConsumerValidator(ctx sdk.Context, chainID string, providerAdd return store.Get(types.ConsumerValidatorKey(chainID, providerAddr.ToSdkConsAddr())) != nil } +// GetConsumerValidator returns the consumer validator with `providerAddr` if it exists for chain `chainID` +func (k Keeper) GetConsumerValidator(ctx sdk.Context, chainID string, providerAddr types.ProviderConsAddress) (types.ConsumerValidator, bool) { + store := ctx.KVStore(k.storeKey) + marshalledConsumerValidator := store.Get(types.ConsumerValidatorKey(chainID, providerAddr.ToSdkConsAddr())) + + if marshalledConsumerValidator == nil { + return types.ConsumerValidator{}, false + } + + var validator types.ConsumerValidator + if err := validator.Unmarshal(marshalledConsumerValidator); err != nil { + panic(fmt.Errorf("failed to unmarshal ConsumerValidator: %w", err)) + } + + return validator, true +} + // GetConsumerValSet returns all the consumer validators for chain `chainID` func (k Keeper) GetConsumerValSet( ctx sdk.Context, @@ -152,10 +169,18 @@ func (k Keeper) CreateConsumerValidator(ctx sdk.Context, chainID string, validat } } + height := ctx.BlockHeight() + if v, found := k.GetConsumerValidator(ctx, chainID, types.ProviderConsAddress{Address: consAddr}); found { + // if validator was already a consumer validator, then do not update the height set the first time + // the validator became a consumer validator + height = v.JoinHeight + } + return types.ConsumerValidator{ ProviderConsAddr: consAddr, Power: power, ConsumerPublicKey: &consumerPublicKey, + JoinHeight: height, }, nil } diff --git a/x/ccv/provider/migrations/migrator.go b/x/ccv/provider/migrations/migrator.go index abc23c42d0..3ed41da6dd 100644 --- a/x/ccv/provider/migrations/migrator.go +++ b/x/ccv/provider/migrations/migrator.go @@ -50,8 +50,10 @@ func (m Migrator) Migrate4to5(ctx sdktypes.Context) error { } // Migrate5to6 migrates x/ccvprovider state from consensus version 5 to 6. -// The migration consists of computing and storing the minimal power in the top N for all registered consumer chains. +// The migration consists of setting the `NumberOfEpochsToStartReceivingRewards` param, as well as +// computing and storing the minimal power in the top N for all registered consumer chains. func (m Migrator) Migrate5to6(ctx sdktypes.Context) error { + v6.MigrateParams(ctx, m.paramSpace) v6.MigrateMinPowerInTopN(ctx, m.providerKeeper) return nil } diff --git a/x/ccv/provider/migrations/v6/migration_test.go b/x/ccv/provider/migrations/v6/migration_test.go new file mode 100644 index 0000000000..a5ae1b0d0c --- /dev/null +++ b/x/ccv/provider/migrations/v6/migration_test.go @@ -0,0 +1,27 @@ +package v6 + +import ( + "testing" + + "github.com/stretchr/testify/require" + + testutil "github.com/cosmos/interchain-security/v4/testutil/keeper" + providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" +) + +func TestMigrateParams(t *testing.T) { + inMemParams := testutil.NewInMemKeeperParams(t) + _, ctx, ctrl, _ := testutil.GetProviderKeeperAndCtx(t, inMemParams) + defer ctrl.Finish() + + // initially number of epochs param does not exist + require.False(t, inMemParams.ParamsSubspace.Has(ctx, providertypes.KeyNumberOfEpochsToStartReceivingRewards)) + + MigrateParams(ctx, *inMemParams.ParamsSubspace) + + // after migration, number of epochs epoch param should exist and be equal to default + require.True(t, inMemParams.ParamsSubspace.Has(ctx, providertypes.KeyNumberOfEpochsToStartReceivingRewards)) + var numberOfEpochsParam int64 + inMemParams.ParamsSubspace.Get(ctx, providertypes.KeyNumberOfEpochsToStartReceivingRewards, &numberOfEpochsParam) + require.Equal(t, providertypes.DefaultNumberOfEpochsToStartReceivingRewards, numberOfEpochsParam) +} diff --git a/x/ccv/provider/migrations/v6/migrations.go b/x/ccv/provider/migrations/v6/migrations.go index 7e659de143..9395d625e3 100644 --- a/x/ccv/provider/migrations/v6/migrations.go +++ b/x/ccv/provider/migrations/v6/migrations.go @@ -2,6 +2,8 @@ package v6 import ( sdk "github.com/cosmos/cosmos-sdk/types" + paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + providertypes "github.com/cosmos/interchain-security/v4/x/ccv/provider/types" providerkeeper "github.com/cosmos/interchain-security/v4/x/ccv/provider/keeper" ) @@ -31,3 +33,11 @@ func MigrateMinPowerInTopN(ctx sdk.Context, providerKeeper providerkeeper.Keeper } } } + +// MigrateParams adds missing provider chain params to the param store. +func MigrateParams(ctx sdk.Context, paramsSubspace paramtypes.Subspace) { + if !paramsSubspace.HasKeyTable() { + paramsSubspace.WithKeyTable(providertypes.ParamKeyTable()) + } + paramsSubspace.Set(ctx, providertypes.KeyNumberOfEpochsToStartReceivingRewards, providertypes.DefaultNumberOfEpochsToStartReceivingRewards) +} diff --git a/x/ccv/provider/module.go b/x/ccv/provider/module.go index 23c773e97a..e78a1e051e 100644 --- a/x/ccv/provider/module.go +++ b/x/ccv/provider/module.go @@ -118,6 +118,10 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { if err := cfg.RegisterMigration(providertypes.ModuleName, 4, m.Migrate4to5); err != nil { panic(fmt.Sprintf("failed to register migrator for %s: %s", providertypes.ModuleName, err)) } + if err := cfg.RegisterMigration(providertypes.ModuleName, 5, m.Migrate5to6); err != nil { + panic(fmt.Sprintf("failed to register migrator for %s: %s", providertypes.ModuleName, err)) + } + } // InitGenesis performs genesis initialization for the provider module. It returns no validator updates. diff --git a/x/ccv/provider/types/genesis_test.go b/x/ccv/provider/types/genesis_test.go index 41a716757f..323aaa49be 100644 --- a/x/ccv/provider/types/genesis_test.go +++ b/x/ccv/provider/types/genesis_test.go @@ -81,7 +81,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600, 24), nil, nil, nil, @@ -102,7 +102,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600, 24), nil, nil, nil, @@ -123,7 +123,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600, 24), nil, nil, nil, @@ -144,7 +144,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600, 24), nil, nil, nil, @@ -171,7 +171,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600, 24), nil, nil, nil, @@ -198,7 +198,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600, 24), nil, nil, nil, @@ -225,7 +225,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: sdk.NewInt(1000000)}, 600), + sdk.Coin{Denom: "stake", Amount: sdk.NewInt(1000000)}, 600, 24), nil, nil, nil, @@ -252,7 +252,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600, 24), nil, nil, nil, @@ -279,7 +279,7 @@ func TestValidateGenesisState(t *testing.T) { 0, // 0 vsc timeout here types.DefaultSlashMeterReplenishPeriod, types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600, 24), nil, nil, nil, @@ -306,7 +306,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, 0, // 0 slash meter replenish period here types.DefaultSlashMeterReplenishFraction, - sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600, 24), nil, nil, nil, @@ -333,7 +333,7 @@ func TestValidateGenesisState(t *testing.T) { types.DefaultVscTimeoutPeriod, types.DefaultSlashMeterReplenishPeriod, "1.15", - sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600), + sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 600, 24), nil, nil, nil, @@ -685,7 +685,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "st", Amount: sdk.NewInt(10000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "st", Amount: sdk.NewInt(10000000)}, 600, 24), nil, nil, nil, @@ -706,7 +706,7 @@ func TestValidateGenesisState(t *testing.T) { nil, types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(-1000000)}, 600), + types.DefaultTrustingPeriodFraction, time.Hour, time.Hour, 30*time.Minute, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(-1000000)}, 600, 24), nil, nil, nil, diff --git a/x/ccv/provider/types/params.go b/x/ccv/provider/types/params.go index a0a7a5ed7a..2c04dd511c 100644 --- a/x/ccv/provider/types/params.go +++ b/x/ccv/provider/types/params.go @@ -41,18 +41,30 @@ const ( // an epoch corresponds to 1 hour (6 * 600 = 3600 seconds). // forcing int64 as the Params KeyTable expects an int64 and not int. DefaultBlocksPerEpoch = int64(600) + + // DefaultNumberOfEpochsToStartReceivingRewards defines the default minimum number of epochs required by a validator to validate + // during so that the validator can start receiving rewards. This would mean that a validator has to be a consumer validator for at least + // `DefaultNumberOfEpochsToStartReceivingRewards * DefaultBlocksPerEpoch` on a consumer chain to start receiving rewards from the chain. + // Note that after a validator starts receiving rewards, the validator would keep receiving rewards every time the + // consumer chain sends an IBC transfer over to the provider. This value only sets a constraint on when a validator + // can first start receiving rewards to avoid cases where a validator just opts in to receive rewards and then opts out + // immediately afterward. + // Current default values for blocks per epoch corresponds to about 1 hour, so with 24 being the + // minimum amount of epochs, this would imply that a validator has to validate at least for 1 day to receive rewards. + DefaultNumberOfEpochsToStartReceivingRewards = int64(24) ) // Reflection based keys for params subspace var ( - KeyTemplateClient = []byte("TemplateClient") - KeyTrustingPeriodFraction = []byte("TrustingPeriodFraction") - KeyInitTimeoutPeriod = []byte("InitTimeoutPeriod") - KeyVscTimeoutPeriod = []byte("VscTimeoutPeriod") - KeySlashMeterReplenishPeriod = []byte("SlashMeterReplenishPeriod") - KeySlashMeterReplenishFraction = []byte("SlashMeterReplenishFraction") - KeyConsumerRewardDenomRegistrationFee = []byte("ConsumerRewardDenomRegistrationFee") - KeyBlocksPerEpoch = []byte("BlocksPerEpoch") + KeyTemplateClient = []byte("TemplateClient") + KeyTrustingPeriodFraction = []byte("TrustingPeriodFraction") + KeyInitTimeoutPeriod = []byte("InitTimeoutPeriod") + KeyVscTimeoutPeriod = []byte("VscTimeoutPeriod") + KeySlashMeterReplenishPeriod = []byte("SlashMeterReplenishPeriod") + KeySlashMeterReplenishFraction = []byte("SlashMeterReplenishFraction") + KeyConsumerRewardDenomRegistrationFee = []byte("ConsumerRewardDenomRegistrationFee") + KeyBlocksPerEpoch = []byte("BlocksPerEpoch") + KeyNumberOfEpochsToStartReceivingRewards = []byte("NumberOfEpochsToStartReceivingRewards") ) // ParamKeyTable returns a key table with the necessary registered provider params @@ -71,17 +83,19 @@ func NewParams( slashMeterReplenishFraction string, consumerRewardDenomRegistrationFee sdk.Coin, blocksPerEpoch int64, + numberOfEpochsToStartReceivingRewards int64, ) Params { return Params{ - TemplateClient: cs, - TrustingPeriodFraction: trustingPeriodFraction, - CcvTimeoutPeriod: ccvTimeoutPeriod, - InitTimeoutPeriod: initTimeoutPeriod, - VscTimeoutPeriod: vscTimeoutPeriod, - SlashMeterReplenishPeriod: slashMeterReplenishPeriod, - SlashMeterReplenishFraction: slashMeterReplenishFraction, - ConsumerRewardDenomRegistrationFee: consumerRewardDenomRegistrationFee, - BlocksPerEpoch: blocksPerEpoch, + TemplateClient: cs, + TrustingPeriodFraction: trustingPeriodFraction, + CcvTimeoutPeriod: ccvTimeoutPeriod, + InitTimeoutPeriod: initTimeoutPeriod, + VscTimeoutPeriod: vscTimeoutPeriod, + SlashMeterReplenishPeriod: slashMeterReplenishPeriod, + SlashMeterReplenishFraction: slashMeterReplenishFraction, + ConsumerRewardDenomRegistrationFee: consumerRewardDenomRegistrationFee, + BlocksPerEpoch: blocksPerEpoch, + NumberOfEpochsToStartReceivingRewards: numberOfEpochsToStartReceivingRewards, } } @@ -113,6 +127,7 @@ func DefaultParams() Params { Amount: sdk.NewInt(10000000), }, DefaultBlocksPerEpoch, + DefaultNumberOfEpochsToStartReceivingRewards, ) } @@ -145,9 +160,12 @@ func (p Params) Validate() error { if err := ValidateCoin(p.ConsumerRewardDenomRegistrationFee); err != nil { return fmt.Errorf("consumer reward denom registration fee is invalid: %s", err) } - if err := ccvtypes.ValidateInt64(p.BlocksPerEpoch); err != nil { + if err := ccvtypes.ValidatePositiveInt64(p.BlocksPerEpoch); err != nil { return fmt.Errorf("blocks per epoch is invalid: %s", err) } + if err := ccvtypes.ValidatePositiveInt64(p.NumberOfEpochsToStartReceivingRewards); err != nil { + return fmt.Errorf("number of epochs to start receiving rewards is invalid: %s", err) + } return nil } @@ -163,6 +181,7 @@ func (p *Params) ParamSetPairs() paramtypes.ParamSetPairs { paramtypes.NewParamSetPair(KeySlashMeterReplenishFraction, p.SlashMeterReplenishFraction, ccvtypes.ValidateStringFraction), paramtypes.NewParamSetPair(KeyConsumerRewardDenomRegistrationFee, p.ConsumerRewardDenomRegistrationFee, ValidateCoin), paramtypes.NewParamSetPair(KeyBlocksPerEpoch, p.BlocksPerEpoch, ccvtypes.ValidatePositiveInt64), + paramtypes.NewParamSetPair(KeyNumberOfEpochsToStartReceivingRewards, p.NumberOfEpochsToStartReceivingRewards, ccvtypes.ValidatePositiveInt64), } } diff --git a/x/ccv/provider/types/params_test.go b/x/ccv/provider/types/params_test.go index 4e72c233af..bcec7c7c77 100644 --- a/x/ccv/provider/types/params_test.go +++ b/x/ccv/provider/types/params_test.go @@ -24,39 +24,43 @@ func TestValidateParams(t *testing.T) { {"custom valid params", types.NewParams( ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000), true}, + "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000, 24), true}, {"custom invalid params", types.NewParams( ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, 0, clienttypes.Height{}, nil, []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000, 24), false}, {"blank client", types.NewParams(&ibctmtypes.ClientState{}, - "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000), false}, - {"nil client", types.NewParams(nil, "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000, 24), false}, + {"nil client", types.NewParams(nil, "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000, 24), false}, // Check if "0.00" is valid or if a zero dec TrustFraction needs to return an error {"0 trusting period fraction", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.00", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000), true}, + "0.00", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000, 24), true}, {"0 ccv timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", 0, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000), false}, + "0.33", 0, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000, 24), false}, {"0 init timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, 0, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, 0, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000, 24), false}, {"0 vsc timeout period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, 0, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, 0, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000, 24), false}, {"0 slash meter replenish period", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, 24*time.Hour, 0, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, 24*time.Hour, 0, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000, 24), false}, {"slash meter replenish fraction over 1", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "1.5", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "1.5", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000, 24), false}, {"invalid consumer reward denom registration fee denom", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", sdk.Coin{Denom: "st", Amount: sdk.NewInt(10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", sdk.Coin{Denom: "st", Amount: sdk.NewInt(10000000)}, 1000, 24), false}, {"invalid consumer reward denom registration fee amount", types.NewParams(ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), - "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(-10000000)}, 1000), false}, + "0.33", time.Hour, time.Hour, 24*time.Hour, time.Hour, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(-10000000)}, 1000, 24), false}, + {"invalid number of epochs to start receiving rewards", types.NewParams( + ibctmtypes.NewClientState("", ibctmtypes.DefaultTrustLevel, 0, 0, + time.Second*40, clienttypes.Height{}, commitmenttypes.GetSDKSpecs(), []string{"ibc", "upgradedIBCState"}), + "0.33", time.Hour, time.Hour, time.Hour, 30*time.Minute, "0.1", sdk.Coin{Denom: "stake", Amount: sdk.NewInt(10000000)}, 1000, 0), false}, } for _, tc := range testCases { diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index 0540dfb0a6..8649882e18 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -593,6 +593,8 @@ type Params struct { ConsumerRewardDenomRegistrationFee types2.Coin `protobuf:"bytes,9,opt,name=consumer_reward_denom_registration_fee,json=consumerRewardDenomRegistrationFee,proto3" json:"consumer_reward_denom_registration_fee"` // The number of blocks that comprise an epoch. BlocksPerEpoch int64 `protobuf:"varint,10,opt,name=blocks_per_epoch,json=blocksPerEpoch,proto3" json:"blocks_per_epoch,omitempty"` + // The number of epochs a validator has to validate a consumer chain in order to start receiving rewards from that chain. + NumberOfEpochsToStartReceivingRewards int64 `protobuf:"varint,11,opt,name=number_of_epochs_to_start_receiving_rewards,json=numberOfEpochsToStartReceivingRewards,proto3" json:"number_of_epochs_to_start_receiving_rewards,omitempty"` } func (m *Params) Reset() { *m = Params{} } @@ -691,6 +693,13 @@ func (m *Params) GetBlocksPerEpoch() int64 { return 0 } +func (m *Params) GetNumberOfEpochsToStartReceivingRewards() int64 { + if m != nil { + return m.NumberOfEpochsToStartReceivingRewards + } + return 0 +} + // SlashAcks contains cons addresses of consumer chain validators // successfully slashed on the provider chain. type SlashAcks struct { @@ -1543,6 +1552,11 @@ type ConsumerValidator struct { Power int64 `protobuf:"varint,2,opt,name=power,proto3" json:"power,omitempty"` // public key the validator uses on the consumer chain during this epoch ConsumerPublicKey *crypto.PublicKey `protobuf:"bytes,3,opt,name=consumer_public_key,json=consumerPublicKey,proto3" json:"consumer_public_key,omitempty"` + // height the validator had when it FIRST became a consumer validator + // If a validator becomes a consumer validator at height `H` and is continuously a consumer validator for all the upcoming + // epochs, then the height of the validator SHOULD remain `H`. This height only resets to a different height if a validator + // stops being a consumer validator during an epoch and later becomes again a consumer validator. + JoinHeight int64 `protobuf:"varint,4,opt,name=join_height,json=joinHeight,proto3" json:"join_height,omitempty"` } func (m *ConsumerValidator) Reset() { *m = ConsumerValidator{} } @@ -1599,6 +1613,13 @@ func (m *ConsumerValidator) GetConsumerPublicKey() *crypto.PublicKey { return nil } +func (m *ConsumerValidator) GetJoinHeight() int64 { + if m != nil { + return m.JoinHeight + } + return 0 +} + // ConsumerRewardsAllocation stores the rewards allocated by a consumer chain // to the consumer rewards pool. It is used to allocate the tokens to the consumer // opted-in validators and the community pool during BeginBlock. @@ -1679,130 +1700,134 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 1954 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcb, 0x6f, 0x1b, 0xc7, - 0x19, 0xd7, 0x92, 0x94, 0x44, 0x0e, 0xf5, 0x1c, 0x29, 0xf1, 0x4a, 0x55, 0x29, 0x7a, 0xd3, 0xa4, - 0x6a, 0x5c, 0x2f, 0x23, 0xa5, 0x05, 0x0c, 0xa3, 0x41, 0x20, 0x51, 0x4e, 0x2c, 0x2b, 0xb6, 0x99, - 0x95, 0x2a, 0xa3, 0xed, 0x61, 0x31, 0x9c, 0x1d, 0x93, 0x03, 0x2d, 0x77, 0xd6, 0x33, 0xc3, 0x55, - 0x78, 0xe9, 0xb9, 0x87, 0x16, 0x48, 0x6f, 0x41, 0x0f, 0x6d, 0x5a, 0xa0, 0x40, 0xd1, 0x4b, 0xfb, - 0x67, 0xe4, 0x98, 0x63, 0x4f, 0x49, 0x61, 0x1f, 0x7a, 0xe8, 0x3f, 0x51, 0xcc, 0xec, 0x93, 0x94, - 0xe4, 0xd2, 0x48, 0x72, 0x91, 0x76, 0xbf, 0xc7, 0xef, 0xfb, 0x66, 0xbe, 0x27, 0x17, 0xec, 0xd1, - 0x40, 0x12, 0x8e, 0xfb, 0x88, 0x06, 0xae, 0x20, 0x78, 0xc8, 0xa9, 0x1c, 0xb5, 0x30, 0x8e, 0x5a, - 0x21, 0x67, 0x11, 0xf5, 0x08, 0x6f, 0x45, 0xbb, 0xd9, 0xb3, 0x1d, 0x72, 0x26, 0x19, 0x7c, 0xe3, - 0x0a, 0x1d, 0x1b, 0xe3, 0xc8, 0xce, 0xe4, 0xa2, 0xdd, 0xcd, 0x37, 0xaf, 0x03, 0x8e, 0x76, 0x5b, - 0x17, 0x94, 0x93, 0x18, 0x6b, 0x73, 0xbd, 0xc7, 0x7a, 0x4c, 0x3f, 0xb6, 0xd4, 0x53, 0x42, 0xdd, - 0xee, 0x31, 0xd6, 0xf3, 0x49, 0x4b, 0xbf, 0x75, 0x87, 0x4f, 0x5b, 0x92, 0x0e, 0x88, 0x90, 0x68, - 0x10, 0x26, 0x02, 0x8d, 0x49, 0x01, 0x6f, 0xc8, 0x91, 0xa4, 0x2c, 0x48, 0x01, 0x68, 0x17, 0xb7, - 0x30, 0xe3, 0xa4, 0x85, 0x7d, 0x4a, 0x02, 0xa9, 0xac, 0xc6, 0x4f, 0x89, 0x40, 0x4b, 0x09, 0xf8, - 0xb4, 0xd7, 0x97, 0x31, 0x59, 0xb4, 0x24, 0x09, 0x3c, 0xc2, 0x07, 0x34, 0x16, 0xce, 0xdf, 0x12, - 0x85, 0xad, 0x02, 0x1f, 0xf3, 0x51, 0x28, 0x59, 0xeb, 0x9c, 0x8c, 0x44, 0xc2, 0x7d, 0x0b, 0x33, - 0x31, 0x60, 0xa2, 0x45, 0xd4, 0xf9, 0x03, 0x4c, 0x5a, 0xd1, 0x6e, 0x97, 0x48, 0xb4, 0x9b, 0x11, - 0x52, 0xbf, 0x13, 0xb9, 0x2e, 0x12, 0xb9, 0x0c, 0x66, 0x34, 0xf5, 0x7b, 0x15, 0x0d, 0x68, 0xc0, - 0x5a, 0xfa, 0x6f, 0x4c, 0xb2, 0x7e, 0x5b, 0x05, 0x66, 0x9b, 0x05, 0x62, 0x38, 0x20, 0x7c, 0xdf, - 0xf3, 0xa8, 0x3a, 0x65, 0x87, 0xb3, 0x90, 0x09, 0xe4, 0xc3, 0x75, 0x30, 0x2b, 0xa9, 0xf4, 0x89, - 0x69, 0x34, 0x8d, 0x9d, 0x9a, 0x13, 0xbf, 0xc0, 0x26, 0xa8, 0x7b, 0x44, 0x60, 0x4e, 0x43, 0x25, - 0x6c, 0x96, 0x34, 0xaf, 0x48, 0x82, 0x1b, 0xa0, 0x1a, 0x87, 0x86, 0x7a, 0x66, 0x59, 0xb3, 0xe7, - 0xf5, 0xfb, 0x91, 0x07, 0x3f, 0x04, 0x4b, 0x34, 0xa0, 0x92, 0x22, 0xdf, 0xed, 0x13, 0x75, 0x41, - 0x66, 0xa5, 0x69, 0xec, 0xd4, 0xf7, 0x36, 0x6d, 0xda, 0xc5, 0xb6, 0xba, 0x53, 0x3b, 0xb9, 0xc9, - 0x68, 0xd7, 0xbe, 0xaf, 0x25, 0x0e, 0x2a, 0x5f, 0x7c, 0xb5, 0x3d, 0xe3, 0x2c, 0x26, 0x7a, 0x31, - 0x11, 0xde, 0x04, 0x0b, 0x3d, 0x12, 0x10, 0x41, 0x85, 0xdb, 0x47, 0xa2, 0x6f, 0xce, 0x36, 0x8d, - 0x9d, 0x05, 0xa7, 0x9e, 0xd0, 0xee, 0x23, 0xd1, 0x87, 0xdb, 0xa0, 0xde, 0xa5, 0x01, 0xe2, 0xa3, - 0x58, 0x62, 0x4e, 0x4b, 0x80, 0x98, 0xa4, 0x05, 0xda, 0x00, 0x88, 0x10, 0x5d, 0x04, 0xae, 0x4a, - 0x00, 0x73, 0x3e, 0x71, 0x24, 0x0e, 0xbe, 0x9d, 0x06, 0xdf, 0x3e, 0x4d, 0xb3, 0xe3, 0xa0, 0xaa, - 0x1c, 0xf9, 0xf4, 0xeb, 0x6d, 0xc3, 0xa9, 0x69, 0x3d, 0xc5, 0x81, 0x8f, 0xc0, 0xca, 0x30, 0xe8, - 0xb2, 0xc0, 0xa3, 0x41, 0xcf, 0x0d, 0x09, 0xa7, 0xcc, 0x33, 0xab, 0x1a, 0x6a, 0xe3, 0x12, 0xd4, - 0x61, 0x92, 0x47, 0x31, 0xd2, 0x67, 0x0a, 0x69, 0x39, 0x53, 0xee, 0x68, 0x5d, 0xf8, 0x31, 0x80, - 0x18, 0x47, 0xda, 0x25, 0x36, 0x94, 0x29, 0x62, 0x6d, 0x7a, 0xc4, 0x15, 0x8c, 0xa3, 0xd3, 0x58, - 0x3b, 0x81, 0xfc, 0x15, 0xb8, 0x21, 0x39, 0x0a, 0xc4, 0x53, 0xc2, 0x27, 0x71, 0xc1, 0xf4, 0xb8, - 0xaf, 0xa5, 0x18, 0xe3, 0xe0, 0xf7, 0x41, 0x13, 0x27, 0x09, 0xe4, 0x72, 0xe2, 0x51, 0x21, 0x39, - 0xed, 0x0e, 0x95, 0xae, 0xfb, 0x94, 0x23, 0xac, 0x73, 0xa4, 0xae, 0x93, 0xa0, 0x91, 0xca, 0x39, - 0x63, 0x62, 0x1f, 0x24, 0x52, 0xf0, 0x31, 0xf8, 0x41, 0xd7, 0x67, 0xf8, 0x5c, 0x28, 0xe7, 0xdc, - 0x31, 0x24, 0x6d, 0x7a, 0x40, 0x85, 0x50, 0x68, 0x0b, 0x4d, 0x63, 0xa7, 0xec, 0xdc, 0x8c, 0x65, - 0x3b, 0x84, 0x1f, 0x16, 0x24, 0x4f, 0x0b, 0x82, 0xf0, 0x36, 0x80, 0x7d, 0x2a, 0x24, 0xe3, 0x14, - 0x23, 0xdf, 0x25, 0x81, 0xe4, 0x94, 0x08, 0x73, 0x51, 0xab, 0xaf, 0xe6, 0x9c, 0x7b, 0x31, 0x03, - 0x3e, 0x00, 0x37, 0xaf, 0x35, 0xea, 0xe2, 0x3e, 0x0a, 0x02, 0xe2, 0x9b, 0x4b, 0xfa, 0x28, 0xdb, - 0xde, 0x35, 0x36, 0xdb, 0xb1, 0x18, 0x5c, 0x03, 0xb3, 0x92, 0x85, 0xee, 0x23, 0x73, 0xb9, 0x69, - 0xec, 0x2c, 0x3a, 0x15, 0xc9, 0xc2, 0x47, 0xf0, 0x1d, 0xb0, 0x1e, 0x21, 0x9f, 0x7a, 0x48, 0x32, - 0x2e, 0xdc, 0x90, 0x5d, 0x10, 0xee, 0x62, 0x14, 0x9a, 0x2b, 0x5a, 0x06, 0xe6, 0xbc, 0x8e, 0x62, - 0xb5, 0x51, 0x08, 0xdf, 0x06, 0xab, 0x19, 0xd5, 0x15, 0x44, 0x6a, 0xf1, 0x55, 0x2d, 0xbe, 0x9c, - 0x31, 0x4e, 0x88, 0x54, 0xb2, 0x5b, 0xa0, 0x86, 0x7c, 0x9f, 0x5d, 0xf8, 0x54, 0x48, 0x13, 0x36, - 0xcb, 0x3b, 0x35, 0x27, 0x27, 0xc0, 0x4d, 0x50, 0xf5, 0x48, 0x30, 0xd2, 0xcc, 0x35, 0xcd, 0xcc, - 0xde, 0xef, 0x56, 0x7f, 0xf3, 0xf9, 0xf6, 0xcc, 0x67, 0x9f, 0x6f, 0xcf, 0x58, 0xff, 0x30, 0xc0, - 0x8d, 0x76, 0x16, 0xa5, 0x01, 0x8b, 0x90, 0xff, 0x5d, 0x76, 0x83, 0x7d, 0x50, 0x13, 0xea, 0x9a, - 0x74, 0xfd, 0x55, 0x5e, 0xa1, 0xfe, 0xaa, 0x4a, 0x4d, 0x31, 0xac, 0x3f, 0x96, 0xc0, 0x56, 0xea, - 0xf1, 0x43, 0xe6, 0xd1, 0xa7, 0x14, 0xa3, 0xef, 0xba, 0x89, 0x65, 0xc1, 0xad, 0x4c, 0x11, 0xdc, - 0xd9, 0x57, 0x0b, 0xee, 0xdc, 0x14, 0xc1, 0x9d, 0x7f, 0x59, 0x70, 0xab, 0xe3, 0xc1, 0xb5, 0xfe, - 0x64, 0x80, 0xf5, 0x7b, 0xcf, 0x86, 0x34, 0x62, 0xdf, 0xd2, 0xc5, 0x1c, 0x83, 0x45, 0x52, 0xc0, - 0x13, 0x66, 0xb9, 0x59, 0xde, 0xa9, 0xef, 0xbd, 0x69, 0xc7, 0xd3, 0xc7, 0xce, 0x86, 0x52, 0x32, - 0x81, 0xec, 0xa2, 0x75, 0x67, 0x5c, 0xf7, 0x6e, 0xc9, 0x34, 0xac, 0xbf, 0x18, 0x60, 0x53, 0xd5, - 0x4d, 0x8f, 0x38, 0xe4, 0x02, 0x71, 0xef, 0x90, 0x04, 0x6c, 0x20, 0xbe, 0xb1, 0x9f, 0x16, 0x58, - 0xf4, 0x34, 0x92, 0x2b, 0x99, 0x8b, 0x3c, 0x4f, 0xfb, 0xa9, 0x65, 0x14, 0xf1, 0x94, 0xed, 0x7b, - 0x1e, 0xdc, 0x01, 0x2b, 0xb9, 0x0c, 0x57, 0x09, 0xaf, 0xf2, 0x50, 0x89, 0x2d, 0xa5, 0x62, 0xba, - 0x0c, 0x88, 0xf5, 0x5f, 0x03, 0xac, 0x7c, 0xe8, 0xb3, 0x2e, 0xf2, 0x4f, 0x7c, 0x24, 0xfa, 0xaa, - 0x67, 0x8c, 0x54, 0xfe, 0x72, 0x92, 0x34, 0x6b, 0xed, 0xde, 0xd4, 0xf9, 0xab, 0xd4, 0xf4, 0xf8, - 0x78, 0x1f, 0xac, 0x66, 0xed, 0x33, 0xcb, 0x37, 0x7d, 0x9a, 0x83, 0xb5, 0xe7, 0x5f, 0x6d, 0x2f, - 0xa7, 0xb9, 0xdd, 0xd6, 0xb9, 0x77, 0xe8, 0x2c, 0xe3, 0x31, 0x82, 0x07, 0x1b, 0xa0, 0x4e, 0xbb, - 0xd8, 0x15, 0xe4, 0x99, 0x1b, 0x0c, 0x07, 0x3a, 0x55, 0x2b, 0x4e, 0x8d, 0x76, 0xf1, 0x09, 0x79, - 0xf6, 0x68, 0x38, 0x80, 0xef, 0x82, 0xd7, 0xd3, 0xcd, 0xc9, 0x8d, 0x90, 0xef, 0x2a, 0x7d, 0x75, - 0x1d, 0x5c, 0x67, 0xef, 0x82, 0xb3, 0x96, 0x72, 0xcf, 0x90, 0xaf, 0x8c, 0xed, 0x7b, 0x1e, 0xb7, - 0x5e, 0xcc, 0x82, 0xb9, 0x0e, 0xe2, 0x68, 0x20, 0xe0, 0x29, 0x58, 0x96, 0x64, 0x10, 0xfa, 0x48, - 0x12, 0x37, 0x1e, 0xcd, 0xc9, 0x49, 0x6f, 0xe9, 0x91, 0x5d, 0xdc, 0x72, 0xec, 0xc2, 0x5e, 0x13, - 0xed, 0xda, 0x6d, 0x4d, 0x3d, 0x91, 0x48, 0x12, 0x67, 0x29, 0xc5, 0x88, 0x89, 0xf0, 0x0e, 0x30, - 0x25, 0x1f, 0x0a, 0x99, 0x0f, 0xcd, 0x7c, 0x5a, 0xc4, 0xb1, 0x7c, 0x3d, 0xe5, 0xc7, 0x73, 0x26, - 0x9b, 0x12, 0x57, 0xcf, 0xc7, 0xf2, 0x37, 0x99, 0x8f, 0x27, 0x60, 0x4d, 0x2d, 0x17, 0x93, 0x98, - 0x95, 0xe9, 0x31, 0x57, 0x95, 0xfe, 0x38, 0xe8, 0xc7, 0x00, 0x46, 0x02, 0x4f, 0x62, 0xce, 0xbe, - 0x82, 0x9f, 0x91, 0xc0, 0xe3, 0x90, 0x1e, 0xd8, 0x12, 0x2a, 0xf9, 0xdc, 0x01, 0x91, 0x7a, 0xda, - 0x86, 0x3e, 0x09, 0xa8, 0xe8, 0xa7, 0xe0, 0x73, 0xd3, 0x83, 0x6f, 0x68, 0xa0, 0x87, 0x0a, 0xc7, - 0x49, 0x61, 0x12, 0x2b, 0x6d, 0xd0, 0xb8, 0xda, 0x4a, 0x16, 0xa0, 0x79, 0x1d, 0xa0, 0xef, 0x5d, - 0x01, 0x91, 0x45, 0x49, 0x80, 0xb7, 0x0a, 0x5b, 0x81, 0xaa, 0x6a, 0x57, 0x17, 0x94, 0xcb, 0x49, - 0x4f, 0x8d, 0x4e, 0x14, 0x2f, 0x08, 0x84, 0x64, 0x9b, 0x4d, 0xd2, 0x3d, 0xd4, 0xee, 0x9a, 0x75, - 0x8e, 0x36, 0xa3, 0x41, 0xb2, 0xfe, 0x59, 0xf9, 0xf2, 0x90, 0xf5, 0x08, 0xa7, 0x80, 0xf5, 0x01, - 0x21, 0xaa, 0x9a, 0x0b, 0x0b, 0x04, 0x09, 0x19, 0xee, 0xeb, 0x05, 0xa7, 0xec, 0x2c, 0x65, 0xcb, - 0xc2, 0x3d, 0x45, 0x7d, 0x50, 0xa9, 0x56, 0x57, 0x6a, 0xd6, 0x8f, 0x40, 0x4d, 0x17, 0xf3, 0x3e, - 0x3e, 0x17, 0xba, 0xc3, 0x7a, 0x1e, 0x27, 0x42, 0x10, 0x61, 0x1a, 0x49, 0x87, 0x4d, 0x09, 0x96, - 0x04, 0x1b, 0xd7, 0xad, 0xc9, 0x02, 0x3e, 0x01, 0xf3, 0x21, 0xd1, 0x3b, 0x9c, 0x56, 0xac, 0xef, - 0xbd, 0x67, 0x4f, 0xf1, 0x23, 0xc6, 0xbe, 0x0e, 0xd0, 0x49, 0xd1, 0x2c, 0x9e, 0x2f, 0xe7, 0x13, - 0xd3, 0x58, 0xc0, 0xb3, 0x49, 0xa3, 0x3f, 0x7b, 0x25, 0xa3, 0x13, 0x78, 0xb9, 0xcd, 0x5b, 0xa0, - 0xbe, 0x1f, 0x1f, 0xfb, 0x23, 0x35, 0x5a, 0x2e, 0x5d, 0xcb, 0x42, 0xf1, 0x5a, 0x1e, 0x80, 0xa5, - 0x64, 0xe3, 0x39, 0x65, 0xba, 0x21, 0xc1, 0xef, 0x03, 0x90, 0xac, 0x4a, 0xaa, 0x91, 0xc5, 0x2d, - 0xbb, 0x96, 0x50, 0x8e, 0xbc, 0xb1, 0xa9, 0x5a, 0x1a, 0x9b, 0xaa, 0x96, 0x03, 0x96, 0xcf, 0x04, - 0xfe, 0x79, 0xba, 0x0e, 0x3f, 0x0e, 0x05, 0x7c, 0x0d, 0xcc, 0xa9, 0x1a, 0x4a, 0x80, 0x2a, 0xce, - 0x6c, 0x24, 0xf0, 0x91, 0xee, 0xda, 0xf9, 0xca, 0xcd, 0x42, 0x97, 0x7a, 0xc2, 0x2c, 0x35, 0xcb, - 0x3b, 0x15, 0x67, 0x69, 0x98, 0xab, 0x1f, 0x79, 0xc2, 0xfa, 0x05, 0xa8, 0x17, 0x00, 0xe1, 0x12, - 0x28, 0x65, 0x58, 0x25, 0xea, 0xc1, 0xbb, 0x60, 0x23, 0x07, 0x1a, 0x6f, 0xc3, 0x31, 0x62, 0xcd, - 0xb9, 0x91, 0x09, 0x8c, 0x75, 0x62, 0x61, 0x3d, 0x06, 0xeb, 0x47, 0x79, 0xd1, 0x67, 0x4d, 0x7e, - 0xec, 0x84, 0xc6, 0xf8, 0xde, 0xb0, 0x05, 0x6a, 0xd9, 0x4f, 0x4d, 0x7d, 0xfa, 0x8a, 0x93, 0x13, - 0xac, 0x01, 0x58, 0x39, 0x13, 0xf8, 0x84, 0x04, 0x5e, 0x0e, 0x76, 0xcd, 0x05, 0x1c, 0x4c, 0x02, - 0x4d, 0xfd, 0xbb, 0x25, 0x37, 0xc7, 0xc0, 0xc6, 0x59, 0x71, 0xc9, 0xd0, 0x03, 0xb8, 0x83, 0xf0, - 0x39, 0x91, 0x02, 0x3a, 0xa0, 0xa2, 0x97, 0x89, 0x38, 0xb3, 0xee, 0x5c, 0x9b, 0x59, 0xd1, 0xae, - 0x7d, 0x1d, 0xc8, 0x21, 0x92, 0x28, 0xa9, 0x5d, 0x8d, 0x65, 0xfd, 0x10, 0xac, 0x3d, 0x44, 0x72, - 0xc8, 0x89, 0x37, 0x16, 0xe3, 0x15, 0x50, 0x56, 0xf1, 0x33, 0x74, 0xfc, 0xd4, 0xa3, 0xda, 0x07, - 0xcc, 0x7b, 0x9f, 0x84, 0x8c, 0x4b, 0xe2, 0x5d, 0xba, 0x91, 0x97, 0x5c, 0xef, 0x39, 0x58, 0x53, - 0x97, 0x25, 0x48, 0xe0, 0xb9, 0xd9, 0x39, 0xe3, 0x38, 0xd6, 0xf7, 0x7e, 0x3a, 0x55, 0x75, 0x4c, - 0x9a, 0x4b, 0x0e, 0xb0, 0x1a, 0x4d, 0xd0, 0x85, 0xf5, 0x7b, 0x03, 0x98, 0xc7, 0x64, 0xb4, 0x2f, - 0x04, 0xed, 0x05, 0x03, 0x12, 0x48, 0xd5, 0x03, 0x11, 0x26, 0xea, 0x11, 0xbe, 0x01, 0x16, 0xb3, - 0x99, 0xab, 0x47, 0xad, 0xa1, 0x47, 0xed, 0x42, 0x4a, 0x54, 0x05, 0x06, 0xef, 0x02, 0x10, 0x72, - 0x12, 0xb9, 0xd8, 0x3d, 0x27, 0xa3, 0x24, 0x8a, 0x5b, 0xc5, 0x11, 0x1a, 0x7f, 0x08, 0xb0, 0x3b, - 0xc3, 0xae, 0x4f, 0xf1, 0x31, 0x19, 0x39, 0x55, 0x25, 0xdf, 0x3e, 0x26, 0x23, 0xb5, 0x13, 0xe9, - 0x0d, 0x53, 0xcf, 0xbd, 0xb2, 0x13, 0xbf, 0x58, 0x7f, 0x30, 0xc0, 0x8d, 0x2c, 0x1c, 0x69, 0xba, - 0x76, 0x86, 0x5d, 0xa5, 0xf1, 0x92, 0x7b, 0xbb, 0xe4, 0x6d, 0xe9, 0x0a, 0x6f, 0xdf, 0x07, 0x0b, - 0x59, 0x81, 0x28, 0x7f, 0xcb, 0x53, 0xf8, 0x5b, 0x4f, 0x35, 0x8e, 0xc9, 0xc8, 0xfa, 0x75, 0xc1, - 0xb7, 0x83, 0x51, 0xa1, 0xf7, 0xf1, 0xff, 0xe3, 0x5b, 0x66, 0xb6, 0xe8, 0x1b, 0x2e, 0xea, 0x5f, - 0x3a, 0x40, 0xf9, 0xf2, 0x01, 0xac, 0x3f, 0x1b, 0x60, 0xbd, 0x68, 0x55, 0x9c, 0xb2, 0x0e, 0x1f, - 0x06, 0xe4, 0x65, 0xd6, 0xf3, 0xf2, 0x2b, 0x15, 0xcb, 0xef, 0x09, 0x58, 0x1a, 0x73, 0x4a, 0x24, - 0xb7, 0xf1, 0xce, 0x54, 0x39, 0x56, 0xe8, 0xae, 0xce, 0x62, 0xf1, 0x1c, 0xc2, 0xfa, 0xab, 0x01, - 0x56, 0x53, 0x1f, 0xb3, 0xcb, 0x82, 0x3f, 0x06, 0x30, 0x3b, 0x5e, 0xbe, 0xbd, 0xc5, 0x29, 0xb5, - 0x92, 0x72, 0xd2, 0xd5, 0x2d, 0x4f, 0x8d, 0x52, 0x21, 0x35, 0xe0, 0x47, 0x60, 0x2d, 0x73, 0x39, - 0xd4, 0x01, 0x9a, 0x3a, 0x8a, 0xd9, 0x7e, 0x9a, 0x91, 0xac, 0xdf, 0x19, 0xf9, 0x38, 0x8c, 0xe7, - 0xb1, 0xd8, 0xf7, 0xfd, 0x64, 0xa9, 0x87, 0x21, 0x98, 0x8f, 0x47, 0xbe, 0x48, 0xfa, 0xc7, 0xd6, - 0x95, 0xc3, 0xfd, 0x90, 0x60, 0x3d, 0xdf, 0xef, 0xa8, 0x12, 0xfb, 0xfb, 0xd7, 0xdb, 0xb7, 0x7a, - 0x54, 0xf6, 0x87, 0x5d, 0x1b, 0xb3, 0x41, 0x2b, 0xf9, 0x90, 0x15, 0xff, 0xbb, 0x2d, 0xbc, 0xf3, - 0x96, 0x1c, 0x85, 0x44, 0xa4, 0x3a, 0xe2, 0x6f, 0xff, 0xf9, 0xe7, 0xdb, 0x86, 0x93, 0x9a, 0x39, - 0x78, 0xf2, 0xc5, 0xf3, 0x86, 0xf1, 0xe5, 0xf3, 0x86, 0xf1, 0xef, 0xe7, 0x0d, 0xe3, 0xd3, 0x17, - 0x8d, 0x99, 0x2f, 0x5f, 0x34, 0x66, 0xfe, 0xf5, 0xa2, 0x31, 0xf3, 0xcb, 0xf7, 0x2e, 0x83, 0xe6, - 0x31, 0xba, 0x9d, 0x7d, 0x3a, 0x8c, 0x7e, 0xd2, 0xfa, 0x64, 0xfc, 0xc3, 0xa4, 0xb6, 0xd7, 0x9d, - 0xd3, 0xdd, 0xf4, 0xdd, 0xff, 0x05, 0x00, 0x00, 0xff, 0xff, 0x24, 0x1f, 0x07, 0x8b, 0xc9, 0x14, - 0x00, 0x00, + // 2022 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcd, 0x73, 0x1c, 0x47, + 0x15, 0xd7, 0x68, 0x57, 0xd2, 0xee, 0x5b, 0x7d, 0xb6, 0x94, 0x78, 0x64, 0x84, 0x24, 0x4f, 0x70, + 0x10, 0x31, 0xde, 0x8d, 0x1c, 0xa8, 0x72, 0xb9, 0x48, 0xa5, 0xa4, 0x95, 0x13, 0x7f, 0xc4, 0xb6, + 0x32, 0x12, 0x76, 0x11, 0x0e, 0x53, 0xbd, 0x3d, 0xad, 0xdd, 0x46, 0xb3, 0xd3, 0xe3, 0xee, 0xde, + 0x71, 0xf6, 0xc2, 0x99, 0x03, 0x54, 0x85, 0x5b, 0x8a, 0x03, 0x04, 0x4e, 0x14, 0x17, 0xf8, 0x0f, + 0xb8, 0x51, 0x39, 0xe6, 0xc8, 0x29, 0xa1, 0xec, 0x03, 0x07, 0xfe, 0x09, 0xaa, 0x7b, 0x3e, 0x77, + 0x25, 0x99, 0x75, 0x85, 0x5c, 0xa4, 0x99, 0xd7, 0xbf, 0xf7, 0x7b, 0xaf, 0xfb, 0xbd, 0x7e, 0xef, + 0xed, 0xc0, 0x0d, 0x16, 0x2a, 0x2a, 0x48, 0x0f, 0xb3, 0xd0, 0x93, 0x94, 0x0c, 0x04, 0x53, 0xc3, + 0x16, 0x21, 0x71, 0x2b, 0x12, 0x3c, 0x66, 0x3e, 0x15, 0xad, 0x78, 0x37, 0x7f, 0x6e, 0x46, 0x82, + 0x2b, 0x8e, 0xde, 0x38, 0x47, 0xa7, 0x49, 0x48, 0xdc, 0xcc, 0x71, 0xf1, 0xee, 0xe5, 0xab, 0x17, + 0x11, 0xc7, 0xbb, 0xad, 0x67, 0x4c, 0xd0, 0x84, 0xeb, 0xf2, 0x5a, 0x97, 0x77, 0xb9, 0x79, 0x6c, + 0xe9, 0xa7, 0x54, 0xba, 0xd5, 0xe5, 0xbc, 0x1b, 0xd0, 0x96, 0x79, 0xeb, 0x0c, 0x4e, 0x5a, 0x8a, + 0xf5, 0xa9, 0x54, 0xb8, 0x1f, 0xa5, 0x80, 0xcd, 0x71, 0x80, 0x3f, 0x10, 0x58, 0x31, 0x1e, 0x66, + 0x04, 0xac, 0x43, 0x5a, 0x84, 0x0b, 0xda, 0x22, 0x01, 0xa3, 0xa1, 0xd2, 0x56, 0x93, 0xa7, 0x14, + 0xd0, 0xd2, 0x80, 0x80, 0x75, 0x7b, 0x2a, 0x11, 0xcb, 0x96, 0xa2, 0xa1, 0x4f, 0x45, 0x9f, 0x25, + 0xe0, 0xe2, 0x2d, 0x55, 0xd8, 0x28, 0xad, 0x13, 0x31, 0x8c, 0x14, 0x6f, 0x9d, 0xd2, 0xa1, 0x4c, + 0x57, 0xdf, 0x24, 0x5c, 0xf6, 0xb9, 0x6c, 0x51, 0xbd, 0xff, 0x90, 0xd0, 0x56, 0xbc, 0xdb, 0xa1, + 0x0a, 0xef, 0xe6, 0x82, 0xcc, 0xef, 0x14, 0xd7, 0xc1, 0xb2, 0xc0, 0x10, 0xce, 0x32, 0xbf, 0x57, + 0x70, 0x9f, 0x85, 0xbc, 0x65, 0xfe, 0x26, 0x22, 0xe7, 0xd7, 0x35, 0xb0, 0xdb, 0x3c, 0x94, 0x83, + 0x3e, 0x15, 0x7b, 0xbe, 0xcf, 0xf4, 0x2e, 0x0f, 0x05, 0x8f, 0xb8, 0xc4, 0x01, 0x5a, 0x83, 0x19, + 0xc5, 0x54, 0x40, 0x6d, 0x6b, 0xdb, 0xda, 0xa9, 0xbb, 0xc9, 0x0b, 0xda, 0x86, 0x86, 0x4f, 0x25, + 0x11, 0x2c, 0xd2, 0x60, 0x7b, 0xda, 0xac, 0x95, 0x45, 0x68, 0x1d, 0x6a, 0x49, 0x68, 0x98, 0x6f, + 0x57, 0xcc, 0xf2, 0x9c, 0x79, 0xbf, 0xeb, 0xa3, 0x0f, 0x60, 0x91, 0x85, 0x4c, 0x31, 0x1c, 0x78, + 0x3d, 0xaa, 0x0f, 0xc8, 0xae, 0x6e, 0x5b, 0x3b, 0x8d, 0x1b, 0x97, 0x9b, 0xac, 0x43, 0x9a, 0xfa, + 0x4c, 0x9b, 0xe9, 0x49, 0xc6, 0xbb, 0xcd, 0x3b, 0x06, 0xb1, 0x5f, 0xfd, 0xe2, 0xab, 0xad, 0x29, + 0x77, 0x21, 0xd5, 0x4b, 0x84, 0xe8, 0x0a, 0xcc, 0x77, 0x69, 0x48, 0x25, 0x93, 0x5e, 0x0f, 0xcb, + 0x9e, 0x3d, 0xb3, 0x6d, 0xed, 0xcc, 0xbb, 0x8d, 0x54, 0x76, 0x07, 0xcb, 0x1e, 0xda, 0x82, 0x46, + 0x87, 0x85, 0x58, 0x0c, 0x13, 0xc4, 0xac, 0x41, 0x40, 0x22, 0x32, 0x80, 0x36, 0x80, 0x8c, 0xf0, + 0xb3, 0xd0, 0xd3, 0x09, 0x60, 0xcf, 0xa5, 0x8e, 0x24, 0xc1, 0x6f, 0x66, 0xc1, 0x6f, 0x1e, 0x67, + 0xd9, 0xb1, 0x5f, 0xd3, 0x8e, 0x7c, 0xfa, 0xf5, 0x96, 0xe5, 0xd6, 0x8d, 0x9e, 0x5e, 0x41, 0x0f, + 0x61, 0x79, 0x10, 0x76, 0x78, 0xe8, 0xb3, 0xb0, 0xeb, 0x45, 0x54, 0x30, 0xee, 0xdb, 0x35, 0x43, + 0xb5, 0x7e, 0x86, 0xea, 0x20, 0xcd, 0xa3, 0x84, 0xe9, 0x33, 0xcd, 0xb4, 0x94, 0x2b, 0x1f, 0x1a, + 0x5d, 0xf4, 0x11, 0x20, 0x42, 0x62, 0xe3, 0x12, 0x1f, 0xa8, 0x8c, 0xb1, 0x3e, 0x39, 0xe3, 0x32, + 0x21, 0xf1, 0x71, 0xa2, 0x9d, 0x52, 0xfe, 0x1c, 0x2e, 0x29, 0x81, 0x43, 0x79, 0x42, 0xc5, 0x38, + 0x2f, 0x4c, 0xce, 0xfb, 0x5a, 0xc6, 0x31, 0x4a, 0x7e, 0x07, 0xb6, 0x49, 0x9a, 0x40, 0x9e, 0xa0, + 0x3e, 0x93, 0x4a, 0xb0, 0xce, 0x40, 0xeb, 0x7a, 0x27, 0x02, 0x13, 0x93, 0x23, 0x0d, 0x93, 0x04, + 0x9b, 0x19, 0xce, 0x1d, 0x81, 0xbd, 0x9f, 0xa2, 0xd0, 0x23, 0xf8, 0x5e, 0x27, 0xe0, 0xe4, 0x54, + 0x6a, 0xe7, 0xbc, 0x11, 0x26, 0x63, 0xba, 0xcf, 0xa4, 0xd4, 0x6c, 0xf3, 0xdb, 0xd6, 0x4e, 0xc5, + 0xbd, 0x92, 0x60, 0x0f, 0xa9, 0x38, 0x28, 0x21, 0x8f, 0x4b, 0x40, 0x74, 0x1d, 0x50, 0x8f, 0x49, + 0xc5, 0x05, 0x23, 0x38, 0xf0, 0x68, 0xa8, 0x04, 0xa3, 0xd2, 0x5e, 0x30, 0xea, 0x2b, 0xc5, 0xca, + 0xed, 0x64, 0x01, 0xdd, 0x83, 0x2b, 0x17, 0x1a, 0xf5, 0x48, 0x0f, 0x87, 0x21, 0x0d, 0xec, 0x45, + 0xb3, 0x95, 0x2d, 0xff, 0x02, 0x9b, 0xed, 0x04, 0x86, 0x56, 0x61, 0x46, 0xf1, 0xc8, 0x7b, 0x68, + 0x2f, 0x6d, 0x5b, 0x3b, 0x0b, 0x6e, 0x55, 0xf1, 0xe8, 0x21, 0x7a, 0x1b, 0xd6, 0x62, 0x1c, 0x30, + 0x1f, 0x2b, 0x2e, 0xa4, 0x17, 0xf1, 0x67, 0x54, 0x78, 0x04, 0x47, 0xf6, 0xb2, 0xc1, 0xa0, 0x62, + 0xed, 0x50, 0x2f, 0xb5, 0x71, 0x84, 0xde, 0x82, 0x95, 0x5c, 0xea, 0x49, 0xaa, 0x0c, 0x7c, 0xc5, + 0xc0, 0x97, 0xf2, 0x85, 0x23, 0xaa, 0x34, 0x76, 0x03, 0xea, 0x38, 0x08, 0xf8, 0xb3, 0x80, 0x49, + 0x65, 0xa3, 0xed, 0xca, 0x4e, 0xdd, 0x2d, 0x04, 0xe8, 0x32, 0xd4, 0x7c, 0x1a, 0x0e, 0xcd, 0xe2, + 0xaa, 0x59, 0xcc, 0xdf, 0x6f, 0xd5, 0x7e, 0xf5, 0xf9, 0xd6, 0xd4, 0x67, 0x9f, 0x6f, 0x4d, 0x39, + 0x7f, 0xb5, 0xe0, 0x52, 0x3b, 0x8f, 0x52, 0x9f, 0xc7, 0x38, 0xf8, 0x36, 0xab, 0xc1, 0x1e, 0xd4, + 0xa5, 0x3e, 0x26, 0x73, 0xff, 0xaa, 0xaf, 0x70, 0xff, 0x6a, 0x5a, 0x4d, 0x2f, 0x38, 0xbf, 0x9f, + 0x86, 0x8d, 0xcc, 0xe3, 0x07, 0xdc, 0x67, 0x27, 0x8c, 0xe0, 0x6f, 0xbb, 0x88, 0xe5, 0xc1, 0xad, + 0x4e, 0x10, 0xdc, 0x99, 0x57, 0x0b, 0xee, 0xec, 0x04, 0xc1, 0x9d, 0x7b, 0x59, 0x70, 0x6b, 0xa3, + 0xc1, 0x75, 0xfe, 0x60, 0xc1, 0xda, 0xed, 0xa7, 0x03, 0x16, 0xf3, 0xff, 0xd3, 0xc1, 0xdc, 0x87, + 0x05, 0x5a, 0xe2, 0x93, 0x76, 0x65, 0xbb, 0xb2, 0xd3, 0xb8, 0x71, 0xb5, 0x99, 0x74, 0x9f, 0x66, + 0xde, 0x94, 0xd2, 0x0e, 0xd4, 0x2c, 0x5b, 0x77, 0x47, 0x75, 0x6f, 0x4d, 0xdb, 0x96, 0xf3, 0x27, + 0x0b, 0x2e, 0xeb, 0x7b, 0xd3, 0xa5, 0x2e, 0x7d, 0x86, 0x85, 0x7f, 0x40, 0x43, 0xde, 0x97, 0xdf, + 0xd8, 0x4f, 0x07, 0x16, 0x7c, 0xc3, 0xe4, 0x29, 0xee, 0x61, 0xdf, 0x37, 0x7e, 0x1a, 0x8c, 0x16, + 0x1e, 0xf3, 0x3d, 0xdf, 0x47, 0x3b, 0xb0, 0x5c, 0x60, 0x84, 0x4e, 0x78, 0x9d, 0x87, 0x1a, 0xb6, + 0x98, 0xc1, 0xcc, 0x35, 0xa0, 0xce, 0x7f, 0x2c, 0x58, 0xfe, 0x20, 0xe0, 0x1d, 0x1c, 0x1c, 0x05, + 0x58, 0xf6, 0x74, 0xcd, 0x18, 0xea, 0xfc, 0x15, 0x34, 0x2d, 0xd6, 0xc6, 0xbd, 0x89, 0xf3, 0x57, + 0xab, 0x99, 0xf6, 0xf1, 0x1e, 0xac, 0xe4, 0xe5, 0x33, 0xcf, 0x37, 0xb3, 0x9b, 0xfd, 0xd5, 0xe7, + 0x5f, 0x6d, 0x2d, 0x65, 0xb9, 0xdd, 0x36, 0xb9, 0x77, 0xe0, 0x2e, 0x91, 0x11, 0x81, 0x8f, 0x36, + 0xa1, 0xc1, 0x3a, 0xc4, 0x93, 0xf4, 0xa9, 0x17, 0x0e, 0xfa, 0x26, 0x55, 0xab, 0x6e, 0x9d, 0x75, + 0xc8, 0x11, 0x7d, 0xfa, 0x70, 0xd0, 0x47, 0xef, 0xc0, 0xeb, 0xd9, 0xe4, 0xe4, 0xc5, 0x38, 0xf0, + 0xb4, 0xbe, 0x3e, 0x0e, 0x61, 0xb2, 0x77, 0xde, 0x5d, 0xcd, 0x56, 0x1f, 0xe3, 0x40, 0x1b, 0xdb, + 0xf3, 0x7d, 0xe1, 0xfc, 0x7d, 0x16, 0x66, 0x0f, 0xb1, 0xc0, 0x7d, 0x89, 0x8e, 0x61, 0x49, 0xd1, + 0x7e, 0x14, 0x60, 0x45, 0xbd, 0xa4, 0x35, 0xa7, 0x3b, 0xbd, 0x66, 0x5a, 0x76, 0x79, 0xca, 0x69, + 0x96, 0xe6, 0x9a, 0x78, 0xb7, 0xd9, 0x36, 0xd2, 0x23, 0x85, 0x15, 0x75, 0x17, 0x33, 0x8e, 0x44, + 0x88, 0x6e, 0x82, 0xad, 0xc4, 0x40, 0xaa, 0xa2, 0x69, 0x16, 0xdd, 0x22, 0x89, 0xe5, 0xeb, 0xd9, + 0x7a, 0xd2, 0x67, 0xf2, 0x2e, 0x71, 0x7e, 0x7f, 0xac, 0x7c, 0x93, 0xfe, 0x78, 0x04, 0xab, 0x7a, + 0xb8, 0x18, 0xe7, 0xac, 0x4e, 0xce, 0xb9, 0xa2, 0xf5, 0x47, 0x49, 0x3f, 0x02, 0x14, 0x4b, 0x32, + 0xce, 0x39, 0xf3, 0x0a, 0x7e, 0xc6, 0x92, 0x8c, 0x52, 0xfa, 0xb0, 0x21, 0x75, 0xf2, 0x79, 0x7d, + 0xaa, 0x4c, 0xb7, 0x8d, 0x02, 0x1a, 0x32, 0xd9, 0xcb, 0xc8, 0x67, 0x27, 0x27, 0x5f, 0x37, 0x44, + 0x0f, 0x34, 0x8f, 0x9b, 0xd1, 0xa4, 0x56, 0xda, 0xb0, 0x79, 0xbe, 0x95, 0x3c, 0x40, 0x73, 0x26, + 0x40, 0xdf, 0x39, 0x87, 0x22, 0x8f, 0x92, 0x84, 0x37, 0x4b, 0x53, 0x81, 0xbe, 0xd5, 0x9e, 0xb9, + 0x50, 0x9e, 0xa0, 0x5d, 0xdd, 0x3a, 0x71, 0x32, 0x20, 0x50, 0x9a, 0x4f, 0x36, 0x69, 0xf5, 0xd0, + 0xb3, 0x6b, 0x5e, 0x39, 0xda, 0x9c, 0x85, 0xe9, 0xf8, 0xe7, 0x14, 0xc3, 0x43, 0x5e, 0x23, 0xdc, + 0x12, 0xd7, 0xfb, 0x94, 0xea, 0xdb, 0x5c, 0x1a, 0x20, 0x68, 0xc4, 0x49, 0xcf, 0x0c, 0x38, 0x15, + 0x77, 0x31, 0x1f, 0x16, 0x6e, 0x6b, 0x29, 0xfa, 0x18, 0xae, 0x85, 0x83, 0x7e, 0x87, 0x0a, 0x8f, + 0x9f, 0x24, 0x40, 0x53, 0x01, 0xa4, 0xc2, 0x42, 0x79, 0x82, 0x12, 0xca, 0x62, 0x9d, 0x99, 0x89, + 0xe7, 0xd2, 0xcc, 0x2f, 0x15, 0xf7, 0x6a, 0xa2, 0xf2, 0xe8, 0xc4, 0x70, 0xc8, 0x63, 0x7e, 0xa4, + 0xe1, 0x6e, 0x86, 0x4e, 0x1c, 0x93, 0xf7, 0xaa, 0xb5, 0xda, 0x72, 0xdd, 0xf9, 0x01, 0xd4, 0x4d, + 0xa1, 0xd8, 0x23, 0xa7, 0xd2, 0x54, 0x6f, 0xdf, 0x17, 0x54, 0x4a, 0x2a, 0x6d, 0x2b, 0xad, 0xde, + 0x99, 0xc0, 0x51, 0xb0, 0x7e, 0xd1, 0x08, 0x2e, 0xd1, 0x13, 0x98, 0x8b, 0xa8, 0x99, 0x0f, 0x8d, + 0x62, 0xe3, 0xc6, 0xbb, 0xcd, 0x09, 0x7e, 0x20, 0x35, 0x2f, 0x22, 0x74, 0x33, 0x36, 0x47, 0x14, + 0x83, 0xff, 0x58, 0xa7, 0x97, 0xe8, 0xf1, 0xb8, 0xd1, 0x9f, 0xbc, 0x92, 0xd1, 0x31, 0xbe, 0xc2, + 0xe6, 0x35, 0x68, 0xec, 0x25, 0xdb, 0xfe, 0x50, 0xb7, 0xad, 0x33, 0xc7, 0x32, 0x5f, 0x3e, 0x96, + 0x7b, 0xb0, 0x98, 0x4e, 0x53, 0xc7, 0xdc, 0x14, 0x3b, 0xf4, 0x5d, 0x80, 0x74, 0x0c, 0xd3, 0x45, + 0x32, 0x69, 0x07, 0xf5, 0x54, 0x72, 0xd7, 0x1f, 0xe9, 0xd8, 0xd3, 0x23, 0x1d, 0xdb, 0x71, 0x61, + 0xe9, 0xb1, 0x24, 0x3f, 0xcd, 0x46, 0xed, 0x47, 0x91, 0x44, 0xaf, 0xc1, 0xac, 0xbe, 0x9f, 0x29, + 0x51, 0xd5, 0x9d, 0x89, 0x25, 0xb9, 0x6b, 0x3a, 0x42, 0x31, 0xce, 0xf3, 0xc8, 0x63, 0xbe, 0xb4, + 0xa7, 0xb7, 0x2b, 0x3b, 0x55, 0x77, 0x71, 0x50, 0xa8, 0xdf, 0xf5, 0xa5, 0xf3, 0x33, 0x68, 0x94, + 0x08, 0xd1, 0x22, 0x4c, 0xe7, 0x5c, 0xd3, 0xcc, 0x47, 0xb7, 0x60, 0xbd, 0x20, 0x1a, 0x2d, 0xf1, + 0x09, 0x63, 0xdd, 0xbd, 0x94, 0x03, 0x46, 0xaa, 0xbc, 0x74, 0x1e, 0xc1, 0xda, 0xdd, 0xa2, 0xa0, + 0xe4, 0x0d, 0x64, 0x64, 0x87, 0xd6, 0xe8, 0x4c, 0xb2, 0x01, 0xf5, 0xfc, 0x67, 0xac, 0xd9, 0x7d, + 0xd5, 0x2d, 0x04, 0x4e, 0x1f, 0x96, 0x1f, 0x4b, 0x72, 0x44, 0x43, 0xbf, 0x20, 0xbb, 0xe0, 0x00, + 0xf6, 0xc7, 0x89, 0x26, 0xfe, 0x4d, 0x54, 0x98, 0xe3, 0xb0, 0xfe, 0xb8, 0x3c, 0xc0, 0x98, 0xe6, + 0x7e, 0x88, 0xc9, 0x29, 0x55, 0x12, 0xb9, 0x50, 0x35, 0x83, 0x4a, 0x92, 0x59, 0x37, 0x2f, 0xcc, + 0xac, 0x78, 0xb7, 0x79, 0x11, 0xc9, 0x01, 0x56, 0x38, 0xad, 0x0b, 0x86, 0xcb, 0xf9, 0x3e, 0xac, + 0x3e, 0xc0, 0x6a, 0x20, 0xa8, 0x3f, 0x12, 0xe3, 0x65, 0xa8, 0xe8, 0xf8, 0x59, 0x26, 0x7e, 0xfa, + 0x51, 0xcf, 0x1a, 0xf6, 0xed, 0x4f, 0x22, 0x2e, 0x14, 0xf5, 0xcf, 0x9c, 0xc8, 0x4b, 0x8e, 0xf7, + 0x14, 0x56, 0xf5, 0x61, 0x49, 0x1a, 0xfa, 0x5e, 0xbe, 0xcf, 0x24, 0x8e, 0x8d, 0x1b, 0x3f, 0x9e, + 0xe8, 0x76, 0x8c, 0x9b, 0x4b, 0x37, 0xb0, 0x12, 0x8f, 0xc9, 0xa5, 0xf3, 0x5b, 0x0b, 0xec, 0xfb, + 0x74, 0xb8, 0x27, 0x25, 0xeb, 0x86, 0x7d, 0x1a, 0x2a, 0x5d, 0x5f, 0x31, 0xa1, 0xfa, 0x11, 0xbd, + 0x01, 0x0b, 0x79, 0x3f, 0x37, 0x6d, 0xdc, 0x32, 0x6d, 0x7c, 0x3e, 0x13, 0xea, 0x0b, 0x86, 0x6e, + 0x01, 0x44, 0x82, 0xc6, 0x1e, 0xf1, 0x4e, 0xe9, 0x30, 0x8d, 0xe2, 0x46, 0xb9, 0x3d, 0x27, 0x1f, + 0x19, 0x9a, 0x87, 0x83, 0x4e, 0xc0, 0xc8, 0x7d, 0x3a, 0x74, 0x6b, 0x1a, 0xdf, 0xbe, 0x4f, 0x87, + 0x7a, 0xde, 0x32, 0xd3, 0xab, 0xe9, 0xa9, 0x15, 0x37, 0x79, 0x71, 0x7e, 0x67, 0xc1, 0xa5, 0x3c, + 0x1c, 0x59, 0xba, 0x1e, 0x0e, 0x3a, 0x5a, 0xe3, 0x25, 0xe7, 0x76, 0xc6, 0xdb, 0xe9, 0x73, 0xbc, + 0x7d, 0x0f, 0xe6, 0xf3, 0x0b, 0xa2, 0xfd, 0xad, 0x4c, 0xe0, 0x6f, 0x23, 0xd3, 0xb8, 0x4f, 0x87, + 0xce, 0x2f, 0x4b, 0xbe, 0xed, 0x0f, 0x4b, 0xb5, 0x4f, 0xfc, 0x0f, 0xdf, 0x72, 0xb3, 0x65, 0xdf, + 0x48, 0x59, 0xff, 0xcc, 0x06, 0x2a, 0x67, 0x37, 0xe0, 0xfc, 0xd1, 0x82, 0xb5, 0xb2, 0x55, 0x79, + 0xcc, 0x0f, 0xc5, 0x20, 0xa4, 0x2f, 0xb3, 0x5e, 0x5c, 0xbf, 0xe9, 0xf2, 0xf5, 0x7b, 0x02, 0x8b, + 0x23, 0x4e, 0xc9, 0xf4, 0x34, 0xde, 0x9e, 0x28, 0xc7, 0x4a, 0xd5, 0xd5, 0x5d, 0x28, 0xef, 0x43, + 0x3a, 0xff, 0xb0, 0x60, 0x25, 0xf3, 0x31, 0x3f, 0x2c, 0xf4, 0x43, 0x40, 0xf9, 0xf6, 0x8a, 0xc9, + 0x30, 0x49, 0xa9, 0xe5, 0x6c, 0x25, 0x1b, 0x0b, 0x8b, 0xd4, 0x98, 0x2e, 0xa5, 0x06, 0xfa, 0x10, + 0x56, 0x73, 0x97, 0x23, 0x13, 0xa0, 0x89, 0xa3, 0x98, 0xcf, 0xbe, 0xb9, 0x08, 0x6d, 0x41, 0xe3, + 0x17, 0x9c, 0x85, 0xe5, 0xcf, 0x43, 0x15, 0x17, 0xb4, 0x28, 0xf9, 0xf2, 0xe3, 0xfc, 0xc6, 0x2a, + 0xfa, 0x65, 0xda, 0x73, 0xf7, 0x82, 0x20, 0xfd, 0x45, 0x81, 0x22, 0x98, 0xcb, 0xba, 0x76, 0x52, + 0x60, 0x36, 0xce, 0x9d, 0x2c, 0x0e, 0x28, 0x31, 0xc3, 0xc5, 0x4d, 0x7d, 0x07, 0xff, 0xf2, 0xf5, + 0xd6, 0xb5, 0x2e, 0x53, 0xbd, 0x41, 0xa7, 0x49, 0x78, 0xbf, 0x95, 0x7e, 0x45, 0x4b, 0xfe, 0x5d, + 0x97, 0xfe, 0x69, 0x4b, 0x0d, 0x23, 0x2a, 0x33, 0x1d, 0xf9, 0xe7, 0x7f, 0xff, 0xed, 0x2d, 0xcb, + 0xcd, 0xcc, 0xec, 0x3f, 0xf9, 0xe2, 0xf9, 0xa6, 0xf5, 0xe5, 0xf3, 0x4d, 0xeb, 0x5f, 0xcf, 0x37, + 0xad, 0x4f, 0x5f, 0x6c, 0x4e, 0x7d, 0xf9, 0x62, 0x73, 0xea, 0x9f, 0x2f, 0x36, 0xa7, 0x3e, 0x7e, + 0xf7, 0x2c, 0x69, 0x11, 0xc4, 0xeb, 0xf9, 0x77, 0xcb, 0xf8, 0x47, 0xad, 0x4f, 0x46, 0xbf, 0x8a, + 0x1a, 0x7b, 0x9d, 0x59, 0x53, 0x6e, 0xdf, 0xf9, 0x6f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xd1, 0x49, + 0x1e, 0xe4, 0x46, 0x15, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -2275,6 +2300,11 @@ func (m *Params) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.NumberOfEpochsToStartReceivingRewards != 0 { + i = encodeVarintProvider(dAtA, i, uint64(m.NumberOfEpochsToStartReceivingRewards)) + i-- + dAtA[i] = 0x58 + } if m.BlocksPerEpoch != 0 { i = encodeVarintProvider(dAtA, i, uint64(m.BlocksPerEpoch)) i-- @@ -3009,6 +3039,11 @@ func (m *ConsumerValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if m.JoinHeight != 0 { + i = encodeVarintProvider(dAtA, i, uint64(m.JoinHeight)) + i-- + dAtA[i] = 0x20 + } if m.ConsumerPublicKey != nil { { size, err := m.ConsumerPublicKey.MarshalToSizedBuffer(dAtA[:i]) @@ -3328,6 +3363,9 @@ func (m *Params) Size() (n int) { if m.BlocksPerEpoch != 0 { n += 1 + sovProvider(uint64(m.BlocksPerEpoch)) } + if m.NumberOfEpochsToStartReceivingRewards != 0 { + n += 1 + sovProvider(uint64(m.NumberOfEpochsToStartReceivingRewards)) + } return n } @@ -3624,6 +3662,9 @@ func (m *ConsumerValidator) Size() (n int) { l = m.ConsumerPublicKey.Size() n += 1 + l + sovProvider(uint64(l)) } + if m.JoinHeight != 0 { + n += 1 + sovProvider(uint64(m.JoinHeight)) + } return n } @@ -5503,6 +5544,25 @@ func (m *Params) Unmarshal(dAtA []byte) error { break } } + case 11: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field NumberOfEpochsToStartReceivingRewards", wireType) + } + m.NumberOfEpochsToStartReceivingRewards = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.NumberOfEpochsToStartReceivingRewards |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipProvider(dAtA[iNdEx:]) @@ -7441,6 +7501,25 @@ func (m *ConsumerValidator) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 4: + if wireType != 0 { + return fmt.Errorf("proto: wrong wireType = %d for field JoinHeight", wireType) + } + m.JoinHeight = 0 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + m.JoinHeight |= int64(b&0x7F) << shift + if b < 0x80 { + break + } + } default: iNdEx = preIndex skippy, err := skipProvider(dAtA[iNdEx:])