From 5937a150a8285bae858c1c485ad3bb527317c092 Mon Sep 17 00:00:00 2001
From: insumity <karolos@informal.systems>
Date: Fri, 17 May 2024 10:47:08 +0200
Subject: [PATCH] feat: add a query to retrieve validator set that was last
 sent to the consumer chain (#1867)

* init commit

* took into account comments

* add docs

* Update docs/docs/validators/partial-set-security-for-validators.md

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
(cherry picked from commit e1b191a893ca1a5c43d35a5eee26188efabd510f)
---
 ...query-for-latest-consumer-validator-set.md |   2 +
 .../partial-set-security-for-validators.md    |  19 +-
 .../ccv/provider/v1/query.proto               |  26 +-
 x/ccv/provider/client/cli/query.go            |  36 +
 x/ccv/provider/keeper/grpc_query.go           |  32 +
 x/ccv/provider/keeper/grpc_query_test.go      | 146 +++
 x/ccv/provider/types/query.pb.go              | 940 +++++++++++++++---
 x/ccv/provider/types/query.pb.gw.go           | 101 ++
 8 files changed, 1163 insertions(+), 139 deletions(-)
 create mode 100644 .changelog/unreleased/features/provider/1867-add-query-for-latest-consumer-validator-set.md

diff --git a/.changelog/unreleased/features/provider/1867-add-query-for-latest-consumer-validator-set.md b/.changelog/unreleased/features/provider/1867-add-query-for-latest-consumer-validator-set.md
new file mode 100644
index 0000000000..dc33ef69d0
--- /dev/null
+++ b/.changelog/unreleased/features/provider/1867-add-query-for-latest-consumer-validator-set.md
@@ -0,0 +1,2 @@
+- Introduces the `consumer-validators` query to retrieve the latest set consumer-validator set for a consumer chain.
+  ([\#1863](https://github.com/cosmos/interchain-security/pull/1867))
diff --git a/docs/docs/validators/partial-set-security-for-validators.md b/docs/docs/validators/partial-set-security-for-validators.md
index 770f423a01..2d6b2dd4a2 100644
--- a/docs/docs/validators/partial-set-security-for-validators.md
+++ b/docs/docs/validators/partial-set-security-for-validators.md
@@ -143,13 +143,30 @@ they will not be opted in automatically.
 :::
 
 
-### How to get all the opted-in validators on a consumer chain?
+### How to retrieve all the opted-in validators on a consumer chain?
 With the following query:
 ```bash
 interchain-security-pd query provider consumer-opted-in-validators <consumer-chain-id>
 ```
 we can see all the opted-in validators on `consumer-chain-id` that were manually or automatically opted in.
 
+### How to retrieve all the consumer validators on a consumer chain?
+With the following query:
+```bash
+interchain-security-pd query provider consumer-validators <consumer-chain-id>
+```
+we can see all the _consumer validators_ (i.e., validator set) of `consumer-chain-id`. The consumer validators are the 
+ones that are currently (or in the future, see warning) validating the consumer chain. A _consumer validator_ is an opted-in
+validator but not vice versa. For example, an opted-in validator `V` might not be a consumer validator because `V` is
+denylisted or because `V` is removed due to a validator-set cap. 
+
+:::warning
+The returned consumer validators from this query do not necessarily correspond to the validator set that is 
+validating the consumer chain at this exact moment. This is because the `VSCPacket` sent to a consumer chain might be
+delayed and hence this query might return the validator set that the consumer chain would have at some future
+point in time.
+:::
+
 ### How can we see the commission rate a validator has set on a consumer chain?
 Using the following query:
 ```bash
diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto
index d34bfd3e4c..b982cea667 100644
--- a/proto/interchain_security/ccv/provider/v1/query.proto
+++ b/proto/interchain_security/ccv/provider/v1/query.proto
@@ -134,6 +134,15 @@ service Query {
       option (google.api.http).get =
       "/interchain_security/ccv/provider/oldest_unconfirmed_vsc/{chain_id}";
     }
+
+  // QueryConsumerValidators returns the latest set consumer-validator set for a given chainID
+  // Note that this does not necessarily mean that the consumer chain is using this validator set at this exact moment
+  // because a VSCPacket could be delayed to be delivered on the consumer chain.
+  rpc QueryConsumerValidators(QueryConsumerValidatorsRequest)
+      returns (QueryConsumerValidatorsResponse) {
+        option (google.api.http).get =
+            "/interchain_security/ccv/provider/consumer_validators/{chain_id}";
+  }
 }
 
 message QueryConsumerGenesisRequest { string chain_id = 1; }
@@ -262,7 +271,6 @@ message QueryParamsResponse {
   Params params = 1 [(gogoproto.nullable) = false];
 }
 
-
 message QueryConsumerChainOptedInValidatorsRequest {
   string chain_id = 1;
 }
@@ -272,6 +280,22 @@ message QueryConsumerChainOptedInValidatorsResponse {
   repeated string validators_provider_addresses = 1;
 }
 
+message QueryConsumerValidatorsRequest {
+  string chain_id = 1;
+}
+
+message QueryConsumerValidatorsValidator {
+  // The consensus address of the validator on the provider chain
+  string provider_address = 1 [ (gogoproto.moretags) = "yaml:\"address\"" ];
+  // The consumer public key of the validator used on the consumer chain
+  tendermint.crypto.PublicKey consumer_key = 2;
+  // The power of the validator used on the consumer chain
+  int64 power = 3;
+}
+
+message QueryConsumerValidatorsResponse {
+  repeated QueryConsumerValidatorsValidator validators = 1;
+}
 
 message QueryConsumerChainsValidatorHasToValidateRequest {
   // The consensus address of the validator on the provider chain
diff --git a/x/ccv/provider/client/cli/query.go b/x/ccv/provider/client/cli/query.go
index cf68d24681..22f82419b2 100644
--- a/x/ccv/provider/client/cli/query.go
+++ b/x/ccv/provider/client/cli/query.go
@@ -36,6 +36,7 @@ func NewQueryCmd() *cobra.Command {
 	cmd.AddCommand(CmdAllPairsValConAddrByConsumerChainID())
 	cmd.AddCommand(CmdProviderParameters())
 	cmd.AddCommand(CmdConsumerChainOptedInValidators())
+	cmd.AddCommand(CmdConsumerValidators())
 	cmd.AddCommand(CmdConsumerChainsValidatorHasToValidate())
 	cmd.AddCommand(CmdValidatorConsumerCommissionRate())
 	cmd.AddCommand(CmdOldestUnconfirmedVsc())
@@ -448,6 +449,41 @@ $ %s consumer-opted-in-validators foochain
 	return cmd
 }
 
+// Command to query the consumer validators by consumer chain ID
+func CmdConsumerValidators() *cobra.Command {
+	cmd := &cobra.Command{
+		Use:   "consumer-validators [chainid]",
+		Short: "Query the last set consumer-validator set for a given consumer chain",
+		Long: strings.TrimSpace(
+			fmt.Sprintf(`Query the last set consumer-validator set for a given consumer chain.
+Note that this does not necessarily mean that the consumer chain is currently using this validator set because a VSCPacket could be delayed, etc.
+Example:
+$ %s consumer-validators foochain
+		`, version.AppName),
+		),
+		Args: cobra.ExactArgs(1),
+		RunE: func(cmd *cobra.Command, args []string) error {
+			clientCtx, err := client.GetClientQueryContext(cmd)
+			if err != nil {
+				return err
+			}
+			queryClient := types.NewQueryClient(clientCtx)
+
+			res, err := queryClient.QueryConsumerValidators(cmd.Context(),
+				&types.QueryConsumerValidatorsRequest{ChainId: args[0]})
+			if err != nil {
+				return err
+			}
+
+			return clientCtx.PrintProto(res)
+		},
+	}
+
+	flags.AddQueryFlagsToCmd(cmd)
+
+	return cmd
+}
+
 // Command to query the consumer chains list a given validator has to validate
 func CmdConsumerChainsValidatorHasToValidate() *cobra.Command {
 	bech32PrefixConsAddr := sdk.GetConfig().GetBech32ConsensusAddrPrefix()
diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go
index 84c5928fea..019c1dc957 100644
--- a/x/ccv/provider/keeper/grpc_query.go
+++ b/x/ccv/provider/keeper/grpc_query.go
@@ -252,6 +252,38 @@ func (k Keeper) QueryConsumerChainOptedInValidators(goCtx context.Context, req *
 	}, nil
 }
 
+// QueryConsumerValidators returns all validators that are consumer validators in a given consumer chain
+func (k Keeper) QueryConsumerValidators(goCtx context.Context, req *types.QueryConsumerValidatorsRequest) (*types.QueryConsumerValidatorsResponse, error) {
+	if req == nil {
+		return nil, status.Error(codes.InvalidArgument, "empty request")
+	}
+
+	consumerChainID := req.ChainId
+	if consumerChainID == "" {
+		return nil, status.Error(codes.InvalidArgument, "empty chainId")
+	}
+
+	ctx := sdk.UnwrapSDKContext(goCtx)
+
+	if _, found := k.GetConsumerClientId(ctx, consumerChainID); !found {
+		// chain has to have started; consumer client id is set for a chain during the chain's spawn time
+		return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("no started consumer chain: %s", consumerChainID))
+	}
+
+	var validators []*types.QueryConsumerValidatorsValidator
+	for _, v := range k.GetConsumerValSet(ctx, consumerChainID) {
+		validators = append(validators, &types.QueryConsumerValidatorsValidator{
+			ProviderAddress: sdk.ConsAddress(v.ProviderConsAddr).String(),
+			ConsumerKey:     v.ConsumerPublicKey,
+			Power:           v.Power,
+		})
+	}
+
+	return &types.QueryConsumerValidatorsResponse{
+		Validators: validators,
+	}, nil
+}
+
 // QueryConsumerChainsValidatorHasToValidate returns all consumer chains that the given validator has to validate now
 // or in the next epoch if nothing changes.
 func (k Keeper) QueryConsumerChainsValidatorHasToValidate(goCtx context.Context, req *types.QueryConsumerChainsValidatorHasToValidateRequest) (*types.QueryConsumerChainsValidatorHasToValidateResponse, error) {
diff --git a/x/ccv/provider/keeper/grpc_query_test.go b/x/ccv/provider/keeper/grpc_query_test.go
index 14e6e675e1..71a9b82b7e 100644
--- a/x/ccv/provider/keeper/grpc_query_test.go
+++ b/x/ccv/provider/keeper/grpc_query_test.go
@@ -1,6 +1,8 @@
 package keeper_test
 
 import (
+	"github.com/cometbft/cometbft/proto/tendermint/crypto"
+	stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
 	"testing"
 	"time"
 
@@ -103,3 +105,147 @@ func TestQueryOldestUnconfirmedVsc(t *testing.T) {
 	}
 	require.Equal(t, expectedResult, response.VscSendTimestamp)
 }
+
+func TestQueryConsumerChainOptedInValidators(t *testing.T) {
+	chainID := "chainID"
+
+	pk, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
+	defer ctrl.Finish()
+
+	req := types.QueryConsumerChainOptedInValidatorsRequest{
+		ChainId: chainID,
+	}
+
+	// error returned from not yet proposed or not yet registered chain
+	_, err := pk.QueryConsumerChainOptedInValidators(ctx, &req)
+	require.Error(t, err)
+
+	pk.SetProposedConsumerChain(ctx, chainID, 1)
+
+	providerAddr1 := types.NewProviderConsAddress([]byte("providerAddr1"))
+	providerAddr2 := types.NewProviderConsAddress([]byte("providerAddr2"))
+	expectedResponse := types.QueryConsumerChainOptedInValidatorsResponse{
+		ValidatorsProviderAddresses: []string{providerAddr1.String(), providerAddr2.String()},
+	}
+
+	pk.SetOptedIn(ctx, chainID, providerAddr1)
+	pk.SetOptedIn(ctx, chainID, providerAddr2)
+	res, err := pk.QueryConsumerChainOptedInValidators(ctx, &req)
+	require.NoError(t, err)
+	require.Equal(t, &expectedResponse, res)
+}
+
+func TestQueryConsumerValidators(t *testing.T) {
+	chainID := "chainID"
+
+	pk, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
+	defer ctrl.Finish()
+
+	req := types.QueryConsumerValidatorsRequest{
+		ChainId: chainID,
+	}
+
+	// error returned from not-started chain
+	_, err := pk.QueryConsumerValidators(ctx, &req)
+	require.Error(t, err)
+
+	providerAddr1 := types.NewProviderConsAddress([]byte("providerAddr1"))
+	consumerKey1 := cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey()
+	consumerValidator1 := types.ConsumerValidator{ProviderConsAddr: providerAddr1.ToSdkConsAddr(), Power: 1, ConsumerPublicKey: &consumerKey1}
+
+	providerAddr2 := types.NewProviderConsAddress([]byte("providerAddr2"))
+	consumerKey2 := cryptotestutil.NewCryptoIdentityFromIntSeed(2).TMProtoCryptoPublicKey()
+	consumerValidator2 := types.ConsumerValidator{ProviderConsAddr: providerAddr2.ToSdkConsAddr(), Power: 2, ConsumerPublicKey: &consumerKey2}
+
+	expectedResponse := types.QueryConsumerValidatorsResponse{
+		Validators: []*types.QueryConsumerValidatorsValidator{
+			{providerAddr1.String(), &consumerKey1, 1},
+			{providerAddr2.String(), &consumerKey2, 2},
+		},
+	}
+
+	// set up the client id so the chain looks like it "started"
+	pk.SetConsumerClientId(ctx, chainID, "clientID")
+	pk.SetConsumerValSet(ctx, chainID, []types.ConsumerValidator{consumerValidator1, consumerValidator2})
+
+	res, err := pk.QueryConsumerValidators(ctx, &req)
+	require.NoError(t, err)
+	require.Equal(t, &expectedResponse, res)
+}
+
+func TestQueryConsumerChainsValidatorHasToValidate(t *testing.T) {
+	pk, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
+	defer ctrl.Finish()
+
+	val := createStakingValidator(ctx, mocks, 1, 1)
+	valConsAddr, _ := val.GetConsAddr()
+	providerAddr := types.NewProviderConsAddress(valConsAddr)
+	mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valConsAddr).Return(val, true).AnyTimes()
+	mocks.MockStakingKeeper.EXPECT().GetLastValidators(ctx).Return([]stakingtypes.Validator{val}).AnyTimes()
+
+	req := types.QueryConsumerChainsValidatorHasToValidateRequest{
+		ProviderAddress: providerAddr.String(),
+	}
+
+	// set up some consumer chains
+	consumerChains := []string{"chain1", "chain2", "chain3", "chain4"}
+	for _, cc := range consumerChains {
+		pk.SetConsumerClientId(ctx, cc, "clientID")
+	}
+
+	// set `providerAddr` as a consumer validator on "chain1"
+	pk.SetConsumerValidator(ctx, "chain1", types.ConsumerValidator{
+		ProviderConsAddr: providerAddr.ToSdkConsAddr(),
+		Power:            1,
+		ConsumerPublicKey: &crypto.PublicKey{
+			Sum: &crypto.PublicKey_Ed25519{
+				Ed25519: []byte{1},
+			}}})
+
+	// set `providerAddr` as an opted-in validator on "chain3"
+	pk.SetOptedIn(ctx, "chain3", providerAddr)
+
+	// `providerAddr` has to validate "chain1" because it is a consumer validator in this chain, as well as "chain3"
+	// because it opted in, in "chain3" and `providerAddr` belongs to the bonded validators (see the mocking of `GetLastValidators`
+	// above)
+	expectedChains := []string{"chain1", "chain3"}
+
+	res, err := pk.QueryConsumerChainsValidatorHasToValidate(ctx, &req)
+	require.NoError(t, err)
+	require.Equal(t, expectedChains, res.ConsumerChainIds)
+}
+
+func TestQueryValidatorConsumerCommissionRate(t *testing.T) {
+	chainID := "chainID"
+
+	pk, ctx, ctrl, mocks := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
+	defer ctrl.Finish()
+
+	providerAddr := types.NewProviderConsAddress([]byte("providerAddr"))
+	req := types.QueryValidatorConsumerCommissionRateRequest{
+		ChainId:         chainID,
+		ProviderAddress: providerAddr.String(),
+	}
+
+	// error returned from not yet proposed or not yet registered chain
+	_, err := pk.QueryValidatorConsumerCommissionRate(ctx, &req)
+	require.Error(t, err)
+
+	pk.SetProposedConsumerChain(ctx, chainID, 1)
+	// validator with set consumer commission rate
+	expectedCommissionRate, _ := sdktypes.NewDecFromStr("0.123")
+	pk.SetConsumerCommissionRate(ctx, chainID, providerAddr, expectedCommissionRate)
+	res, _ := pk.QueryValidatorConsumerCommissionRate(ctx, &req)
+	require.Equal(t, expectedCommissionRate, res.Rate)
+
+	// validator with no set consumer commission rate
+	pk.DeleteConsumerCommissionRate(ctx, chainID, providerAddr)
+	expectedCommissionRate, _ = sdktypes.NewDecFromStr("0.456")
+
+	// because no consumer commission rate is set, the validator's set commission rate on the provider is used
+	val := stakingtypes.Validator{Commission: stakingtypes.Commission{CommissionRates: stakingtypes.CommissionRates{Rate: expectedCommissionRate}}}
+	mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(
+		ctx, providerAddr.ToSdkConsAddr()).Return(val, true).Times(1)
+	res, _ = pk.QueryValidatorConsumerCommissionRate(ctx, &req)
+	require.Equal(t, expectedCommissionRate, res.Rate)
+}
diff --git a/x/ccv/provider/types/query.pb.go b/x/ccv/provider/types/query.pb.go
index b2a57c1c2f..4d42311fda 100644
--- a/x/ccv/provider/types/query.pb.go
+++ b/x/ccv/provider/types/query.pb.go
@@ -1309,6 +1309,157 @@ func (m *QueryConsumerChainOptedInValidatorsResponse) GetValidatorsProviderAddre
 	return nil
 }
 
+type QueryConsumerValidatorsRequest struct {
+	ChainId string `protobuf:"bytes,1,opt,name=chain_id,json=chainId,proto3" json:"chain_id,omitempty"`
+}
+
+func (m *QueryConsumerValidatorsRequest) Reset()         { *m = QueryConsumerValidatorsRequest{} }
+func (m *QueryConsumerValidatorsRequest) String() string { return proto.CompactTextString(m) }
+func (*QueryConsumerValidatorsRequest) ProtoMessage()    {}
+func (*QueryConsumerValidatorsRequest) Descriptor() ([]byte, []int) {
+	return fileDescriptor_422512d7b7586cd7, []int{27}
+}
+func (m *QueryConsumerValidatorsRequest) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *QueryConsumerValidatorsRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_QueryConsumerValidatorsRequest.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *QueryConsumerValidatorsRequest) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_QueryConsumerValidatorsRequest.Merge(m, src)
+}
+func (m *QueryConsumerValidatorsRequest) XXX_Size() int {
+	return m.Size()
+}
+func (m *QueryConsumerValidatorsRequest) XXX_DiscardUnknown() {
+	xxx_messageInfo_QueryConsumerValidatorsRequest.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_QueryConsumerValidatorsRequest proto.InternalMessageInfo
+
+func (m *QueryConsumerValidatorsRequest) GetChainId() string {
+	if m != nil {
+		return m.ChainId
+	}
+	return ""
+}
+
+type QueryConsumerValidatorsValidator struct {
+	// The consensus address of the validator on the provider chain
+	ProviderAddress string `protobuf:"bytes,1,opt,name=provider_address,json=providerAddress,proto3" json:"provider_address,omitempty" yaml:"address"`
+	// The consumer public key of the validator used on the consumer chain
+	ConsumerKey *crypto.PublicKey `protobuf:"bytes,2,opt,name=consumer_key,json=consumerKey,proto3" json:"consumer_key,omitempty"`
+	// The power of the validator used on the consumer chain
+	Power int64 `protobuf:"varint,3,opt,name=power,proto3" json:"power,omitempty"`
+}
+
+func (m *QueryConsumerValidatorsValidator) Reset()         { *m = QueryConsumerValidatorsValidator{} }
+func (m *QueryConsumerValidatorsValidator) String() string { return proto.CompactTextString(m) }
+func (*QueryConsumerValidatorsValidator) ProtoMessage()    {}
+func (*QueryConsumerValidatorsValidator) Descriptor() ([]byte, []int) {
+	return fileDescriptor_422512d7b7586cd7, []int{28}
+}
+func (m *QueryConsumerValidatorsValidator) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *QueryConsumerValidatorsValidator) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_QueryConsumerValidatorsValidator.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *QueryConsumerValidatorsValidator) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_QueryConsumerValidatorsValidator.Merge(m, src)
+}
+func (m *QueryConsumerValidatorsValidator) XXX_Size() int {
+	return m.Size()
+}
+func (m *QueryConsumerValidatorsValidator) XXX_DiscardUnknown() {
+	xxx_messageInfo_QueryConsumerValidatorsValidator.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_QueryConsumerValidatorsValidator proto.InternalMessageInfo
+
+func (m *QueryConsumerValidatorsValidator) GetProviderAddress() string {
+	if m != nil {
+		return m.ProviderAddress
+	}
+	return ""
+}
+
+func (m *QueryConsumerValidatorsValidator) GetConsumerKey() *crypto.PublicKey {
+	if m != nil {
+		return m.ConsumerKey
+	}
+	return nil
+}
+
+func (m *QueryConsumerValidatorsValidator) GetPower() int64 {
+	if m != nil {
+		return m.Power
+	}
+	return 0
+}
+
+type QueryConsumerValidatorsResponse struct {
+	Validators []*QueryConsumerValidatorsValidator `protobuf:"bytes,1,rep,name=validators,proto3" json:"validators,omitempty"`
+}
+
+func (m *QueryConsumerValidatorsResponse) Reset()         { *m = QueryConsumerValidatorsResponse{} }
+func (m *QueryConsumerValidatorsResponse) String() string { return proto.CompactTextString(m) }
+func (*QueryConsumerValidatorsResponse) ProtoMessage()    {}
+func (*QueryConsumerValidatorsResponse) Descriptor() ([]byte, []int) {
+	return fileDescriptor_422512d7b7586cd7, []int{29}
+}
+func (m *QueryConsumerValidatorsResponse) XXX_Unmarshal(b []byte) error {
+	return m.Unmarshal(b)
+}
+func (m *QueryConsumerValidatorsResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
+	if deterministic {
+		return xxx_messageInfo_QueryConsumerValidatorsResponse.Marshal(b, m, deterministic)
+	} else {
+		b = b[:cap(b)]
+		n, err := m.MarshalToSizedBuffer(b)
+		if err != nil {
+			return nil, err
+		}
+		return b[:n], nil
+	}
+}
+func (m *QueryConsumerValidatorsResponse) XXX_Merge(src proto.Message) {
+	xxx_messageInfo_QueryConsumerValidatorsResponse.Merge(m, src)
+}
+func (m *QueryConsumerValidatorsResponse) XXX_Size() int {
+	return m.Size()
+}
+func (m *QueryConsumerValidatorsResponse) XXX_DiscardUnknown() {
+	xxx_messageInfo_QueryConsumerValidatorsResponse.DiscardUnknown(m)
+}
+
+var xxx_messageInfo_QueryConsumerValidatorsResponse proto.InternalMessageInfo
+
+func (m *QueryConsumerValidatorsResponse) GetValidators() []*QueryConsumerValidatorsValidator {
+	if m != nil {
+		return m.Validators
+	}
+	return nil
+}
+
 type QueryConsumerChainsValidatorHasToValidateRequest struct {
 	// The consensus address of the validator on the provider chain
 	ProviderAddress string `protobuf:"bytes,1,opt,name=provider_address,json=providerAddress,proto3" json:"provider_address,omitempty" yaml:"address"`
@@ -1322,7 +1473,7 @@ func (m *QueryConsumerChainsValidatorHasToValidateRequest) String() string {
 }
 func (*QueryConsumerChainsValidatorHasToValidateRequest) ProtoMessage() {}
 func (*QueryConsumerChainsValidatorHasToValidateRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_422512d7b7586cd7, []int{27}
+	return fileDescriptor_422512d7b7586cd7, []int{30}
 }
 func (m *QueryConsumerChainsValidatorHasToValidateRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1370,7 +1521,7 @@ func (m *QueryConsumerChainsValidatorHasToValidateResponse) String() string {
 }
 func (*QueryConsumerChainsValidatorHasToValidateResponse) ProtoMessage() {}
 func (*QueryConsumerChainsValidatorHasToValidateResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_422512d7b7586cd7, []int{28}
+	return fileDescriptor_422512d7b7586cd7, []int{31}
 }
 func (m *QueryConsumerChainsValidatorHasToValidateResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1420,7 +1571,7 @@ func (m *QueryValidatorConsumerCommissionRateRequest) String() string {
 }
 func (*QueryValidatorConsumerCommissionRateRequest) ProtoMessage() {}
 func (*QueryValidatorConsumerCommissionRateRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_422512d7b7586cd7, []int{29}
+	return fileDescriptor_422512d7b7586cd7, []int{32}
 }
 func (m *QueryValidatorConsumerCommissionRateRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1476,7 +1627,7 @@ func (m *QueryValidatorConsumerCommissionRateResponse) String() string {
 }
 func (*QueryValidatorConsumerCommissionRateResponse) ProtoMessage() {}
 func (*QueryValidatorConsumerCommissionRateResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_422512d7b7586cd7, []int{30}
+	return fileDescriptor_422512d7b7586cd7, []int{33}
 }
 func (m *QueryValidatorConsumerCommissionRateResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1513,7 +1664,7 @@ func (m *QueryOldestUnconfirmedVscRequest) Reset()         { *m = QueryOldestUnc
 func (m *QueryOldestUnconfirmedVscRequest) String() string { return proto.CompactTextString(m) }
 func (*QueryOldestUnconfirmedVscRequest) ProtoMessage()    {}
 func (*QueryOldestUnconfirmedVscRequest) Descriptor() ([]byte, []int) {
-	return fileDescriptor_422512d7b7586cd7, []int{31}
+	return fileDescriptor_422512d7b7586cd7, []int{34}
 }
 func (m *QueryOldestUnconfirmedVscRequest) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1557,7 +1708,7 @@ func (m *QueryOldestUnconfirmedVscResponse) Reset()         { *m = QueryOldestUn
 func (m *QueryOldestUnconfirmedVscResponse) String() string { return proto.CompactTextString(m) }
 func (*QueryOldestUnconfirmedVscResponse) ProtoMessage()    {}
 func (*QueryOldestUnconfirmedVscResponse) Descriptor() ([]byte, []int) {
-	return fileDescriptor_422512d7b7586cd7, []int{32}
+	return fileDescriptor_422512d7b7586cd7, []int{35}
 }
 func (m *QueryOldestUnconfirmedVscResponse) XXX_Unmarshal(b []byte) error {
 	return m.Unmarshal(b)
@@ -1621,6 +1772,9 @@ func init() {
 	proto.RegisterType((*QueryParamsResponse)(nil), "interchain_security.ccv.provider.v1.QueryParamsResponse")
 	proto.RegisterType((*QueryConsumerChainOptedInValidatorsRequest)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainOptedInValidatorsRequest")
 	proto.RegisterType((*QueryConsumerChainOptedInValidatorsResponse)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainOptedInValidatorsResponse")
+	proto.RegisterType((*QueryConsumerValidatorsRequest)(nil), "interchain_security.ccv.provider.v1.QueryConsumerValidatorsRequest")
+	proto.RegisterType((*QueryConsumerValidatorsValidator)(nil), "interchain_security.ccv.provider.v1.QueryConsumerValidatorsValidator")
+	proto.RegisterType((*QueryConsumerValidatorsResponse)(nil), "interchain_security.ccv.provider.v1.QueryConsumerValidatorsResponse")
 	proto.RegisterType((*QueryConsumerChainsValidatorHasToValidateRequest)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainsValidatorHasToValidateRequest")
 	proto.RegisterType((*QueryConsumerChainsValidatorHasToValidateResponse)(nil), "interchain_security.ccv.provider.v1.QueryConsumerChainsValidatorHasToValidateResponse")
 	proto.RegisterType((*QueryValidatorConsumerCommissionRateRequest)(nil), "interchain_security.ccv.provider.v1.QueryValidatorConsumerCommissionRateRequest")
@@ -1634,129 +1788,134 @@ func init() {
 }
 
 var fileDescriptor_422512d7b7586cd7 = []byte{
-	// 1937 bytes of a gzipped FileDescriptorProto
-	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x58, 0xcb, 0x6f, 0x1b, 0xc7,
-	0x19, 0xd7, 0x52, 0xb2, 0x22, 0x8d, 0xe2, 0x47, 0xc6, 0x6e, 0x42, 0xaf, 0x64, 0x52, 0xd9, 0xb4,
-	0x29, 0x2d, 0xdb, 0xbb, 0x12, 0xdd, 0xa0, 0x8e, 0x13, 0x45, 0x16, 0x45, 0xdb, 0x21, 0xec, 0xc4,
-	0xcc, 0x5a, 0x56, 0x0b, 0xb7, 0xe8, 0x7a, 0xbd, 0x3b, 0xa1, 0x16, 0x5e, 0xee, 0xac, 0x76, 0x86,
-	0x74, 0x08, 0x23, 0x40, 0xd3, 0x43, 0x9b, 0x53, 0x11, 0xf4, 0x01, 0xf4, 0x98, 0x4b, 0x8f, 0xbd,
-	0x14, 0x45, 0xff, 0x85, 0xe6, 0xd6, 0xb4, 0xb9, 0x14, 0x3d, 0xb8, 0x85, 0xdc, 0x43, 0xd1, 0x53,
-	0x11, 0x14, 0xe8, 0xa9, 0x40, 0xb1, 0xb3, 0xb3, 0x2f, 0x72, 0x45, 0x2e, 0x29, 0xe5, 0x24, 0xed,
-	0xcc, 0x37, 0xbf, 0xef, 0x31, 0xdf, 0x63, 0x7e, 0x04, 0x8a, 0xe5, 0x50, 0xe4, 0x19, 0xbb, 0xba,
-	0xe5, 0x68, 0x04, 0x19, 0x1d, 0xcf, 0xa2, 0x3d, 0xc5, 0x30, 0xba, 0x8a, 0xeb, 0xe1, 0xae, 0x65,
-	0x22, 0x4f, 0xe9, 0xae, 0x29, 0x7b, 0x1d, 0xe4, 0xf5, 0x64, 0xd7, 0xc3, 0x14, 0xc3, 0x57, 0x32,
-	0x0e, 0xc8, 0x86, 0xd1, 0x95, 0xc3, 0x03, 0x72, 0x77, 0x4d, 0x5c, 0x6a, 0x61, 0xdc, 0xb2, 0x91,
-	0xa2, 0xbb, 0x96, 0xa2, 0x3b, 0x0e, 0xa6, 0x3a, 0xb5, 0xb0, 0x43, 0x02, 0x08, 0xf1, 0x4c, 0x0b,
-	0xb7, 0x30, 0xfb, 0x57, 0xf1, 0xff, 0xe3, 0xab, 0x65, 0x7e, 0x86, 0x7d, 0x3d, 0xec, 0xbc, 0xaf,
-	0x50, 0xab, 0x8d, 0x08, 0xd5, 0xdb, 0x2e, 0x17, 0xa8, 0xe6, 0x31, 0x35, 0xb2, 0x22, 0x38, 0xb3,
-	0x7a, 0xd0, 0x99, 0xee, 0x9a, 0x42, 0x76, 0x75, 0x0f, 0x99, 0x9a, 0x81, 0x1d, 0xd2, 0x69, 0x47,
-	0x27, 0xbe, 0x31, 0xe4, 0xc4, 0x63, 0xcb, 0x43, 0x5c, 0x6c, 0x89, 0x22, 0xc7, 0x44, 0x5e, 0xdb,
-	0x72, 0xa8, 0x62, 0x78, 0x3d, 0x97, 0x62, 0xe5, 0x11, 0xea, 0x85, 0x1e, 0x9e, 0x35, 0x30, 0x69,
-	0x63, 0xa2, 0x05, 0x4e, 0x06, 0x1f, 0xc1, 0x96, 0x74, 0x05, 0x2c, 0xbe, 0xe7, 0x87, 0x73, 0x8b,
-	0xab, 0xbd, 0x89, 0x1c, 0x44, 0x2c, 0xa2, 0xa2, 0xbd, 0x0e, 0x22, 0x14, 0x9e, 0x05, 0x73, 0x81,
-	0x6e, 0xcb, 0x2c, 0x0a, 0xcb, 0x42, 0x65, 0x5e, 0x7d, 0x8e, 0x7d, 0x37, 0x4c, 0xe9, 0x09, 0x58,
-	0xca, 0x3e, 0x49, 0x5c, 0xec, 0x10, 0x04, 0xbf, 0x07, 0x8e, 0xb7, 0x82, 0x25, 0x8d, 0x50, 0x9d,
-	0x22, 0x76, 0x7e, 0xa1, 0xba, 0x2a, 0x1f, 0x74, 0x63, 0xdd, 0x35, 0xb9, 0x0f, 0xeb, 0xae, 0x7f,
-	0xae, 0x36, 0xf3, 0xd9, 0xd3, 0xf2, 0x94, 0xfa, 0x7c, 0x2b, 0xb1, 0x26, 0x2d, 0x01, 0x31, 0xa5,
-	0x7c, 0xcb, 0x87, 0x0b, 0xad, 0x96, 0xf4, 0x3e, 0xa7, 0xc2, 0x5d, 0x6e, 0x59, 0x0d, 0xcc, 0x32,
-	0xf5, 0xa4, 0x28, 0x2c, 0x4f, 0x57, 0x16, 0xaa, 0x2b, 0x72, 0x8e, 0x24, 0x92, 0x19, 0x88, 0xca,
-	0x4f, 0x4a, 0xe7, 0xc1, 0x37, 0x07, 0x55, 0xdc, 0xa5, 0xba, 0x47, 0x9b, 0x1e, 0x76, 0x31, 0xd1,
-	0xed, 0xc8, 0x9a, 0x8f, 0x05, 0x50, 0x19, 0x2d, 0xcb, 0x6d, 0xfb, 0x3e, 0x98, 0x77, 0xc3, 0x45,
-	0x1e, 0xb1, 0xb7, 0xf2, 0x99, 0xc7, 0xc1, 0x37, 0x4d, 0xd3, 0xf2, 0xb3, 0x3b, 0x86, 0x8e, 0x01,
-	0xa5, 0x0a, 0x78, 0x35, 0xcb, 0x12, 0xec, 0x0e, 0x18, 0xfd, 0x63, 0x21, 0xdb, 0xc1, 0x94, 0x68,
-	0x74, 0xd3, 0x03, 0x36, 0xaf, 0x8f, 0x65, 0xb3, 0x8a, 0xda, 0xb8, 0xab, 0xdb, 0x99, 0x26, 0xff,
-	0xaa, 0x00, 0x8e, 0x31, 0xdd, 0x43, 0x72, 0x11, 0x2e, 0x82, 0x79, 0xc3, 0xb6, 0x90, 0x43, 0xfd,
-	0xbd, 0x02, 0xdb, 0x9b, 0x0b, 0x16, 0x1a, 0x26, 0x3c, 0x0d, 0x8e, 0x51, 0xec, 0x6a, 0xef, 0x16,
-	0xa7, 0x97, 0x85, 0xca, 0x71, 0x75, 0x86, 0x62, 0xf7, 0x5d, 0xb8, 0x02, 0x60, 0xdb, 0x72, 0x34,
-	0x17, 0x3f, 0x46, 0x9e, 0x66, 0x39, 0x5a, 0x20, 0x31, 0xb3, 0x2c, 0x54, 0xa6, 0xd5, 0x13, 0x6d,
-	0xcb, 0x69, 0xfa, 0x1b, 0x0d, 0x67, 0xdb, 0x97, 0x5d, 0x05, 0x67, 0xba, 0xba, 0x6d, 0x99, 0x3a,
-	0xc5, 0x1e, 0xe1, 0x47, 0x0c, 0xdd, 0x2d, 0x1e, 0x63, 0x78, 0x30, 0xde, 0x63, 0x87, 0xb6, 0x74,
-	0x17, 0xae, 0x80, 0x17, 0xa2, 0x55, 0x8d, 0x20, 0xca, 0xc4, 0x67, 0x99, 0xf8, 0xc9, 0x68, 0xe3,
-	0x2e, 0xa2, 0xbe, 0xec, 0x12, 0x98, 0xd7, 0x6d, 0x1b, 0x3f, 0xb6, 0x2d, 0x42, 0x8b, 0xcf, 0x2d,
-	0x4f, 0x57, 0xe6, 0xd5, 0x78, 0x01, 0x8a, 0x60, 0xce, 0x44, 0x4e, 0x8f, 0x6d, 0xce, 0xb1, 0xcd,
-	0xe8, 0x5b, 0xfa, 0x89, 0x00, 0x5e, 0x66, 0x77, 0xb4, 0x13, 0x42, 0x26, 0x92, 0xc0, 0x1b, 0x5d,
-	0xc2, 0x70, 0x1d, 0x9c, 0x0a, 0xaf, 0x43, 0xd3, 0x4d, 0xd3, 0x43, 0x84, 0x04, 0xd1, 0xab, 0xc1,
-	0x2f, 0x9f, 0x96, 0x4f, 0xf4, 0xf4, 0xb6, 0x7d, 0x55, 0xe2, 0x1b, 0x92, 0x7a, 0x32, 0x94, 0xdd,
-	0x0c, 0x56, 0xae, 0xce, 0x7d, 0xfc, 0x69, 0x79, 0xea, 0x9f, 0x9f, 0x96, 0xa7, 0xa4, 0x3b, 0x40,
-	0x1a, 0x66, 0x08, 0xcf, 0x93, 0xf3, 0xe0, 0x54, 0xd8, 0xdd, 0x22, 0x75, 0x81, 0x45, 0x27, 0x8d,
-	0x84, 0xbc, 0xaf, 0x6c, 0xd0, 0xb5, 0x66, 0x42, 0x79, 0x3e, 0xd7, 0x06, 0x74, 0x0d, 0x71, 0xad,
-	0x4f, 0xff, 0x30, 0xd7, 0xd2, 0x86, 0xc4, 0xae, 0x0d, 0x44, 0x92, 0xbb, 0xd6, 0x17, 0x35, 0x69,
-	0x11, 0x9c, 0x65, 0x80, 0xdb, 0xbb, 0x1e, 0xa6, 0xd4, 0x46, 0xac, 0xa1, 0x85, 0x65, 0xf7, 0x27,
-	0x81, 0x37, 0xb6, 0xbe, 0x5d, 0xae, 0xa6, 0x0c, 0x16, 0x88, 0xad, 0x93, 0x5d, 0xad, 0x8d, 0x28,
-	0xf2, 0x98, 0x86, 0x69, 0x15, 0xb0, 0xa5, 0x77, 0xfc, 0x15, 0x58, 0x05, 0x5f, 0x4b, 0x08, 0x68,
-	0x2c, 0x8f, 0x74, 0xc7, 0x40, 0xcc, 0xf7, 0x69, 0xf5, 0x74, 0x2c, 0xba, 0x19, 0x6e, 0xc1, 0x1f,
-	0x80, 0xa2, 0x83, 0x3e, 0xa0, 0x9a, 0x87, 0x5c, 0x1b, 0x39, 0x16, 0xd9, 0xd5, 0x0c, 0xdd, 0x31,
-	0x7d, 0x67, 0x11, 0x2b, 0x99, 0x85, 0xaa, 0x28, 0x07, 0xc3, 0x50, 0x0e, 0x87, 0xa1, 0xbc, 0x1d,
-	0x0e, 0xc3, 0xda, 0x9c, 0xdf, 0x9d, 0x3f, 0xf9, 0x5b, 0x59, 0x50, 0x5f, 0xf4, 0x51, 0xd4, 0x10,
-	0x64, 0x2b, 0xc4, 0x90, 0x2e, 0x82, 0x15, 0xe6, 0x92, 0x8a, 0x5a, 0x16, 0xa1, 0xc8, 0x43, 0x66,
-	0x5c, 0xf7, 0x8f, 0x75, 0xcf, 0xac, 0x23, 0x07, 0xb7, 0xa3, 0xc6, 0x73, 0x1d, 0x5c, 0xc8, 0x25,
-	0xcd, 0x23, 0xf2, 0x22, 0x98, 0x35, 0xd9, 0x0a, 0xeb, 0xe5, 0xf3, 0x2a, 0xff, 0x92, 0x4a, 0x7c,
-	0x3a, 0x05, 0x3d, 0x05, 0x99, 0xac, 0x85, 0x34, 0xea, 0x91, 0x9a, 0x8f, 0x04, 0x70, 0xee, 0x00,
-	0x01, 0x8e, 0xfc, 0x00, 0x9c, 0x70, 0x93, 0x7b, 0xe1, 0xb4, 0xa8, 0xe6, 0x6a, 0x6d, 0x29, 0x58,
-	0x3e, 0xc2, 0xfa, 0xf0, 0xa4, 0x06, 0x38, 0x9e, 0x12, 0x83, 0x45, 0xc0, 0xf3, 0xb7, 0x9e, 0x4e,
-	0xe7, 0x3a, 0x2c, 0x01, 0x10, 0xb6, 0xc4, 0x46, 0x9d, 0x5d, 0xe6, 0x8c, 0x9a, 0x58, 0x91, 0x6e,
-	0x03, 0x85, 0x79, 0xb3, 0x69, 0xdb, 0x4d, 0xdd, 0xf2, 0xc8, 0x8e, 0x6e, 0x6f, 0x61, 0xc7, 0x4f,
-	0xb9, 0x5a, 0xba, 0x83, 0x37, 0xea, 0x39, 0x46, 0xfb, 0xaf, 0x05, 0xb0, 0x9a, 0x1f, 0x8e, 0xc7,
-	0x6b, 0x0f, 0xbc, 0xe0, 0xea, 0x96, 0xa7, 0x75, 0x75, 0xdb, 0x7f, 0xc4, 0xb0, 0x32, 0xe0, 0x21,
-	0xbb, 0x91, 0x2f, 0x64, 0xba, 0xe5, 0xc5, 0x8a, 0xa2, 0x32, 0x73, 0xe2, 0x04, 0x38, 0xe1, 0xa6,
-	0x44, 0xa4, 0xff, 0x08, 0xe0, 0xe5, 0x91, 0xa7, 0xe0, 0x8d, 0x83, 0x6a, 0xb3, 0xb6, 0xf8, 0xe5,
-	0xd3, 0xf2, 0x4b, 0x41, 0x2b, 0xe8, 0x97, 0x18, 0x6c, 0x77, 0x3e, 0xce, 0x01, 0x2d, 0x25, 0x81,
-	0xd3, 0x2f, 0x31, 0xd8, 0x5b, 0xe0, 0x06, 0x78, 0x3e, 0x92, 0x7a, 0x84, 0x7a, 0xbc, 0xc6, 0x96,
-	0xe4, 0xf8, 0x09, 0x27, 0x07, 0x4f, 0x38, 0xb9, 0xd9, 0x79, 0x68, 0x5b, 0xc6, 0x2d, 0xd4, 0x53,
-	0x17, 0xc2, 0x13, 0xb7, 0x50, 0x4f, 0x3a, 0x03, 0x60, 0x90, 0xba, 0xba, 0xa7, 0xc7, 0x85, 0xf3,
-	0x00, 0x9c, 0x4e, 0xad, 0xf2, 0x6b, 0x69, 0x80, 0x59, 0x97, 0xad, 0xf0, 0xc9, 0x7c, 0x21, 0xe7,
-	0x5d, 0xf8, 0x47, 0x78, 0xde, 0x72, 0x00, 0xe9, 0x26, 0x2f, 0xe4, 0x54, 0x06, 0xdc, 0x71, 0x29,
-	0x32, 0x1b, 0x4e, 0xd4, 0x1e, 0xf3, 0x3c, 0x1d, 0xf7, 0x78, 0x8d, 0x8f, 0x02, 0x8a, 0xde, 0x6b,
-	0xe7, 0x92, 0xf3, 0xb7, 0xef, 0xa6, 0x50, 0x58, 0xfa, 0x8b, 0x89, 0x41, 0x9c, 0xbe, 0x3a, 0x44,
-	0xa4, 0x3d, 0x9e, 0xd1, 0xe9, 0x27, 0x61, 0xa4, 0xec, 0x6d, 0x9d, 0x6c, 0x63, 0xfe, 0x15, 0x36,
-	0xe3, 0xcc, 0xf1, 0x28, 0xe4, 0x1e, 0x8f, 0x92, 0x0e, 0xd6, 0xc6, 0x50, 0xc9, 0x7d, 0xbd, 0x08,
-	0x60, 0x94, 0x1c, 0x61, 0xf8, 0x42, 0x07, 0xa3, 0xf4, 0x0b, 0x4a, 0xcf, 0x64, 0x63, 0xf2, 0x42,
-	0xf6, 0xe0, 0xdd, 0xc2, 0xed, 0xb6, 0x45, 0x88, 0x85, 0x1d, 0x35, 0xe1, 0xd1, 0x57, 0xf6, 0x16,
-	0x90, 0x7e, 0x28, 0x80, 0x8b, 0xf9, 0x2c, 0xe1, 0x8e, 0x36, 0xc1, 0x8c, 0x17, 0xb2, 0x82, 0xf9,
-	0xda, 0x9b, 0x7e, 0xa2, 0xfd, 0xf5, 0x69, 0xf9, 0xd5, 0x96, 0x45, 0x77, 0x3b, 0x0f, 0x65, 0x03,
-	0xb7, 0x39, 0x4f, 0xe1, 0x7f, 0x2e, 0x11, 0xf3, 0x91, 0x42, 0x7b, 0x2e, 0x22, 0x72, 0x1d, 0x19,
-	0x7f, 0xfe, 0xdd, 0x25, 0xc0, 0x69, 0x4c, 0x1d, 0x19, 0x2a, 0x43, 0x92, 0xd6, 0xc1, 0x32, 0xb3,
-	0xe0, 0x8e, 0x6d, 0x22, 0x42, 0xef, 0x39, 0x06, 0x76, 0xde, 0xb7, 0xbc, 0x36, 0x32, 0x77, 0x88,
-	0x91, 0x23, 0x29, 0x7f, 0x1a, 0x3e, 0x39, 0xb2, 0xcf, 0x73, 0xb3, 0x2d, 0x00, 0xbb, 0xc4, 0xd0,
-	0x08, 0x72, 0x4c, 0x2d, 0x62, 0x84, 0xbc, 0xb4, 0x5e, 0xcb, 0x55, 0x5a, 0x3b, 0xc4, 0xb8, 0x8b,
-	0x1c, 0x33, 0x9e, 0xa0, 0x41, 0x91, 0x9d, 0xea, 0xf6, 0xad, 0x57, 0xff, 0x70, 0x0e, 0x1c, 0x63,
-	0x06, 0xc1, 0x7d, 0x01, 0x9c, 0xc9, 0xe2, 0x5a, 0xf0, 0x5a, 0x2e, 0x8d, 0x43, 0x08, 0x9e, 0xb8,
-	0x79, 0x08, 0x84, 0x20, 0x24, 0xd2, 0xf5, 0x1f, 0x7d, 0xf1, 0x8f, 0x9f, 0x17, 0x36, 0xe0, 0xfa,
-	0x68, 0xf2, 0x1e, 0xa5, 0x36, 0x27, 0x73, 0xca, 0x93, 0xf0, 0x36, 0x3e, 0x84, 0x5f, 0x08, 0xbc,
-	0x81, 0xa5, 0xeb, 0x05, 0x6e, 0x8c, 0x6f, 0x61, 0x8a, 0x0d, 0x8a, 0xd7, 0x26, 0x07, 0xe0, 0x1e,
-	0xbe, 0xce, 0x3c, 0xbc, 0x0c, 0xd7, 0xc6, 0xf0, 0x30, 0xe0, 0x89, 0xf0, 0xa3, 0x02, 0x28, 0x1e,
-	0x40, 0xfe, 0x08, 0xbc, 0x3d, 0xa1, 0x65, 0x99, 0x3c, 0x53, 0x7c, 0xe7, 0x88, 0xd0, 0xb8, 0xd3,
-	0x6f, 0x33, 0xa7, 0x6b, 0xf0, 0xda, 0xb8, 0x4e, 0xfb, 0x74, 0xdf, 0xa3, 0x5a, 0x44, 0xe1, 0xe0,
-	0xff, 0x04, 0xf0, 0x52, 0x36, 0x97, 0x24, 0xf0, 0xd6, 0xc4, 0x46, 0x0f, 0x92, 0x56, 0xf1, 0xf6,
-	0xd1, 0x80, 0xf1, 0x00, 0xdc, 0x64, 0x01, 0xd8, 0x84, 0x1b, 0x13, 0x04, 0x00, 0xbb, 0x09, 0xff,
-	0xff, 0x1d, 0x3e, 0xea, 0x33, 0xe9, 0x11, 0xbc, 0x91, 0xdf, 0xea, 0x61, 0x44, 0x4f, 0xbc, 0x79,
-	0x68, 0x1c, 0xee, 0xf8, 0x26, 0x73, 0xfc, 0x0d, 0xf8, 0x7a, 0x8e, 0x5f, 0xe3, 0x22, 0x96, 0x9b,
-	0x7a, 0xf8, 0x64, 0xb8, 0x9c, 0x1c, 0xc9, 0x13, 0xb9, 0x9c, 0x41, 0x00, 0x27, 0x72, 0x39, 0x8b,
-	0xbf, 0x4d, 0xe6, 0x72, 0x6a, 0x5e, 0xc2, 0x3f, 0x0a, 0xfc, 0x59, 0x96, 0xa2, 0x6e, 0xf0, 0xad,
-	0xfc, 0x26, 0x66, 0x31, 0x42, 0x71, 0x63, 0xe2, 0xf3, 0xdc, 0xb5, 0x2b, 0xcc, 0xb5, 0x2a, 0x5c,
-	0x1d, 0xed, 0x1a, 0xe5, 0x00, 0xc1, 0x0f, 0x76, 0xf0, 0x97, 0x05, 0xf0, 0x4a, 0x0e, 0x2e, 0x06,
-	0xef, 0xe4, 0x37, 0x31, 0x17, 0x07, 0x14, 0x9b, 0x47, 0x07, 0xc8, 0x83, 0x70, 0x8b, 0x05, 0xe1,
-	0x3a, 0xdc, 0x1a, 0x1d, 0x04, 0x2f, 0x42, 0x8c, 0x73, 0xda, 0x63, 0x98, 0x5a, 0xc0, 0x2d, 0xe1,
-	0xbf, 0x06, 0xb8, 0x63, 0x9a, 0x12, 0x11, 0x38, 0xc6, 0x54, 0x3d, 0x80, 0xa0, 0x8a, 0xb5, 0xc3,
-	0x40, 0x70, 0xaf, 0x6b, 0xcc, 0xeb, 0x37, 0xe1, 0xd5, 0xd1, 0x5e, 0x87, 0xd4, 0x54, 0xeb, 0x1f,
-	0x60, 0xbf, 0x28, 0xf0, 0x5f, 0x2f, 0x73, 0x70, 0x41, 0xb8, 0x9d, 0xdf, 0xe8, 0xfc, 0x4c, 0x55,
-	0xbc, 0x77, 0xc4, 0xa8, 0x3c, 0x3a, 0x6f, 0xb0, 0xe8, 0xbc, 0x06, 0x2f, 0x8f, 0xdd, 0xdf, 0x2d,
-	0x13, 0xfe, 0x56, 0x00, 0x0b, 0x09, 0xba, 0x05, 0xbf, 0x3d, 0xc6, 0x75, 0x25, 0x69, 0x9b, 0x78,
-	0x65, 0xfc, 0x83, 0xdc, 0xfe, 0x55, 0x66, 0xff, 0x0a, 0xac, 0xe4, 0xb8, 0xdd, 0xc0, 0xc8, 0x9f,
-	0x85, 0x05, 0x3d, 0x9c, 0x78, 0x8d, 0x53, 0xd0, 0xb9, 0xb8, 0xe0, 0x38, 0x05, 0x9d, 0x8f, 0x13,
-	0x8e, 0xf3, 0x3a, 0xc1, 0x3e, 0x88, 0x66, 0x39, 0x5a, 0xcc, 0x0f, 0x93, 0xef, 0xce, 0xdf, 0x17,
-	0xc0, 0xf9, 0xdc, 0x3c, 0x0d, 0xde, 0x9b, 0xf4, 0x31, 0x39, 0x94, 0x6a, 0x8a, 0x3b, 0x47, 0x0d,
-	0xcb, 0xc3, 0x74, 0x9f, 0x85, 0x69, 0x1b, 0xaa, 0x63, 0xbf, 0x5c, 0x35, 0x17, 0x79, 0x71, 0xc4,
-	0x94, 0x27, 0xfd, 0xe4, 0xf0, 0x43, 0xf8, 0x9b, 0x02, 0xf8, 0x7a, 0x1e, 0xca, 0x07, 0x9b, 0x87,
-	0x78, 0x98, 0x64, 0xf2, 0x58, 0xf1, 0xbd, 0x23, 0x44, 0xe4, 0x91, 0x7a, 0xc0, 0x22, 0x75, 0x1f,
-	0x7e, 0x77, 0x9c, 0x48, 0x45, 0x50, 0x9a, 0xcf, 0x40, 0x13, 0x59, 0x95, 0x15, 0xaf, 0xff, 0x0a,
-	0xfc, 0x97, 0xdf, 0x2c, 0x82, 0x09, 0xaf, 0xe7, 0x77, 0x69, 0x08, 0xc1, 0x15, 0x6f, 0x1c, 0x16,
-	0x66, 0xfc, 0x81, 0x89, 0x19, 0x8e, 0xd6, 0x89, 0x81, 0xb4, 0x2e, 0x31, 0x12, 0xc1, 0xa8, 0x7d,
-	0xe7, 0xb3, 0xfd, 0x92, 0xf0, 0xf9, 0x7e, 0x49, 0xf8, 0xfb, 0x7e, 0x49, 0xf8, 0xe4, 0x59, 0x69,
-	0xea, 0xf3, 0x67, 0xa5, 0xa9, 0xbf, 0x3c, 0x2b, 0x4d, 0xdd, 0x5f, 0x1f, 0xe4, 0xfb, 0xb1, 0xbe,
-	0x4b, 0x91, 0xbe, 0xee, 0xb7, 0x94, 0x0f, 0xfa, 0x9e, 0x2a, 0x3d, 0x17, 0x91, 0x87, 0xb3, 0xec,
-	0x07, 0xe9, 0xcb, 0xff, 0x0f, 0x00, 0x00, 0xff, 0xff, 0x5f, 0xab, 0xc1, 0xc7, 0x37, 0x1e, 0x00,
-	0x00,
+	// 2023 bytes of a gzipped FileDescriptorProto
+	0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xb4, 0x59, 0xcd, 0x6f, 0xdc, 0xc6,
+	0x15, 0x17, 0x57, 0x1f, 0x91, 0x46, 0xf1, 0x47, 0xc6, 0x6a, 0x22, 0x53, 0xca, 0xae, 0xc2, 0xb4,
+	0xa9, 0x2c, 0xdb, 0xa4, 0x24, 0x37, 0xa8, 0x63, 0x47, 0x91, 0xb5, 0x5a, 0xdb, 0x59, 0xd8, 0x89,
+	0x15, 0x5a, 0x56, 0x0b, 0xb7, 0x28, 0x4d, 0x93, 0x13, 0x89, 0x30, 0x97, 0x43, 0x71, 0x66, 0xd7,
+	0x59, 0x18, 0x01, 0x9a, 0x1e, 0xda, 0x9c, 0x8a, 0xa0, 0x1f, 0x40, 0x8f, 0xb9, 0xf4, 0xd8, 0x4b,
+	0x51, 0x14, 0xf9, 0x13, 0x72, 0x6b, 0xda, 0x5c, 0x8a, 0x1e, 0xdc, 0xc2, 0xee, 0xa1, 0xe8, 0xa1,
+	0x28, 0x8c, 0x02, 0x3d, 0x15, 0x28, 0x38, 0x1c, 0x7e, 0xed, 0x72, 0x77, 0xc9, 0x5d, 0xe5, 0xa4,
+	0xe5, 0xcc, 0x9b, 0xdf, 0xbc, 0xf7, 0xe6, 0xbd, 0x37, 0xef, 0x37, 0x02, 0x8a, 0xe5, 0x50, 0xe4,
+	0x19, 0x07, 0xba, 0xe5, 0x68, 0x04, 0x19, 0x4d, 0xcf, 0xa2, 0x6d, 0xc5, 0x30, 0x5a, 0x8a, 0xeb,
+	0xe1, 0x96, 0x65, 0x22, 0x4f, 0x69, 0xad, 0x29, 0x87, 0x4d, 0xe4, 0xb5, 0x65, 0xd7, 0xc3, 0x14,
+	0xc3, 0x57, 0x33, 0x16, 0xc8, 0x86, 0xd1, 0x92, 0xc3, 0x05, 0x72, 0x6b, 0x4d, 0x5c, 0xdc, 0xc7,
+	0x78, 0xdf, 0x46, 0x8a, 0xee, 0x5a, 0x8a, 0xee, 0x38, 0x98, 0xea, 0xd4, 0xc2, 0x0e, 0x09, 0x20,
+	0xc4, 0xb9, 0x7d, 0xbc, 0x8f, 0xd9, 0x4f, 0xc5, 0xff, 0xc5, 0x47, 0x2b, 0x7c, 0x0d, 0xfb, 0xba,
+	0xdf, 0x7c, 0x5f, 0xa1, 0x56, 0x03, 0x11, 0xaa, 0x37, 0x5c, 0x2e, 0xb0, 0x9e, 0x47, 0xd5, 0x48,
+	0x8b, 0x60, 0xcd, 0x6a, 0xaf, 0x35, 0xad, 0x35, 0x85, 0x1c, 0xe8, 0x1e, 0x32, 0x35, 0x03, 0x3b,
+	0xa4, 0xd9, 0x88, 0x56, 0x7c, 0xa3, 0xcf, 0x8a, 0x87, 0x96, 0x87, 0xb8, 0xd8, 0x22, 0x45, 0x8e,
+	0x89, 0xbc, 0x86, 0xe5, 0x50, 0xc5, 0xf0, 0xda, 0x2e, 0xc5, 0xca, 0x03, 0xd4, 0x0e, 0x2d, 0x3c,
+	0x6d, 0x60, 0xd2, 0xc0, 0x44, 0x0b, 0x8c, 0x0c, 0x3e, 0x82, 0x29, 0xe9, 0x22, 0x58, 0x78, 0xcf,
+	0x77, 0xe7, 0x36, 0xdf, 0xf6, 0x3a, 0x72, 0x10, 0xb1, 0x88, 0x8a, 0x0e, 0x9b, 0x88, 0x50, 0x78,
+	0x1a, 0x4c, 0x07, 0x7b, 0x5b, 0xe6, 0xbc, 0xb0, 0x24, 0x2c, 0xcf, 0xa8, 0xcf, 0xb1, 0xef, 0xba,
+	0x29, 0x3d, 0x02, 0x8b, 0xd9, 0x2b, 0x89, 0x8b, 0x1d, 0x82, 0xe0, 0xf7, 0xc0, 0xb1, 0xfd, 0x60,
+	0x48, 0x23, 0x54, 0xa7, 0x88, 0xad, 0x9f, 0x5d, 0x5f, 0x95, 0x7b, 0x9d, 0x58, 0x6b, 0x4d, 0xee,
+	0xc0, 0xba, 0xed, 0xaf, 0xab, 0x4e, 0x7c, 0xfe, 0xb8, 0x32, 0xa6, 0x3e, 0xbf, 0x9f, 0x18, 0x93,
+	0x16, 0x81, 0x98, 0xda, 0x7c, 0xdb, 0x87, 0x0b, 0xb5, 0x96, 0xf4, 0x0e, 0xa3, 0xc2, 0x59, 0xae,
+	0x59, 0x15, 0x4c, 0xb1, 0xed, 0xc9, 0xbc, 0xb0, 0x34, 0xbe, 0x3c, 0xbb, 0xbe, 0x22, 0xe7, 0x08,
+	0x22, 0x99, 0x81, 0xa8, 0x7c, 0xa5, 0x74, 0x06, 0x7c, 0xb3, 0x7b, 0x8b, 0xdb, 0x54, 0xf7, 0xe8,
+	0x8e, 0x87, 0x5d, 0x4c, 0x74, 0x3b, 0xd2, 0xe6, 0x63, 0x01, 0x2c, 0x0f, 0x96, 0xe5, 0xba, 0x7d,
+	0x1f, 0xcc, 0xb8, 0xe1, 0x20, 0xf7, 0xd8, 0x5b, 0xf9, 0xd4, 0xe3, 0xe0, 0x5b, 0xa6, 0x69, 0xf9,
+	0xd1, 0x1d, 0x43, 0xc7, 0x80, 0xd2, 0x32, 0x78, 0x2d, 0x4b, 0x13, 0xec, 0x76, 0x29, 0xfd, 0x63,
+	0x21, 0xdb, 0xc0, 0x94, 0x68, 0x74, 0xd2, 0x5d, 0x3a, 0x6f, 0x14, 0xd2, 0x59, 0x45, 0x0d, 0xdc,
+	0xd2, 0xed, 0x4c, 0x95, 0x7f, 0x55, 0x02, 0x93, 0x6c, 0xef, 0x3e, 0xb1, 0x08, 0x17, 0xc0, 0x8c,
+	0x61, 0x5b, 0xc8, 0xa1, 0xfe, 0x5c, 0x89, 0xcd, 0x4d, 0x07, 0x03, 0x75, 0x13, 0x9e, 0x02, 0x93,
+	0x14, 0xbb, 0xda, 0xbb, 0xf3, 0xe3, 0x4b, 0xc2, 0xf2, 0x31, 0x75, 0x82, 0x62, 0xf7, 0x5d, 0xb8,
+	0x02, 0x60, 0xc3, 0x72, 0x34, 0x17, 0x3f, 0x44, 0x9e, 0x66, 0x39, 0x5a, 0x20, 0x31, 0xb1, 0x24,
+	0x2c, 0x8f, 0xab, 0xc7, 0x1b, 0x96, 0xb3, 0xe3, 0x4f, 0xd4, 0x9d, 0x5d, 0x5f, 0x76, 0x15, 0xcc,
+	0xb5, 0x74, 0xdb, 0x32, 0x75, 0x8a, 0x3d, 0xc2, 0x97, 0x18, 0xba, 0x3b, 0x3f, 0xc9, 0xf0, 0x60,
+	0x3c, 0xc7, 0x16, 0x6d, 0xeb, 0x2e, 0x5c, 0x01, 0x2f, 0x44, 0xa3, 0x1a, 0x41, 0x94, 0x89, 0x4f,
+	0x31, 0xf1, 0x13, 0xd1, 0xc4, 0x6d, 0x44, 0x7d, 0xd9, 0x45, 0x30, 0xa3, 0xdb, 0x36, 0x7e, 0x68,
+	0x5b, 0x84, 0xce, 0x3f, 0xb7, 0x34, 0xbe, 0x3c, 0xa3, 0xc6, 0x03, 0x50, 0x04, 0xd3, 0x26, 0x72,
+	0xda, 0x6c, 0x72, 0x9a, 0x4d, 0x46, 0xdf, 0xd2, 0x4f, 0x04, 0xf0, 0x0a, 0x3b, 0xa3, 0xbd, 0x10,
+	0x32, 0x11, 0x04, 0xde, 0xe0, 0x14, 0x86, 0x1b, 0xe0, 0x64, 0x78, 0x1c, 0x9a, 0x6e, 0x9a, 0x1e,
+	0x22, 0x24, 0xf0, 0x5e, 0x15, 0x3e, 0x7b, 0x5c, 0x39, 0xde, 0xd6, 0x1b, 0xf6, 0x25, 0x89, 0x4f,
+	0x48, 0xea, 0x89, 0x50, 0x76, 0x2b, 0x18, 0xb9, 0x34, 0xfd, 0xf1, 0xa7, 0x95, 0xb1, 0x7f, 0x7c,
+	0x5a, 0x19, 0x93, 0x6e, 0x01, 0xa9, 0x9f, 0x22, 0x3c, 0x4e, 0xce, 0x80, 0x93, 0x61, 0x75, 0x8b,
+	0xb6, 0x0b, 0x34, 0x3a, 0x61, 0x24, 0xe4, 0xfd, 0xcd, 0xba, 0x4d, 0xdb, 0x49, 0x6c, 0x9e, 0xcf,
+	0xb4, 0xae, 0xbd, 0xfa, 0x98, 0xd6, 0xb1, 0x7f, 0x3f, 0xd3, 0xd2, 0x8a, 0xc4, 0xa6, 0x75, 0x79,
+	0x92, 0x9b, 0xd6, 0xe1, 0x35, 0x69, 0x01, 0x9c, 0x66, 0x80, 0xbb, 0x07, 0x1e, 0xa6, 0xd4, 0x46,
+	0xac, 0xa0, 0x85, 0x69, 0xf7, 0x47, 0x81, 0x17, 0xb6, 0x8e, 0x59, 0xbe, 0x4d, 0x05, 0xcc, 0x12,
+	0x5b, 0x27, 0x07, 0x5a, 0x03, 0x51, 0xe4, 0xb1, 0x1d, 0xc6, 0x55, 0xc0, 0x86, 0xde, 0xf1, 0x47,
+	0xe0, 0x3a, 0xf8, 0x5a, 0x42, 0x40, 0x63, 0x71, 0xa4, 0x3b, 0x06, 0x62, 0xb6, 0x8f, 0xab, 0xa7,
+	0x62, 0xd1, 0xad, 0x70, 0x0a, 0xfe, 0x00, 0xcc, 0x3b, 0xe8, 0x03, 0xaa, 0x79, 0xc8, 0xb5, 0x91,
+	0x63, 0x91, 0x03, 0xcd, 0xd0, 0x1d, 0xd3, 0x37, 0x16, 0xb1, 0x94, 0x99, 0x5d, 0x17, 0xe5, 0xe0,
+	0x32, 0x94, 0xc3, 0xcb, 0x50, 0xde, 0x0d, 0x2f, 0xc3, 0xea, 0xb4, 0x5f, 0x9d, 0x3f, 0xf9, 0x6b,
+	0x45, 0x50, 0x5f, 0xf4, 0x51, 0xd4, 0x10, 0x64, 0x3b, 0xc4, 0x90, 0xce, 0x81, 0x15, 0x66, 0x92,
+	0x8a, 0xf6, 0x2d, 0x42, 0x91, 0x87, 0xcc, 0x38, 0xef, 0x1f, 0xea, 0x9e, 0x59, 0x43, 0x0e, 0x6e,
+	0x44, 0x85, 0xe7, 0x2a, 0x38, 0x9b, 0x4b, 0x9a, 0x7b, 0xe4, 0x45, 0x30, 0x65, 0xb2, 0x11, 0x56,
+	0xcb, 0x67, 0x54, 0xfe, 0x25, 0x95, 0xf9, 0xed, 0x14, 0xd4, 0x14, 0x64, 0xb2, 0x12, 0x52, 0xaf,
+	0x45, 0xdb, 0x7c, 0x24, 0x80, 0x97, 0x7b, 0x08, 0x70, 0xe4, 0x7b, 0xe0, 0xb8, 0x9b, 0x9c, 0x0b,
+	0x6f, 0x8b, 0xf5, 0x5c, 0xa5, 0x2d, 0x05, 0xcb, 0xaf, 0xb0, 0x0e, 0x3c, 0xa9, 0x0e, 0x8e, 0xa5,
+	0xc4, 0xe0, 0x3c, 0xe0, 0xf1, 0x5b, 0x4b, 0x87, 0x73, 0x0d, 0x96, 0x01, 0x08, 0x4b, 0x62, 0xbd,
+	0xc6, 0x0e, 0x73, 0x42, 0x4d, 0x8c, 0x48, 0x37, 0x81, 0xc2, 0xac, 0xd9, 0xb2, 0xed, 0x1d, 0xdd,
+	0xf2, 0xc8, 0x9e, 0x6e, 0x6f, 0x63, 0xc7, 0x0f, 0xb9, 0x6a, 0xba, 0x82, 0xd7, 0x6b, 0x39, 0xae,
+	0xf6, 0x5f, 0x0b, 0x60, 0x35, 0x3f, 0x1c, 0xf7, 0xd7, 0x21, 0x78, 0xc1, 0xd5, 0x2d, 0x4f, 0x6b,
+	0xe9, 0xb6, 0xdf, 0xc4, 0xb0, 0x34, 0xe0, 0x2e, 0xbb, 0x96, 0xcf, 0x65, 0xba, 0xe5, 0xc5, 0x1b,
+	0x45, 0x69, 0xe6, 0xc4, 0x01, 0x70, 0xdc, 0x4d, 0x89, 0x48, 0xff, 0x11, 0xc0, 0x2b, 0x03, 0x57,
+	0xc1, 0x6b, 0xbd, 0x72, 0xb3, 0xba, 0xf0, 0xec, 0x71, 0xe5, 0xa5, 0xa0, 0x14, 0x74, 0x4a, 0x74,
+	0x97, 0x3b, 0x1f, 0xa7, 0x47, 0x49, 0x49, 0xe0, 0x74, 0x4a, 0x74, 0xd7, 0x16, 0xb8, 0x09, 0x9e,
+	0x8f, 0xa4, 0x1e, 0xa0, 0x36, 0xcf, 0xb1, 0x45, 0x39, 0x6e, 0xe1, 0xe4, 0xa0, 0x85, 0x93, 0x77,
+	0x9a, 0xf7, 0x6d, 0xcb, 0xb8, 0x81, 0xda, 0xea, 0x6c, 0xb8, 0xe2, 0x06, 0x6a, 0x4b, 0x73, 0x00,
+	0x06, 0xa1, 0xab, 0x7b, 0x7a, 0x9c, 0x38, 0xf7, 0xc0, 0xa9, 0xd4, 0x28, 0x3f, 0x96, 0x3a, 0x98,
+	0x72, 0xd9, 0x08, 0xbf, 0x99, 0xcf, 0xe6, 0x3c, 0x0b, 0x7f, 0x09, 0x8f, 0x5b, 0x0e, 0x20, 0x5d,
+	0xe7, 0x89, 0x9c, 0x8a, 0x80, 0x5b, 0x2e, 0x45, 0x66, 0xdd, 0x89, 0xca, 0x63, 0x9e, 0xd6, 0xf1,
+	0x90, 0xe7, 0xf8, 0x20, 0xa0, 0xa8, 0x5f, 0x7b, 0x39, 0x79, 0xff, 0x76, 0x9c, 0x14, 0x0a, 0x53,
+	0x7f, 0x21, 0x71, 0x11, 0xa7, 0x8f, 0x0e, 0x11, 0xe9, 0x32, 0x28, 0xa7, 0xb6, 0x2c, 0xa4, 0xef,
+	0x67, 0x02, 0x58, 0xea, 0xb1, 0x3a, 0xfa, 0x95, 0x79, 0x99, 0x0a, 0xb9, 0x2f, 0xd3, 0xae, 0xa8,
+	0x28, 0x15, 0x8c, 0x0a, 0x38, 0x07, 0x26, 0x59, 0x6b, 0xc2, 0xe2, 0x69, 0x5c, 0x0d, 0x3e, 0xfc,
+	0xe6, 0xb3, 0xd2, 0xd3, 0x70, 0xee, 0x5f, 0x04, 0x40, 0xec, 0x3a, 0x9e, 0xb2, 0x57, 0x73, 0x85,
+	0xc9, 0x20, 0xa7, 0xa8, 0x09, 0x60, 0xe9, 0x90, 0x17, 0x95, 0x74, 0x57, 0x1e, 0xc9, 0xbe, 0xad,
+	0x93, 0x5d, 0xcc, 0xbf, 0xc2, 0xfb, 0x70, 0x44, 0xa7, 0x4a, 0x3a, 0x58, 0x2b, 0xb0, 0x25, 0x77,
+	0xc7, 0x39, 0x00, 0xa3, 0x93, 0x08, 0x23, 0x22, 0x8c, 0xb1, 0xa8, 0x02, 0x04, 0xd5, 0xcf, 0x64,
+	0x9d, 0xca, 0xd9, 0xec, 0xde, 0x67, 0x1b, 0x37, 0x1a, 0x16, 0x21, 0x16, 0x76, 0xd4, 0x84, 0x45,
+	0x5f, 0x59, 0x3b, 0x26, 0xfd, 0x50, 0x00, 0xe7, 0xf2, 0x69, 0xc2, 0x0d, 0xdd, 0x01, 0x13, 0x5e,
+	0x48, 0xcc, 0x66, 0xaa, 0x6f, 0xfa, 0xb9, 0xfe, 0x97, 0xc7, 0x95, 0xd7, 0xf6, 0x2d, 0x7a, 0xd0,
+	0xbc, 0x2f, 0x1b, 0xb8, 0xc1, 0xa9, 0x22, 0xff, 0x73, 0x9e, 0x98, 0x0f, 0x14, 0xda, 0x76, 0x11,
+	0x91, 0x6b, 0xc8, 0xf8, 0xd3, 0xef, 0xce, 0x03, 0xce, 0x24, 0x6b, 0xc8, 0x50, 0x19, 0x92, 0xb4,
+	0xc1, 0xf3, 0xe4, 0x96, 0x6d, 0x22, 0x42, 0xef, 0x38, 0x06, 0x76, 0xde, 0xb7, 0xbc, 0x06, 0x32,
+	0xf7, 0x88, 0x91, 0x23, 0xcf, 0x7e, 0x1a, 0x76, 0x7d, 0xd9, 0xeb, 0xb9, 0xda, 0x16, 0x80, 0x2d,
+	0x62, 0x68, 0x04, 0x39, 0xa6, 0x16, 0x91, 0x72, 0x5e, 0xdd, 0x5e, 0xcf, 0x15, 0xb6, 0x7b, 0xc4,
+	0xb8, 0x8d, 0x1c, 0x33, 0x6e, 0x62, 0x82, 0x3a, 0x77, 0xb2, 0xd5, 0x31, 0xbe, 0xfe, 0x59, 0x05,
+	0x4c, 0x32, 0x85, 0xe0, 0x13, 0x01, 0xcc, 0x65, 0xd1, 0x5d, 0x78, 0xa5, 0x78, 0xa2, 0xa4, 0x39,
+	0xb6, 0xb8, 0x35, 0x02, 0x42, 0xe0, 0x12, 0xe9, 0xea, 0x8f, 0xbe, 0xfc, 0xfb, 0xcf, 0x4b, 0x9b,
+	0x70, 0x63, 0xf0, 0xfb, 0x49, 0x14, 0xda, 0x9c, 0x4f, 0x2b, 0x8f, 0xc2, 0xd3, 0xf8, 0x10, 0x7e,
+	0x29, 0xf0, 0x3b, 0x24, 0x9d, 0x2f, 0x70, 0xb3, 0xb8, 0x86, 0x29, 0x42, 0x2e, 0x5e, 0x19, 0x1e,
+	0x80, 0x5b, 0xf8, 0x06, 0xb3, 0xf0, 0x02, 0x5c, 0x2b, 0x60, 0x61, 0x40, 0xd5, 0xe1, 0x47, 0x25,
+	0x30, 0xdf, 0x83, 0x7f, 0x13, 0x78, 0x73, 0x48, 0xcd, 0x32, 0xa9, 0xbe, 0xf8, 0xce, 0x11, 0xa1,
+	0x71, 0xa3, 0xdf, 0x66, 0x46, 0x57, 0xe1, 0x95, 0xa2, 0x46, 0x6b, 0xc4, 0x07, 0xd4, 0x22, 0x16,
+	0x0d, 0xff, 0x27, 0x80, 0x97, 0xb2, 0xe9, 0x3c, 0x81, 0x37, 0x86, 0x56, 0xba, 0xfb, 0xdd, 0x40,
+	0xbc, 0x79, 0x34, 0x60, 0xdc, 0x01, 0xd7, 0x99, 0x03, 0xb6, 0xe0, 0xe6, 0x10, 0x0e, 0xc0, 0x6e,
+	0xc2, 0xfe, 0x7f, 0x87, 0xbc, 0x2a, 0x93, 0xa1, 0xc2, 0x6b, 0xf9, 0xb5, 0xee, 0xc7, 0xb5, 0xc5,
+	0xeb, 0x23, 0xe3, 0x70, 0xc3, 0xb7, 0x98, 0xe1, 0x97, 0xe1, 0x1b, 0x39, 0x1e, 0x44, 0xa3, 0x87,
+	0x86, 0x54, 0xef, 0x99, 0x61, 0x72, 0xb2, 0x2b, 0x1a, 0xca, 0xe4, 0x0c, 0x0e, 0x3e, 0x94, 0xc9,
+	0x59, 0x14, 0x7a, 0x38, 0x93, 0x53, 0xf7, 0x25, 0xfc, 0x83, 0xc0, 0x3b, 0xe3, 0x14, 0x7b, 0x86,
+	0x6f, 0xe5, 0x57, 0x31, 0x8b, 0x94, 0x8b, 0x9b, 0x43, 0xaf, 0xe7, 0xa6, 0x5d, 0x64, 0xa6, 0xad,
+	0xc3, 0xd5, 0xc1, 0xa6, 0x51, 0x0e, 0x10, 0xbc, 0x99, 0xc2, 0x5f, 0x96, 0xc0, 0xab, 0x39, 0xe8,
+	0x30, 0xbc, 0x95, 0x5f, 0xc5, 0x5c, 0x34, 0x5c, 0xdc, 0x39, 0x3a, 0x40, 0xee, 0x84, 0x1b, 0xcc,
+	0x09, 0x57, 0xe1, 0xf6, 0x60, 0x27, 0x78, 0x11, 0x62, 0x1c, 0xd3, 0x1e, 0xc3, 0xd4, 0x02, 0x7a,
+	0x0f, 0xff, 0xd9, 0x45, 0xdf, 0xd3, 0xac, 0x94, 0xc0, 0x02, 0xb7, 0x6a, 0x8f, 0x37, 0x02, 0xb1,
+	0x3a, 0x0a, 0x04, 0xb7, 0xba, 0xca, 0xac, 0x7e, 0x13, 0x5e, 0x1a, 0x6c, 0x75, 0xf8, 0x3a, 0xa0,
+	0x75, 0x5e, 0x60, 0xbf, 0x28, 0xf1, 0x07, 0xe4, 0x1c, 0x74, 0x1c, 0xee, 0xe6, 0x57, 0x3a, 0xff,
+	0x63, 0x81, 0x78, 0xe7, 0x88, 0x51, 0xb9, 0x77, 0x2e, 0x33, 0xef, 0xbc, 0x0e, 0x2f, 0x14, 0xae,
+	0xef, 0x96, 0x09, 0x7f, 0x2b, 0x80, 0xd9, 0x04, 0xe3, 0x85, 0xdf, 0x2e, 0x70, 0x5c, 0x49, 0xe6,
+	0x2c, 0x5e, 0x2c, 0xbe, 0x90, 0xeb, 0xbf, 0xca, 0xf4, 0x5f, 0x81, 0xcb, 0x39, 0x4e, 0x37, 0x50,
+	0xf2, 0x67, 0x61, 0x42, 0xf7, 0xe7, 0xbe, 0x45, 0x12, 0x3a, 0x17, 0x1d, 0x2f, 0x92, 0xd0, 0xf9,
+	0x68, 0x79, 0x91, 0xee, 0x04, 0xfb, 0x20, 0x9a, 0xe5, 0x68, 0x31, 0x1d, 0x4c, 0xf6, 0x9d, 0xbf,
+	0x2f, 0x81, 0x33, 0xb9, 0x79, 0x1a, 0xbc, 0x33, 0x6c, 0x33, 0xd9, 0x97, 0x6a, 0x8a, 0x7b, 0x47,
+	0x0d, 0xcb, 0xdd, 0x74, 0x97, 0xb9, 0x69, 0x17, 0xaa, 0x85, 0x3b, 0x57, 0xcd, 0x45, 0x5e, 0xec,
+	0x31, 0xe5, 0x51, 0x27, 0x39, 0xfc, 0x10, 0xfe, 0xa6, 0x04, 0xbe, 0x9e, 0x87, 0xf2, 0xc1, 0x9d,
+	0x11, 0x1a, 0x93, 0x4c, 0x1e, 0x2b, 0xbe, 0x77, 0x84, 0x88, 0xdc, 0x53, 0xf7, 0x98, 0xa7, 0xee,
+	0xc2, 0xef, 0x16, 0xf1, 0x54, 0x04, 0xa5, 0xf9, 0x0c, 0x34, 0x11, 0x55, 0x59, 0xfe, 0xfa, 0xaf,
+	0xc0, 0x1f, 0xdf, 0xb3, 0x08, 0x26, 0x2c, 0xf0, 0xe6, 0xd1, 0x87, 0xe0, 0x8a, 0xd7, 0x46, 0x85,
+	0x29, 0x7e, 0x61, 0x62, 0x86, 0xa3, 0x35, 0x63, 0x20, 0xad, 0x45, 0x8c, 0x64, 0x8a, 0xfd, 0xab,
+	0x93, 0x00, 0x24, 0x6a, 0xcd, 0xf6, 0x28, 0x6f, 0x3d, 0xa1, 0xd5, 0xb5, 0xd1, 0x40, 0x46, 0x60,
+	0x3c, 0x99, 0x35, 0xa5, 0xfa, 0x9d, 0xcf, 0x9f, 0x94, 0x85, 0x2f, 0x9e, 0x94, 0x85, 0xbf, 0x3d,
+	0x29, 0x0b, 0x9f, 0x3c, 0x2d, 0x8f, 0x7d, 0xf1, 0xb4, 0x3c, 0xf6, 0xe7, 0xa7, 0xe5, 0xb1, 0xbb,
+	0x1b, 0xdd, 0x0f, 0x1c, 0xf1, 0x66, 0xe7, 0xa3, 0xcd, 0x5a, 0xdf, 0x52, 0x3e, 0xe8, 0xe8, 0xcd,
+	0xda, 0x2e, 0x22, 0xf7, 0xa7, 0xd8, 0x3f, 0x41, 0x2e, 0xfc, 0x3f, 0x00, 0x00, 0xff, 0xff, 0xb7,
+	0x19, 0x6f, 0x26, 0xab, 0x20, 0x00, 0x00,
 }
 
 // Reference imports to suppress errors if they are not otherwise used.
@@ -1812,6 +1971,10 @@ type QueryClient interface {
 	QueryValidatorConsumerCommissionRate(ctx context.Context, in *QueryValidatorConsumerCommissionRateRequest, opts ...grpc.CallOption) (*QueryValidatorConsumerCommissionRateResponse, error)
 	// QueryOldestUnconfirmedVsc returns the send timestamp of the oldest unconfirmed VSCPacket for a given chainID
 	QueryOldestUnconfirmedVsc(ctx context.Context, in *QueryOldestUnconfirmedVscRequest, opts ...grpc.CallOption) (*QueryOldestUnconfirmedVscResponse, error)
+	// QueryConsumerValidators returns the latest set consumer-validator set for a given chainID
+	// Note that this does not necessarily mean that the consumer chain is using this validator set at this exact moment
+	// because a VSCPacket could be delayed to be delivered on the consumer chain.
+	QueryConsumerValidators(ctx context.Context, in *QueryConsumerValidatorsRequest, opts ...grpc.CallOption) (*QueryConsumerValidatorsResponse, error)
 }
 
 type queryClient struct {
@@ -1957,6 +2120,15 @@ func (c *queryClient) QueryOldestUnconfirmedVsc(ctx context.Context, in *QueryOl
 	return out, nil
 }
 
+func (c *queryClient) QueryConsumerValidators(ctx context.Context, in *QueryConsumerValidatorsRequest, opts ...grpc.CallOption) (*QueryConsumerValidatorsResponse, error) {
+	out := new(QueryConsumerValidatorsResponse)
+	err := c.cc.Invoke(ctx, "/interchain_security.ccv.provider.v1.Query/QueryConsumerValidators", in, out, opts...)
+	if err != nil {
+		return nil, err
+	}
+	return out, nil
+}
+
 // QueryServer is the server API for Query service.
 type QueryServer interface {
 	// ConsumerGenesis queries the genesis state needed to start a consumer chain
@@ -2000,6 +2172,10 @@ type QueryServer interface {
 	QueryValidatorConsumerCommissionRate(context.Context, *QueryValidatorConsumerCommissionRateRequest) (*QueryValidatorConsumerCommissionRateResponse, error)
 	// QueryOldestUnconfirmedVsc returns the send timestamp of the oldest unconfirmed VSCPacket for a given chainID
 	QueryOldestUnconfirmedVsc(context.Context, *QueryOldestUnconfirmedVscRequest) (*QueryOldestUnconfirmedVscResponse, error)
+	// QueryConsumerValidators returns the latest set consumer-validator set for a given chainID
+	// Note that this does not necessarily mean that the consumer chain is using this validator set at this exact moment
+	// because a VSCPacket could be delayed to be delivered on the consumer chain.
+	QueryConsumerValidators(context.Context, *QueryConsumerValidatorsRequest) (*QueryConsumerValidatorsResponse, error)
 }
 
 // UnimplementedQueryServer can be embedded to have forward compatible implementations.
@@ -2051,6 +2227,9 @@ func (*UnimplementedQueryServer) QueryValidatorConsumerCommissionRate(ctx contex
 func (*UnimplementedQueryServer) QueryOldestUnconfirmedVsc(ctx context.Context, req *QueryOldestUnconfirmedVscRequest) (*QueryOldestUnconfirmedVscResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method QueryOldestUnconfirmedVsc not implemented")
 }
+func (*UnimplementedQueryServer) QueryConsumerValidators(ctx context.Context, req *QueryConsumerValidatorsRequest) (*QueryConsumerValidatorsResponse, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method QueryConsumerValidators not implemented")
+}
 
 func RegisterQueryServer(s grpc1.Server, srv QueryServer) {
 	s.RegisterService(&_Query_serviceDesc, srv)
@@ -2326,6 +2505,24 @@ func _Query_QueryOldestUnconfirmedVsc_Handler(srv interface{}, ctx context.Conte
 	return interceptor(ctx, in, info, handler)
 }
 
+func _Query_QueryConsumerValidators_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(QueryConsumerValidatorsRequest)
+	if err := dec(in); err != nil {
+		return nil, err
+	}
+	if interceptor == nil {
+		return srv.(QueryServer).QueryConsumerValidators(ctx, in)
+	}
+	info := &grpc.UnaryServerInfo{
+		Server:     srv,
+		FullMethod: "/interchain_security.ccv.provider.v1.Query/QueryConsumerValidators",
+	}
+	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
+		return srv.(QueryServer).QueryConsumerValidators(ctx, req.(*QueryConsumerValidatorsRequest))
+	}
+	return interceptor(ctx, in, info, handler)
+}
+
 var _Query_serviceDesc = grpc.ServiceDesc{
 	ServiceName: "interchain_security.ccv.provider.v1.Query",
 	HandlerType: (*QueryServer)(nil),
@@ -2390,6 +2587,10 @@ var _Query_serviceDesc = grpc.ServiceDesc{
 			MethodName: "QueryOldestUnconfirmedVsc",
 			Handler:    _Query_QueryOldestUnconfirmedVsc_Handler,
 		},
+		{
+			MethodName: "QueryConsumerValidators",
+			Handler:    _Query_QueryConsumerValidators_Handler,
+		},
 	},
 	Streams:  []grpc.StreamDesc{},
 	Metadata: "interchain_security/ccv/provider/v1/query.proto",
@@ -3291,6 +3492,120 @@ func (m *QueryConsumerChainOptedInValidatorsResponse) MarshalToSizedBuffer(dAtA
 	return len(dAtA) - i, nil
 }
 
+func (m *QueryConsumerValidatorsRequest) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *QueryConsumerValidatorsRequest) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *QueryConsumerValidatorsRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if len(m.ChainId) > 0 {
+		i -= len(m.ChainId)
+		copy(dAtA[i:], m.ChainId)
+		i = encodeVarintQuery(dAtA, i, uint64(len(m.ChainId)))
+		i--
+		dAtA[i] = 0xa
+	}
+	return len(dAtA) - i, nil
+}
+
+func (m *QueryConsumerValidatorsValidator) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *QueryConsumerValidatorsValidator) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *QueryConsumerValidatorsValidator) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if m.Power != 0 {
+		i = encodeVarintQuery(dAtA, i, uint64(m.Power))
+		i--
+		dAtA[i] = 0x18
+	}
+	if m.ConsumerKey != nil {
+		{
+			size, err := m.ConsumerKey.MarshalToSizedBuffer(dAtA[:i])
+			if err != nil {
+				return 0, err
+			}
+			i -= size
+			i = encodeVarintQuery(dAtA, i, uint64(size))
+		}
+		i--
+		dAtA[i] = 0x12
+	}
+	if len(m.ProviderAddress) > 0 {
+		i -= len(m.ProviderAddress)
+		copy(dAtA[i:], m.ProviderAddress)
+		i = encodeVarintQuery(dAtA, i, uint64(len(m.ProviderAddress)))
+		i--
+		dAtA[i] = 0xa
+	}
+	return len(dAtA) - i, nil
+}
+
+func (m *QueryConsumerValidatorsResponse) Marshal() (dAtA []byte, err error) {
+	size := m.Size()
+	dAtA = make([]byte, size)
+	n, err := m.MarshalToSizedBuffer(dAtA[:size])
+	if err != nil {
+		return nil, err
+	}
+	return dAtA[:n], nil
+}
+
+func (m *QueryConsumerValidatorsResponse) MarshalTo(dAtA []byte) (int, error) {
+	size := m.Size()
+	return m.MarshalToSizedBuffer(dAtA[:size])
+}
+
+func (m *QueryConsumerValidatorsResponse) MarshalToSizedBuffer(dAtA []byte) (int, error) {
+	i := len(dAtA)
+	_ = i
+	var l int
+	_ = l
+	if len(m.Validators) > 0 {
+		for iNdEx := len(m.Validators) - 1; iNdEx >= 0; iNdEx-- {
+			{
+				size, err := m.Validators[iNdEx].MarshalToSizedBuffer(dAtA[:i])
+				if err != nil {
+					return 0, err
+				}
+				i -= size
+				i = encodeVarintQuery(dAtA, i, uint64(size))
+			}
+			i--
+			dAtA[i] = 0xa
+		}
+	}
+	return len(dAtA) - i, nil
+}
+
 func (m *QueryConsumerChainsValidatorHasToValidateRequest) Marshal() (dAtA []byte, err error) {
 	size := m.Size()
 	dAtA = make([]byte, size)
@@ -3877,7 +4192,20 @@ func (m *QueryConsumerChainOptedInValidatorsResponse) Size() (n int) {
 	return n
 }
 
-func (m *QueryConsumerChainsValidatorHasToValidateRequest) Size() (n int) {
+func (m *QueryConsumerValidatorsRequest) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	l = len(m.ChainId)
+	if l > 0 {
+		n += 1 + l + sovQuery(uint64(l))
+	}
+	return n
+}
+
+func (m *QueryConsumerValidatorsValidator) Size() (n int) {
 	if m == nil {
 		return 0
 	}
@@ -3887,35 +4215,70 @@ func (m *QueryConsumerChainsValidatorHasToValidateRequest) Size() (n int) {
 	if l > 0 {
 		n += 1 + l + sovQuery(uint64(l))
 	}
+	if m.ConsumerKey != nil {
+		l = m.ConsumerKey.Size()
+		n += 1 + l + sovQuery(uint64(l))
+	}
+	if m.Power != 0 {
+		n += 1 + sovQuery(uint64(m.Power))
+	}
 	return n
 }
 
-func (m *QueryConsumerChainsValidatorHasToValidateResponse) Size() (n int) {
+func (m *QueryConsumerValidatorsResponse) Size() (n int) {
 	if m == nil {
 		return 0
 	}
 	var l int
 	_ = l
-	if len(m.ConsumerChainIds) > 0 {
-		for _, s := range m.ConsumerChainIds {
-			l = len(s)
+	if len(m.Validators) > 0 {
+		for _, e := range m.Validators {
+			l = e.Size()
 			n += 1 + l + sovQuery(uint64(l))
 		}
 	}
 	return n
 }
 
-func (m *QueryValidatorConsumerCommissionRateRequest) Size() (n int) {
+func (m *QueryConsumerChainsValidatorHasToValidateRequest) Size() (n int) {
 	if m == nil {
 		return 0
 	}
 	var l int
 	_ = l
-	l = len(m.ChainId)
+	l = len(m.ProviderAddress)
 	if l > 0 {
 		n += 1 + l + sovQuery(uint64(l))
 	}
-	l = len(m.ProviderAddress)
+	return n
+}
+
+func (m *QueryConsumerChainsValidatorHasToValidateResponse) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	if len(m.ConsumerChainIds) > 0 {
+		for _, s := range m.ConsumerChainIds {
+			l = len(s)
+			n += 1 + l + sovQuery(uint64(l))
+		}
+	}
+	return n
+}
+
+func (m *QueryValidatorConsumerCommissionRateRequest) Size() (n int) {
+	if m == nil {
+		return 0
+	}
+	var l int
+	_ = l
+	l = len(m.ChainId)
+	if l > 0 {
+		n += 1 + l + sovQuery(uint64(l))
+	}
+	l = len(m.ProviderAddress)
 	if l > 0 {
 		n += 1 + l + sovQuery(uint64(l))
 	}
@@ -6331,6 +6694,309 @@ func (m *QueryConsumerChainOptedInValidatorsResponse) Unmarshal(dAtA []byte) err
 	}
 	return nil
 }
+func (m *QueryConsumerValidatorsRequest) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowQuery
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: QueryConsumerValidatorsRequest: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: QueryConsumerValidatorsRequest: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ChainId", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowQuery
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthQuery
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.ChainId = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipQuery(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *QueryConsumerValidatorsValidator) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowQuery
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: QueryConsumerValidatorsValidator: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: QueryConsumerValidatorsValidator: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ProviderAddress", wireType)
+			}
+			var stringLen uint64
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowQuery
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				stringLen |= uint64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			intStringLen := int(stringLen)
+			if intStringLen < 0 {
+				return ErrInvalidLengthQuery
+			}
+			postIndex := iNdEx + intStringLen
+			if postIndex < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.ProviderAddress = string(dAtA[iNdEx:postIndex])
+			iNdEx = postIndex
+		case 2:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field ConsumerKey", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowQuery
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthQuery
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			if m.ConsumerKey == nil {
+				m.ConsumerKey = &crypto.PublicKey{}
+			}
+			if err := m.ConsumerKey.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		case 3:
+			if wireType != 0 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Power", wireType)
+			}
+			m.Power = 0
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowQuery
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				m.Power |= int64(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+		default:
+			iNdEx = preIndex
+			skippy, err := skipQuery(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
+func (m *QueryConsumerValidatorsResponse) Unmarshal(dAtA []byte) error {
+	l := len(dAtA)
+	iNdEx := 0
+	for iNdEx < l {
+		preIndex := iNdEx
+		var wire uint64
+		for shift := uint(0); ; shift += 7 {
+			if shift >= 64 {
+				return ErrIntOverflowQuery
+			}
+			if iNdEx >= l {
+				return io.ErrUnexpectedEOF
+			}
+			b := dAtA[iNdEx]
+			iNdEx++
+			wire |= uint64(b&0x7F) << shift
+			if b < 0x80 {
+				break
+			}
+		}
+		fieldNum := int32(wire >> 3)
+		wireType := int(wire & 0x7)
+		if wireType == 4 {
+			return fmt.Errorf("proto: QueryConsumerValidatorsResponse: wiretype end group for non-group")
+		}
+		if fieldNum <= 0 {
+			return fmt.Errorf("proto: QueryConsumerValidatorsResponse: illegal tag %d (wire type %d)", fieldNum, wire)
+		}
+		switch fieldNum {
+		case 1:
+			if wireType != 2 {
+				return fmt.Errorf("proto: wrong wireType = %d for field Validators", wireType)
+			}
+			var msglen int
+			for shift := uint(0); ; shift += 7 {
+				if shift >= 64 {
+					return ErrIntOverflowQuery
+				}
+				if iNdEx >= l {
+					return io.ErrUnexpectedEOF
+				}
+				b := dAtA[iNdEx]
+				iNdEx++
+				msglen |= int(b&0x7F) << shift
+				if b < 0x80 {
+					break
+				}
+			}
+			if msglen < 0 {
+				return ErrInvalidLengthQuery
+			}
+			postIndex := iNdEx + msglen
+			if postIndex < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if postIndex > l {
+				return io.ErrUnexpectedEOF
+			}
+			m.Validators = append(m.Validators, &QueryConsumerValidatorsValidator{})
+			if err := m.Validators[len(m.Validators)-1].Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
+				return err
+			}
+			iNdEx = postIndex
+		default:
+			iNdEx = preIndex
+			skippy, err := skipQuery(dAtA[iNdEx:])
+			if err != nil {
+				return err
+			}
+			if (skippy < 0) || (iNdEx+skippy) < 0 {
+				return ErrInvalidLengthQuery
+			}
+			if (iNdEx + skippy) > l {
+				return io.ErrUnexpectedEOF
+			}
+			iNdEx += skippy
+		}
+	}
+
+	if iNdEx > l {
+		return io.ErrUnexpectedEOF
+	}
+	return nil
+}
 func (m *QueryConsumerChainsValidatorHasToValidateRequest) Unmarshal(dAtA []byte) error {
 	l := len(dAtA)
 	iNdEx := 0
diff --git a/x/ccv/provider/types/query.pb.gw.go b/x/ccv/provider/types/query.pb.gw.go
index 2be0974fbf..16bb010d71 100644
--- a/x/ccv/provider/types/query.pb.gw.go
+++ b/x/ccv/provider/types/query.pb.gw.go
@@ -559,6 +559,60 @@ func local_request_Query_QueryOldestUnconfirmedVsc_0(ctx context.Context, marsha
 
 }
 
+func request_Query_QueryConsumerValidators_0(ctx context.Context, marshaler runtime.Marshaler, client QueryClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq QueryConsumerValidatorsRequest
+	var metadata runtime.ServerMetadata
+
+	var (
+		val string
+		ok  bool
+		err error
+		_   = err
+	)
+
+	val, ok = pathParams["chain_id"]
+	if !ok {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id")
+	}
+
+	protoReq.ChainId, err = runtime.String(val)
+
+	if err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err)
+	}
+
+	msg, err := client.QueryConsumerValidators(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
+	return msg, metadata, err
+
+}
+
+func local_request_Query_QueryConsumerValidators_0(ctx context.Context, marshaler runtime.Marshaler, server QueryServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
+	var protoReq QueryConsumerValidatorsRequest
+	var metadata runtime.ServerMetadata
+
+	var (
+		val string
+		ok  bool
+		err error
+		_   = err
+	)
+
+	val, ok = pathParams["chain_id"]
+	if !ok {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "missing parameter %s", "chain_id")
+	}
+
+	protoReq.ChainId, err = runtime.String(val)
+
+	if err != nil {
+		return nil, metadata, status.Errorf(codes.InvalidArgument, "type mismatch, parameter: %s, error: %v", "chain_id", err)
+	}
+
+	msg, err := server.QueryConsumerValidators(ctx, &protoReq)
+	return msg, metadata, err
+
+}
+
 // RegisterQueryHandlerServer registers the http handlers for service Query to "mux".
 // UnaryRPC     :call QueryServer directly.
 // StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
@@ -910,6 +964,29 @@ func RegisterQueryHandlerServer(ctx context.Context, mux *runtime.ServeMux, serv
 
 	})
 
+	mux.Handle("GET", pattern_Query_QueryConsumerValidators_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		var stream runtime.ServerTransportStream
+		ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := local_request_Query_QueryConsumerValidators_0(rctx, inboundMarshaler, server, req, pathParams)
+		md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_Query_QueryConsumerValidators_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
 	return nil
 }
 
@@ -1251,6 +1328,26 @@ func RegisterQueryHandlerClient(ctx context.Context, mux *runtime.ServeMux, clie
 
 	})
 
+	mux.Handle("GET", pattern_Query_QueryConsumerValidators_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
+		ctx, cancel := context.WithCancel(req.Context())
+		defer cancel()
+		inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
+		rctx, err := runtime.AnnotateContext(ctx, mux, req)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+		resp, md, err := request_Query_QueryConsumerValidators_0(rctx, inboundMarshaler, client, req, pathParams)
+		ctx = runtime.NewServerMetadataContext(ctx, md)
+		if err != nil {
+			runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
+			return
+		}
+
+		forward_Query_QueryConsumerValidators_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
+
+	})
+
 	return nil
 }
 
@@ -1284,6 +1381,8 @@ var (
 	pattern_Query_QueryValidatorConsumerCommissionRate_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4, 1, 0, 4, 1, 5, 5}, []string{"interchain_security", "ccv", "provider", "consumer_commission_rate", "chain_id", "provider_address"}, "", runtime.AssumeColonVerbOpt(false)))
 
 	pattern_Query_QueryOldestUnconfirmedVsc_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"interchain_security", "ccv", "provider", "oldest_unconfirmed_vsc", "chain_id"}, "", runtime.AssumeColonVerbOpt(false)))
+
+	pattern_Query_QueryConsumerValidators_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 1, 0, 4, 1, 5, 4}, []string{"interchain_security", "ccv", "provider", "consumer_validators", "chain_id"}, "", runtime.AssumeColonVerbOpt(false)))
 )
 
 var (
@@ -1316,4 +1415,6 @@ var (
 	forward_Query_QueryValidatorConsumerCommissionRate_0 = runtime.ForwardResponseMessage
 
 	forward_Query_QueryOldestUnconfirmedVsc_0 = runtime.ForwardResponseMessage
+
+	forward_Query_QueryConsumerValidators_0 = runtime.ForwardResponseMessage
 )