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!: compute partial sets #1702

Merged
merged 15 commits into from
Mar 25, 2024
13 changes: 0 additions & 13 deletions proto/interchain_security/ccv/provider/v1/provider.proto
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
syntax = "proto3";

Check failure on line 1 in proto/interchain_security/ccv/provider/v1/provider.proto

View workflow job for this annotation

GitHub Actions / break-check

Previously present message "OptedInValidator" was deleted from file.

package interchain_security.ccv.provider.v1;

Expand Down Expand Up @@ -326,16 +326,3 @@
(gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins"
];
}

// OptedInValidator is used to store a opted-in validator
// to a consumer chain with the following mapping: (chainID, providerAddr) -> optedInValidator
message OptedInValidator {
// validator address
bytes provider_addr = 1;
// block height at which the validator opted-in
int64 block_height = 2;
// validator voting power at the block it opted-in
int64 power = 3;
// public key used by the validator on the consumer
bytes public_key = 4;
}
3 changes: 2 additions & 1 deletion tests/mbt/driver/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -373,7 +373,8 @@ func (s *Driver) ConfigureNewPath(consumerChain, providerChain *ibctesting.TestC
stakingValidators = append(stakingValidators, v)
}

nextValidators := s.providerKeeper().ComputeNextEpochConsumerValSet(s.providerCtx(), string(consumerChainId), stakingValidators)
considerAll := func(validator stakingtypes.Validator) bool { return true }
nextValidators := s.providerKeeper().ComputeNextEpochConsumerValSet(s.providerCtx(), string(consumerChainId), stakingValidators, considerAll)
s.providerKeeper().SetConsumerValSet(s.providerCtx(), string(consumerChainId), nextValidators)

err = s.providerKeeper().SetConsumerGenesis(
Expand Down
11 changes: 6 additions & 5 deletions x/ccv/provider/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,12 +225,13 @@ func (h Hooks) AfterProposalVote(ctx sdk.Context, proposalID uint64, voterAddr s
return
}

// in the validator is already to-be-opted in, the `SetToBeOptedIn` is a no-op
h.k.SetToBeOptedIn(ctx, chainID, providertypes.NewProviderConsAddress(consAddr))
// If the validator is already opted in, the `SetOptedIn` is a no-op
h.k.SetOptedIn(ctx, chainID, providertypes.NewProviderConsAddress(consAddr))
} else {
// if vote is not a YES vote with 100% weight, we delete the validator from to-be-opted in
// if the validator is not to-be-opted in, the `DeleteToBeOptedIn` is a no-op
h.k.DeleteToBeOptedIn(ctx, chainID, providertypes.NewProviderConsAddress(consAddr))
// If vote is not a YES vote with 100% weight, we opt out the validator.
// Note that a validator still gets opted out even if before it manually opted in with a `MsgOptIn` message.
// This is because if a validator wants to opt in, there's no reason to not vote YES with 100% weight.
h.k.DeleteOptedIn(ctx, chainID, providertypes.NewProviderConsAddress(consAddr))
}
}

Expand Down
10 changes: 5 additions & 5 deletions x/ccv/provider/keeper/hooks_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,9 +249,9 @@ func TestAfterProposalVoteWithYesVote(t *testing.T) {
),
)

require.False(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr))
require.False(t, k.IsOptedIn(ctx, "chainID", providerAddr))
k.Hooks().AfterProposalVote(ctx, 1, sdk.AccAddress{})
require.True(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr))
require.True(t, k.IsOptedIn(ctx, "chainID", providerAddr))
}

func TestAfterProposalVoteWithNoVote(t *testing.T) {
Expand Down Expand Up @@ -306,10 +306,10 @@ func TestAfterProposalVoteWithNoVote(t *testing.T) {
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.SetOptedIn(ctx, "chainID", providerAddr)
require.True(t, k.IsOptedIn(ctx, "chainID", providerAddr))
k.Hooks().AfterProposalVote(ctx, 1, sdk.AccAddress{})
require.False(t, k.IsToBeOptedIn(ctx, "chainID", providerAddr))
require.False(t, k.IsOptedIn(ctx, "chainID", providerAddr))
})
}
}
121 changes: 10 additions & 111 deletions x/ccv/provider/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -1174,13 +1174,13 @@ func (k Keeper) GetTopN(
return binary.BigEndian.Uint32(buf), true
}

// IsTopN returns true if chain with `chainID` is a Top N chain (i.e., enforces at least one validator to validate chain `chainID`)
// IsTopN returns true if chain with `chainID` is a Top-N chain (i.e., enforces at least one validator to validate chain `chainID`)
func (k Keeper) IsTopN(ctx sdk.Context, chainID string) bool {
topN, found := k.GetTopN(ctx, chainID)
return found && topN > 0
}

