Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat!: only distribute rewards to validators that have been validating a consumer chain for some time #1929

Merged
merged 10 commits into from
Jun 19, 2024
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
- Only start distributing rewards to validators after they have been validating
insumity marked this conversation as resolved.
Show resolved Hide resolved
for a fixed number of blocks. Introduces the `NumberOfEpochsToStartReceivingRewards` param.
([\#1929](https://github.com/cosmos/interchain-security/pull/1929))
Original file line number Diff line number Diff line change
@@ -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))
11 changes: 10 additions & 1 deletion docs/docs/validators/withdraw_rewards.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,17 @@
sidebar_position: 3
---

# Withdrawing consumer chain validator rewards
# Consumer chain validator rewards

:::warning
insumity marked this conversation as resolved.
Show resolved Hide resolved
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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a blank line above the heading for better Markdown formatting.

+ 
## Withdrawing rewards
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
## Withdrawing rewards
+
## Withdrawing rewards
Tools
Markdownlint

15-15: Expected: 1; Actual: 0; Below (MD022, blanks-around-headings)
Headings should be surrounded by blank lines

Here are example steps for withdrawing rewards from consumer chains in the provider chain

:::info
Expand Down
8 changes: 8 additions & 0 deletions proto/interchain_security/ccv/provider/v1/provider.proto
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down
135 changes: 126 additions & 9 deletions tests/integration/distribution.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -718,7 +723,7 @@ func (s *CCVTestSuite) TestAllocateTokens() {
for chainID := range s.consumerBundles {
// update consumer allocation
providerKeeper.SetConsumerRewardsAllocation(
s.providerCtx(),
providerCtx,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

The SetConsumerRewardsAllocation method in x/ccv/provider/keeper/distribution.go does not appear to handle any edge cases explicitly. It simply marshals the pool object and stores it using the chainID as the key. There is no error handling or validation of the input parameters.

  • x/ccv/provider/keeper/distribution.go:236-240

Category:

Analysis chain

Ensure that the SetConsumerRewardsAllocation method handles edge cases appropriately.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify the handling of edge cases in `SetConsumerRewardsAllocation`.
# Test: Search for error handling in the method implementation.
ast-grep --lang go --pattern $'func (providerKeeper *ProviderKeeper) SetConsumerRewardsAllocation($_, $_, $_) { $$$ }'

Length of output: 119



Script:

#!/bin/bash
# Locate the `SetConsumerRewardsAllocation` method definition in the codebase.
rg 'func (providerKeeper \*ProviderKeeper) SetConsumerRewardsAllocation' --no-heading --line-number --color=never

Length of output: 115



Script:

#!/bin/bash
# Search for methods related to consumer rewards allocation in the codebase.
rg 'func .*ConsumerRewards' --no-heading --line-number --color=never

Length of output: 3381



Script:

#!/bin/bash
# Retrieve the implementation of the `SetConsumerRewardsAllocation` method in `x/ccv/provider/keeper/distribution.go`.
sed -n '236,256p' x/ccv/provider/keeper/distribution.go

Length of output: 912

chainID,
providertypes.ConsumerRewardsAllocation{
Rewards: sdk.NewDecCoinsFromCoins(rewardsPerConsumer...),
Expand All @@ -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,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

The BeginBlockRD function in x/ccv/provider/keeper/distribution.go does perform a state update by calling k.AllocateTokens(ctx) if the block height is greater than 1. However, there is no explicit exception handling within the function.

  • x/ccv/provider/keeper/distribution.go:22-24: The function checks the block height and calls k.AllocateTokens(ctx) for state updates.
  • There is no explicit exception handling code present in the function.

Please ensure that BeginBlockRD includes proper exception handling mechanisms to manage any potential errors during execution.

  • Add exception handling in BeginBlockRD in x/ccv/provider/keeper/distribution.go.
Analysis chain

Ensure that BeginBlockRD properly updates relevant state and handles any exceptions.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that `BeginBlockRD` updates state and handles exceptions.
# Test: Search for state updates and exception handling in `BeginBlockRD`.
ast-grep --lang go --pattern $'func (providerKeeper *ProviderKeeper) BeginBlockRD($_, $_) { $$$ }'

Length of output: 99



Script:

#!/bin/bash
# Searching for the function `BeginBlockRD` in the Go codebase
rg 'BeginBlockRD' --type go

Length of output: 622



Script:

#!/bin/bash
# Extract the implementation of `BeginBlockRD` from `x/ccv/provider/keeper/distribution.go`
ast-grep --lang go --pattern $'func (k Keeper) BeginBlockRD(ctx sdk.Context, req abci.RequestBeginBlock) { $$$ }' x/ccv/provider/keeper/distribution.go

Length of output: 667

abci.RequestBeginBlock{
LastCommitInfo: abci.CommitInfo{
Votes: votes,
Expand All @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Tip

Codebase Verification

The calculation of validatorsExpRewards involves multiple operations, including MulDecTruncate and MulDec. However, there is no explicit check for overflow in these calculations.

  • validatorsExpRewards := rewardsPerConsumerDec.MulDecTruncate(math.LegacyOneDec().Sub(communityTax)).MulDec(sdk.NewDec(int64(consuNum)))
  • perValExpReward := validatorsExpRewards.QuoDec(sdk.NewDec(int64(valNum)))

These calculations could potentially lead to overflow issues if the values involved are large enough. It is advisable to add explicit overflow checks or handle potential overflow scenarios to ensure robustness.

  • [tests/integration/distribution.go:768]
Analysis chain

Check the calculation of validatorsExpRewards for potential overflow issues.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify the calculation of `validatorsExpRewards` for overflow.
# Test: Search for overflow checks in the calculation.
ast-grep --lang go --pattern $'$_ = $_.MulDecTruncate($_).MulDec($_)' --lang go

Length of output: 241



Script:

#!/bin/bash
# Description: Verify the calculation of `validatorsExpRewards` for overflow.
# Test: Search for overflow checks in the calculation.
ast-grep --lang go --pattern $'$_ = $_.MulDecTruncate($_).MulDec($_)'

Length of output: 70



Script:

#!/bin/bash
# Locate the definition and calculation of `validatorsExpRewards` in the codebase.
rg 'validatorsExpRewards'

Length of output: 341



Script:

#!/bin/bash
# Extract and display the lines around the definition and calculation of `validatorsExpRewards` for detailed examination.
rg -A 10 -B 10 'validatorsExpRewards' tests/integration/distribution.go

Length of output: 1629

validatorsExpRewards := rewardsPerConsumerDec.
MulDecTruncate(math.LegacyOneDec().Sub(communityTax)).
// multiply by the number of consumers since all the validators opted in
Expand All @@ -770,15 +775,15 @@ 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...),
)
}

commPoolExpRewards := sdk.NewDecCoinsFromCoins(totalRewards...).Sub(validatorsExpRewards)
currCommPool := distributionKeeper.GetFeePoolCommunityCoins(s.providerCtx())
currCommPool := distributionKeeper.GetFeePoolCommunityCoins(providerCtx)

s.Require().Equal(currCommPool, (lastCommPool.Add(commPoolExpRewards...)))
}
Expand Down Expand Up @@ -935,7 +940,7 @@ func (s *CCVTestSuite) prepareRewardDist() {
s.coordinator.CommitNBlocks(s.consumerChain, uint64(blocksToGo))
}

func (s *CCVTestSuite) TestAllocateTokensToValidator() {
func (s *CCVTestSuite) TestAllocateTokensToConsumerValidators() {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test was practically testing AllocateTokensToConsumerValidators so renamed it.

providerKeeper := s.providerApp.GetProviderKeeper()
distributionKeeper := s.providerApp.GetTestDistributionKeeper()
bankKeeper := s.providerApp.GetTestBankKeeper()
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
insumity marked this conversation as resolved.
Show resolved Hide resolved

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()
Expand Down
20 changes: 20 additions & 0 deletions x/ccv/provider/keeper/distribution.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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
Expand Down Expand Up @@ -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)
insumity marked this conversation as resolved.
Show resolved Hide resolved
if !k.IsEligibleForConsumerRewards(ctx, v.JoinHeight) {
continue
}

totalPower += v.Power
}

Expand Down
26 changes: 26 additions & 0 deletions x/ccv/provider/keeper/distribution_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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))
}
9 changes: 9 additions & 0 deletions x/ccv/provider/keeper/params.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand All @@ -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),
)
}

Expand Down
1 change: 1 addition & 0 deletions x/ccv/provider/keeper/params_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ func TestParams(t *testing.T) {
Amount: sdk.NewInt(10000000),
},
600,
24,
)
providerKeeper.SetParams(ctx, newParams)
params = providerKeeper.GetParams(ctx)
Expand Down
3 changes: 2 additions & 1 deletion x/ccv/provider/keeper/proposal_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down
Loading
Loading