-
Notifications
You must be signed in to change notification settings - Fork 138
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat!: Let consumer chains choose a minimum stake and validator rank (#…
…2035) * Add minimum stake key * Add MinValidatorRank prefix * Add keeper and tests for new parameters * Utilize MinStake and MaxRank parameters in computing next validators * Mention MinStake and MaxRank in adr * Add test for FulfillsMinStake * Handle multiple validators with same power * Add min stake and max rank to docs * Add minStake and maxRank to proposals * Check for untyped equality * Handle minStake and maxRank in Msgs * Add integration test for min stake and max rank * Rename test and testfile * Update docs/docs/adrs/adr-017-allowing-inactive-validators.md * Add changelog entries for maxrank and minstake * Address comments * Clarify which feature is disabled by setting maxrank * Test validator powers cap and validator set cap into int param testing function
- Loading branch information
1 parent
d2ee22b
commit cb44240
Showing
27 changed files
with
1,262 additions
and
301 deletions.
There are no files selected for viewing
3 changes: 1 addition & 2 deletions
3
.changelog/unreleased/bug-fixes/provider/1925-apply-audit-suggestions.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
- Apply audit suggestions that include a bug fix in the way we compute the | ||
maximum capped power. ([\#1925](https://github.com/cosmos/interchain- | ||
security/pull/1925)) | ||
maximum capped power. ([\#1925](https://github.com/cosmos/interchain-security/pull/1925)) |
2 changes: 2 additions & 0 deletions
2
.changelog/unreleased/features/provider/2035-min-stake-max-rank.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
- Add minimum stake and maximum validator rank requirements to let consumer chains | ||
determine requirements for validators that validate their chain. ([\#2035](https://github.com/cosmos/interchain-security/pull/2035)) |
3 changes: 1 addition & 2 deletions
3
.changelog/unreleased/state-breaking/provider/1925-apply-audit-suggestions.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
- Apply audit suggestions that include a bug fix in the way we compute the | ||
maximum capped power. ([\#1925](https://github.com/cosmos/interchain- | ||
security/pull/1925)) | ||
maximum capped power. ([\#1925](https://github.com/cosmos/interchain-security/pull/1925)) |
2 changes: 2 additions & 0 deletions
2
.changelog/unreleased/state-breaking/provider/2035-min-stake-max-rank.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
- Add minimum stake and maximum validator rank requirements to let consumer chains | ||
determine requirements for validators that validate their chain. ([\#2035](https://github.com/cosmos/interchain-security/pull/2035)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,232 @@ | ||
package integration | ||
|
||
import ( | ||
"testing" | ||
|
||
"cosmossdk.io/math" | ||
ccv "github.com/cosmos/interchain-security/v5/x/ccv/types" | ||
"github.com/stretchr/testify/require" | ||
|
||
icstestingutils "github.com/cosmos/interchain-security/v5/testutil/ibc_testing" | ||
|
||
appConsumer "github.com/cosmos/interchain-security/v5/app/consumer" | ||
appProvider "github.com/cosmos/interchain-security/v5/app/provider" | ||
) | ||
|
||
// we need a stake multiplier because tokens do not directly correspond to voting power | ||
// this is needed because 1000000 tokens = 1 voting power, so lower multipliers | ||
// will be verbose and harder to read because small token numbers | ||
// won't correspond to at least one voting power | ||
const stake_multiplier = 1000000 | ||
|
||
// TestMinStakeMaxRank tests the min stake and max rank parameters. | ||
// It starts a provider and single consumer chain, | ||
// sets the initial powers according to the input, and then | ||
// sets the min stake and max rank parameters according to the test case. | ||
// Finally, it checks that the validator set on the consumer chain is as expected | ||
// according to the min stake and max rank parameters. | ||
func TestMinStakeMaxRank(t *testing.T) { | ||
testCases := []struct { | ||
name string | ||
stakedTokens []int64 | ||
minStake uint64 | ||
maxRank uint32 | ||
expectedConsuValSet []int64 | ||
}{ | ||
{ | ||
name: "disabled min stake and max rank", | ||
stakedTokens: []int64{ | ||
1 * stake_multiplier, | ||
2 * stake_multiplier, | ||
3 * stake_multiplier, | ||
4 * stake_multiplier, | ||
}, | ||
minStake: 0, | ||
maxRank: 0, | ||
expectedConsuValSet: []int64{ | ||
1 * stake_multiplier, | ||
2 * stake_multiplier, | ||
3 * stake_multiplier, | ||
4 * stake_multiplier, | ||
}, | ||
}, | ||
{ | ||
name: "stake multiplier - standard case", | ||
stakedTokens: []int64{ | ||
1 * stake_multiplier, | ||
2 * stake_multiplier, | ||
3 * stake_multiplier, | ||
4 * stake_multiplier, | ||
}, | ||
minStake: 3 * stake_multiplier, | ||
maxRank: 0, | ||
expectedConsuValSet: []int64{ | ||
3 * stake_multiplier, | ||
4 * stake_multiplier, | ||
}, | ||
}, | ||
{ | ||
name: "validator rank - standard case", | ||
stakedTokens: []int64{ | ||
1 * stake_multiplier, | ||
2 * stake_multiplier, | ||
3 * stake_multiplier, | ||
4 * stake_multiplier, | ||
}, | ||
minStake: 0, | ||
maxRank: 2, | ||
expectedConsuValSet: []int64{ | ||
3 * stake_multiplier, | ||
4 * stake_multiplier, | ||
}, | ||
}, | ||
{ | ||
name: "check max rank precedence over min stake", | ||
stakedTokens: []int64{ | ||
1 * stake_multiplier, | ||
2 * stake_multiplier, | ||
3 * stake_multiplier, | ||
4 * stake_multiplier, | ||
}, | ||
minStake: 4 * stake_multiplier, | ||
maxRank: 2, | ||
expectedConsuValSet: []int64{ | ||
4 * stake_multiplier, | ||
}, | ||
}, | ||
{ | ||
name: "check min stake precedence over max rank", | ||
stakedTokens: []int64{ | ||
1 * stake_multiplier, | ||
2 * stake_multiplier, | ||
3 * stake_multiplier, | ||
4 * stake_multiplier, | ||
}, | ||
minStake: 2 * stake_multiplier, | ||
maxRank: 1, | ||
expectedConsuValSet: []int64{ | ||
4 * stake_multiplier, | ||
}, | ||
}, | ||
{ | ||
name: "check min stake with multiple equal stakes", | ||
stakedTokens: []int64{ | ||
1 * stake_multiplier, | ||
2 * stake_multiplier, | ||
2 * stake_multiplier, | ||
2 * stake_multiplier, | ||
}, | ||
minStake: 2 * stake_multiplier, | ||
maxRank: 0, | ||
expectedConsuValSet: []int64{ | ||
2 * stake_multiplier, | ||
2 * stake_multiplier, | ||
2 * stake_multiplier, | ||
}, | ||
}, | ||
{ | ||
name: "check max rank with multiple equal stakes", | ||
stakedTokens: []int64{ | ||
1 * stake_multiplier, | ||
2 * stake_multiplier, | ||
2 * stake_multiplier, | ||
2 * stake_multiplier, | ||
}, | ||
minStake: 0, | ||
maxRank: 1, | ||
expectedConsuValSet: []int64{ | ||
2 * stake_multiplier, | ||
2 * stake_multiplier, | ||
2 * stake_multiplier, | ||
}, | ||
}, | ||
} | ||
for _, tc := range testCases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
s := NewCCVTestSuite[*appProvider.App, *appConsumer.App]( | ||
// Pass in ibctesting.AppIniters for provider and consumer. | ||
icstestingutils.ProviderAppIniter, icstestingutils.ConsumerAppIniter, []string{}) | ||
s.SetT(t) | ||
s.SetupTest() | ||
|
||
providerKeeper := s.providerApp.GetProviderKeeper() | ||
s.SetupCCVChannel(s.path) | ||
|
||
// set validator powers | ||
vals, err := providerKeeper.GetLastBondedValidators(s.providerChain.GetContext()) | ||
s.Require().NoError(err) | ||
|
||
delegatorAccount := s.providerChain.SenderAccounts[0] | ||
|
||
for i, val := range vals { | ||
power := tc.stakedTokens[i] | ||
valAddr, err := providerKeeper.ValidatorAddressCodec().StringToBytes(val.GetOperator()) | ||
s.Require().NoError(err) | ||
undelegate(s, delegatorAccount.SenderAccount.GetAddress(), valAddr, math.LegacyOneDec()) | ||
|
||
// set validator power | ||
delegateByIdx(s, delegatorAccount.SenderAccount.GetAddress(), math.NewInt(power), i) | ||
} | ||
|
||
// end the epoch to apply the updates | ||
s.nextEpoch() | ||
|
||
// Relay 1 VSC packet from provider to consumer | ||
relayAllCommittedPackets(s, s.providerChain, s.path, ccv.ProviderPortID, s.path.EndpointB.ChannelID, 1) | ||
|
||
// end the block on the consumer to apply the updates | ||
s.consumerChain.NextBlock() | ||
|
||
// get the last bonded validators | ||
lastVals, err := providerKeeper.GetLastBondedValidators(s.providerChain.GetContext()) | ||
s.Require().NoError(err) | ||
|
||
for i, val := range lastVals { | ||
// check that the intiial state was set correctly | ||
require.Equal(s.T(), math.NewInt(tc.stakedTokens[i]), val.Tokens) | ||
} | ||
|
||
// check the validator set on the consumer chain is the original one | ||
consuValSet := s.consumerChain.LastHeader.ValidatorSet | ||
s.Require().Equal(len(consuValSet.Validators), 4) | ||
|
||
// get just the powers of the consu val set | ||
consuValPowers := make([]int64, len(consuValSet.Validators)) | ||
for i, consuVal := range consuValSet.Validators { | ||
// voting power corresponds to staked tokens at a 1:stake_multiplier ratio | ||
consuValPowers[i] = consuVal.VotingPower * stake_multiplier | ||
} | ||
|
||
s.Require().ElementsMatch(consuValPowers, tc.stakedTokens) | ||
|
||
// adjust parameters | ||
|
||
// set the maxRank and minStake according to the test case | ||
providerKeeper.SetMaxValidatorRank(s.providerChain.GetContext(), s.consumerChain.ChainID, tc.maxRank) | ||
providerKeeper.SetMinStake(s.providerChain.GetContext(), s.consumerChain.ChainID, tc.minStake) | ||
|
||
// undelegate and delegate to trigger a vscupdate | ||
delegateAndUndelegate(s, delegatorAccount.SenderAccount.GetAddress(), math.NewInt(1*stake_multiplier), 1) | ||
|
||
// end the epoch to apply the updates | ||
s.nextEpoch() | ||
|
||
// Relay 1 VSC packet from provider to consumer | ||
relayAllCommittedPackets(s, s.providerChain, s.path, ccv.ProviderPortID, s.path.EndpointB.ChannelID, 1) | ||
|
||
// end the block on the consumer to apply the updates | ||
s.consumerChain.NextBlock() | ||
|
||
// construct the new val powers | ||
newConsuValSet := s.consumerChain.LastHeader.ValidatorSet | ||
newConsuValPowers := make([]int64, len(newConsuValSet.Validators)) | ||
for i, consuVal := range newConsuValSet.Validators { | ||
// voting power corresponds to staked tokens at a 1:stake_multiplier ratio | ||
newConsuValPowers[i] = consuVal.VotingPower * stake_multiplier | ||
} | ||
|
||
// check that the new validator set is as expected | ||
s.Require().ElementsMatch(newConsuValPowers, tc.expectedConsuValSet) | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.