// IsOptIn returns true if chain with `chainID` is an Opt In chain (i.e., no validator is forced to validate chain `chainID`)
// IsOptIn returns true if chain with `chainID` is an Opt-In chain (i.e., no validator is forced to validate chain `chainID`)
func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool {
topN, found := k.GetTopN(ctx, chainID)
return !found || topN == 0
Expand All @@ -1189,15 +1189,10 @@ func (k Keeper) IsOptIn(ctx sdk.Context, chainID string) bool {
func (k Keeper) SetOptedIn(
ctx sdk.Context,
chainID string,
validator types.OptedInValidator,
providerConsAddress types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
bz, err := validator.Marshal()
if err != nil {
panic(fmt.Errorf("failed to marshal OptedInValidator: %w", err))
}

store.Set(types.OptedInKey(chainID, validator.ProviderAddr), bz)
store.Set(types.OptedInKey(chainID, providerConsAddress), []byte{})
}

func (k Keeper) DeleteOptedIn(
Expand All @@ -1206,7 +1201,7 @@ func (k Keeper) DeleteOptedIn(
providerAddr types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.OptedInKey(chainID, providerAddr.ToSdkConsAddr()))
store.Delete(types.OptedInKey(chainID, providerAddr))
}

func (k Keeper) IsOptedIn(
Expand All @@ -1215,38 +1210,23 @@ func (k Keeper) IsOptedIn(
providerAddr types.ProviderConsAddress,
) bool {
store := ctx.KVStore(k.storeKey)
return store.Get(types.OptedInKey(chainID, providerAddr.ToSdkConsAddr())) != nil
return store.Get(types.OptedInKey(chainID, providerAddr)) != nil
}

// GetAllOptedIn returns all the opted-in validators on chain `chainID`
func (k Keeper) GetAllOptedIn(
ctx sdk.Context,
chainID string,
) (optedInValidators []types.OptedInValidator) {
chainID string) (providerConsAddresses []types.ProviderConsAddress) {
store := ctx.KVStore(k.storeKey)
key := types.ChainIdWithLenKey(types.OptedInBytePrefix, chainID)
iterator := sdk.KVStorePrefixIterator(store, key)
defer iterator.Close()

for ; iterator.Valid(); iterator.Next() {
iterator.Value()
var optedInValidator types.OptedInValidator
if err := optedInValidator.Unmarshal(iterator.Value()); err != nil {
panic(fmt.Errorf("failed to unmarshal OptedInValidator: %w", err))
}
optedInValidators = append(optedInValidators, optedInValidator)
providerConsAddresses = append(providerConsAddresses, types.NewProviderConsAddress(iterator.Key()[len(key):]))
}

return optedInValidators
}

func (k Keeper) SetToBeOptedIn(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
store.Set(types.ToBeOptedInKey(chainID, providerAddr), []byte{})
return providerConsAddresses
}

// SetConsumerCommissionRate sets a per-consumer chain commission rate
Expand Down Expand Up @@ -1316,85 +1296,4 @@ func (k Keeper) DeleteConsumerCommissionRate(
) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.ConsumerCommissionRateKey(chainID, providerAddr))
}

func (k Keeper) DeleteToBeOptedIn(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.ToBeOptedInKey(chainID, providerAddr))
}

func (k Keeper) IsToBeOptedIn(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) bool {
store := ctx.KVStore(k.storeKey)
return store.Get(types.ToBeOptedInKey(chainID, providerAddr)) != nil
}

// GetAllToBeOptedIn returns all the to-be-opted-in validators on chain `chainID`
func (k Keeper) GetAllToBeOptedIn(
ctx sdk.Context,
chainID string,
) (addresses []types.ProviderConsAddress) {
store := ctx.KVStore(k.storeKey)
key := types.ChainIdWithLenKey(types.ToBeOptedInBytePrefix, chainID)
iterator := sdk.KVStorePrefixIterator(store, key)
defer iterator.Close()

for ; iterator.Valid(); iterator.Next() {
providerAddr := types.NewProviderConsAddress(iterator.Key()[len(key):])
addresses = append(addresses, providerAddr)
}

return addresses
}

func (k Keeper) SetToBeOptedOut(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
store.Set(types.ToBeOptedOutKey(chainID, providerAddr), []byte{})
}

func (k Keeper) DeleteToBeOptedOut(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.ToBeOptedOutKey(chainID, providerAddr))
}

func (k Keeper) IsToBeOptedOut(
ctx sdk.Context,
chainID string,
providerAddr types.ProviderConsAddress,
) bool {
store := ctx.KVStore(k.storeKey)
return store.Get(types.ToBeOptedOutKey(chainID, providerAddr)) != nil
}

// GetAllToBeOptedOut returns all the to-be-opted-out validators on chain `chainID`
func (k Keeper) GetAllToBeOptedOut(
ctx sdk.Context,
chainID string,
) (addresses []types.ProviderConsAddress) {
store := ctx.KVStore(k.storeKey)
key := types.ChainIdWithLenKey(types.ToBeOptedOutBytePrefix, chainID)
iterator := sdk.KVStorePrefixIterator(store, key)
defer iterator.Close()

for ; iterator.Valid(); iterator.Next() {
providerAddr := types.NewProviderConsAddress(iterator.Key()[len(key):])
addresses = append(addresses, providerAddr)
}

return addresses
}
}
Loading
Loading