-
Notifications
You must be signed in to change notification settings - Fork 136
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!: automatically opt in validators that vote Yes on consumer addition proposals #1629
Changes from all commits
bef8202
3402f75
07e5d4f
2c2849e
d6df534
9ae1c74
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,10 @@ | ||
package keeper_test | ||
|
||
import ( | ||
codectypes "github.com/cosmos/cosmos-sdk/codec/types" | ||
"github.com/cosmos/cosmos-sdk/crypto/keys/ed25519" | ||
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" | ||
"github.com/cosmos/interchain-security/v4/x/ccv/provider/types" | ||
"testing" | ||
"time" | ||
|
||
|
@@ -123,11 +127,13 @@ func TestAfterPropSubmissionAndVotingPeriodEnded(t *testing.T) { | |
|
||
k.Hooks().AfterProposalSubmission(ctx, prop.Id) | ||
// verify that the proposal ID is created | ||
require.NotEmpty(t, k.GetProposedConsumerChain(ctx, prop.Id)) | ||
_, found := k.GetProposedConsumerChain(ctx, prop.Id) | ||
require.True(t, found) | ||
|
||
k.Hooks().AfterProposalVotingPeriodEnded(ctx, prop.Id) | ||
// verify that the proposal ID is deleted | ||
require.Empty(t, k.GetProposedConsumerChain(ctx, prop.Id)) | ||
_, found = k.GetProposedConsumerChain(ctx, prop.Id) | ||
require.False(t, found) | ||
} | ||
|
||
func TestGetConsumerAdditionLegacyPropFromProp(t *testing.T) { | ||
|
@@ -223,3 +229,85 @@ func TestGetConsumerAdditionLegacyPropFromProp(t *testing.T) { | |
}) | ||
} | ||
} | ||
|
||
func TestAfterProposalVoteWithYesVote(t *testing.T) { | ||
k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) | ||
defer ctrl.Finish() | ||
|
||
providerConsPubKey := ed25519.GenPrivKeyFromSecret([]byte{1}).PubKey() | ||
pkAny, _ := codectypes.NewAnyWithValue(providerConsPubKey) | ||
providerAddr := types.NewProviderConsAddress(providerConsPubKey.Address().Bytes()) | ||
|
||
options := []*v1.WeightedVoteOption{{Option: v1.OptionYes, Weight: "1"}} | ||
k.SetProposedConsumerChain(ctx, "chainID", 1) | ||
|
||
gomock.InOrder( | ||
mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return( | ||
stakingtypes.Validator{ConsensusPubkey: pkAny}, true), | ||
mocks.MockGovKeeper.EXPECT().GetVote(ctx, gomock.Any(), gomock.Any()).Return( | ||
v1.Vote{ProposalId: 1, Voter: "voter", Options: options}, true, | ||
), | ||
) | ||
|
||
require.False(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) | ||
k.Hooks().AfterProposalVote(ctx, 1, sdk.AccAddress{}) | ||
require.True(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) | ||
} | ||
|
||
func TestAfterProposalVoteWithNoVote(t *testing.T) { | ||
testCases := []struct { | ||
name string | ||
options []*v1.WeightedVoteOption | ||
setup func(sdk.Context, []*v1.WeightedVoteOption, testkeeper.MockedKeepers, *codectypes.Any) | ||
}{ | ||
{ | ||
"Weighted vote with 100% NO", | ||
[]*v1.WeightedVoteOption{{Option: v1.OptionNo, Weight: "1"}}, | ||
func(ctx sdk.Context, options []*v1.WeightedVoteOption, | ||
mocks testkeeper.MockedKeepers, pubKey *codectypes.Any) { | ||
gomock.InOrder( | ||
mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return( | ||
stakingtypes.Validator{ConsensusPubkey: pubKey}, true), | ||
mocks.MockGovKeeper.EXPECT().GetVote(ctx, gomock.Any(), gomock.Any()).Return( | ||
v1.Vote{ProposalId: 1, Voter: "voter", Options: options}, true, | ||
), | ||
) | ||
}, | ||
}, | ||
{ | ||
"Weighted vote with 99.9% YES and 0.1% NO", | ||
[]*v1.WeightedVoteOption{{Option: v1.OptionYes, Weight: "0.999"}, {Option: v1.OptionNo, Weight: "0.001"}}, | ||
func(ctx sdk.Context, options []*v1.WeightedVoteOption, | ||
mocks testkeeper.MockedKeepers, pubKey *codectypes.Any) { | ||
gomock.InOrder( | ||
mocks.MockStakingKeeper.EXPECT().GetValidator(ctx, gomock.Any()).Return( | ||
stakingtypes.Validator{ConsensusPubkey: pubKey}, true), | ||
mocks.MockGovKeeper.EXPECT().GetVote(ctx, gomock.Any(), gomock.Any()).Return( | ||
v1.Vote{ProposalId: 1, Voter: "voter", Options: options}, true, | ||
), | ||
) | ||
}, | ||
}, | ||
} | ||
|
||
for _, tc := range testCases { | ||
t.Run(tc.name, func(t *testing.T) { | ||
k, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) | ||
defer ctrl.Finish() | ||
|
||
providerConsPubKey := ed25519.GenPrivKeyFromSecret([]byte{1}).PubKey() | ||
pkAny, _ := codectypes.NewAnyWithValue(providerConsPubKey) | ||
providerAddr := types.NewProviderConsAddress(providerConsPubKey.Address().Bytes()) | ||
|
||
k.SetProposedConsumerChain(ctx, "chainID", 1) | ||
|
||
tc.setup(ctx, tc.options, mocks, pkAny) | ||
|
||
// set the validator to-be-opted in first to assert that a NO vote removes the validator from to-be-opted in | ||
k.SetToBeOptedIn(ctx, "chainID", providerAddr) | ||
require.True(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) | ||
k.Hooks().AfterProposalVote(ctx, 1, sdk.AccAddress{}) | ||
require.False(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr)) | ||
}) | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could we add a test with a weighted vote, just to safeguard against potential future regressions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also, in case you think https://github.com/cosmos/interchain-security/pull/1629/files#r1482790758 should be taken into account, we also should add test cases for it There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added one more test case and made the "No" vote test tabular. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note: These are cases where we could also
panic
instead of simplyreturn
ing. We couldpanic
because those are exceptional cases that should never trigger (e.g., a validator with no consensus address). However, I choose to simplyreturn
because a potential buggypanic
call could potentially lead so that no one is able toMsgVote
on such a proposal.For this, we only log such error cases.