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: extend consumer chains query #2172

Merged
merged 21 commits into from
Aug 29, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion proto/interchain_security/ccv/provider/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,17 @@ message QueryConsumerGenesisResponse {
[ (gogoproto.nullable) = false ];
}

message QueryConsumerChainsRequest {}
message QueryConsumerChainsRequest {
// filter_by_phase enables the filtering by phase of
// the returned consumer chains
bool filter_by_phase = 1;
// The phase of the consumer chains returned (optional)
// Registered=1|Initialized=2|Launched=3|Stopped=4
ConsumerPhase phase = 2;
// The limit of consumer chains returned (optional)
// default is 100
int32 limit = 3;
}

message QueryConsumerChainsResponse { repeated Chain chains = 1; }

Expand Down Expand Up @@ -225,6 +235,10 @@ message Chain {
repeated string allowlist = 7;
// Corresponds to a list of provider consensus addresses of validators that CANNOT validate the consumer chain.
repeated string denylist = 8;
// The phase the consumer chain (Registered=0|Initialized=1|FailedToLaunch=2|Launched=3|Stopped=4)
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
// The phase the consumer chain (Registered=0|Initialized=1|FailedToLaunch=2|Launched=3|Stopped=4)
// The phase the consumer chain (Registered=1|Initialized=2|Launched=3|Stopped=4)

ConsumerPhase phase = 9;
// The metadata of the consumer chain
ConsumerMetadata metadata = 10 [(gogoproto.nullable) = false ];
}

message QueryValidatorConsumerAddrRequest {
Expand Down
23 changes: 21 additions & 2 deletions x/ccv/provider/client/cli/query.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import (
"fmt"
"strconv"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -75,9 +76,9 @@

func CmdConsumerChains() *cobra.Command {
cmd := &cobra.Command{
Use: "list-consumer-chains",
Use: "list-consumer-chains [phase] [limit]",
Short: "Query active consumer chains for provider chain.",
Args: cobra.ExactArgs(0),
Args: cobra.MaximumNArgs(2),
RunE: func(cmd *cobra.Command, args []string) (err error) {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
Expand All @@ -86,6 +87,24 @@
queryClient := types.NewQueryClient(clientCtx)

req := &types.QueryConsumerChainsRequest{}

if args[0] != "" {
phase, err := strconv.Atoi(args[0])
if err != nil {
return err
}
req.FilterByPhase = true
req.Phase = types.ConsumerPhase(phase)
Fixed Show fixed Hide fixed
}

if args[1] != "" {
limit, err := strconv.Atoi(args[1])
if err != nil {
return err
}
req.Limit = int32(limit)
Fixed Show fixed Hide fixed
}

res, err := queryClient.QueryConsumerChains(cmd.Context(), req)
if err != nil {
return err
Expand Down
86 changes: 67 additions & 19 deletions x/ccv/provider/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@ package keeper
import (
"context"
"fmt"
"strconv"

"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

errorsmod "cosmossdk.io/errors"

"cosmossdk.io/math"
sdk "github.com/cosmos/cosmos-sdk/types"

"github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types"
)
Expand Down Expand Up @@ -49,37 +50,77 @@ func (k Keeper) QueryConsumerChains(goCtx context.Context, req *types.QueryConsu

ctx := sdk.UnwrapSDKContext(goCtx)

chains := []*types.Chain{}
for _, chainID := range k.GetAllRegisteredConsumerIds(ctx) {
c, err := k.GetConsumerChain(ctx, chainID)
consumerIds := []string{}

phase := types.ConsumerPhase(req.Phase)

// if phase filter is set Launched get consumer from the state directly
if req.FilterByPhase && phase == types.ConsumerPhase_CONSUMER_PHASE_LAUNCHED {
consumerIds = append(consumerIds, k.GetAllRegisteredConsumerIds(ctx)...)
// otherwise iterate over all the consumer using the last unused consumer Id
} else {
firstUnusedConsumerId, ok := k.GetConsumerId(ctx)
if !ok {
return &types.QueryConsumerChainsResponse{}, nil
}
for i := uint64(0); i < firstUnusedConsumerId; i++ {
// if the filter is set, verify that the consumer has the same phase
if req.FilterByPhase {
p := k.GetConsumerPhase(ctx, strconv.FormatInt(int64(i), 10))
if p == types.ConsumerPhase_CONSUMER_PHASE_UNSPECIFIED {
return nil, status.Error(codes.Internal, fmt.Sprintf("cannot retrieve phase for consumer id: %d", i))
}
if p != phase {
continue
}
}

consumerIds = append(consumerIds, strconv.FormatInt(int64(i), 10))
}
}

// set limit to default value
limit := 100
if req.Limit != 0 {
// update limit if specified
limit = int(req.Limit)
}

chains := make([]*types.Chain, math.Min(len(consumerIds), limit))
for i, cID := range consumerIds {
if i == limit {
break
}
c, err := k.GetConsumerChain(ctx, cID)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
chains = append(chains, &c)
chains[i] = &c
}

return &types.QueryConsumerChainsResponse{Chains: chains}, nil
}

// GetConsumerChain returns a Chain data structure with all the necessary fields
func (k Keeper) GetConsumerChain(ctx sdk.Context, consumerId string) (types.Chain, error) {
clientID, found := k.GetConsumerClientId(ctx, consumerId)
if !found {
return types.Chain{}, fmt.Errorf("cannot find clientID for consumer (%s)", consumerId)
}

topN := k.GetTopN(ctx, consumerId)

// Get the minimal power in the top N for the consumer chain
minPowerInTopN, found := k.GetMinimumPowerInTopN(ctx, consumerId)
if !found {
k.Logger(ctx).Error("failed to get minimum power in top N, treating as -1", "chain", consumerId)
minPowerInTopN = -1
}

validatorSetCap := k.GetValidatorSetCap(ctx, consumerId)
chainID, err := k.GetConsumerChainId(ctx, consumerId)
if err != nil {
return types.Chain{}, fmt.Errorf("cannot find chain ID for consumer (%s):%s", consumerId, err)
}

validatorsPowerCap := k.GetValidatorsPowerCap(ctx, consumerId)
clientId, _ := k.GetConsumerClientId(ctx, consumerId)

phase := k.GetConsumerPhase(ctx, consumerId)
if phase == types.ConsumerPhase_CONSUMER_PHASE_UNSPECIFIED {
return types.Chain{}, fmt.Errorf("cannot find phase for consumer (%s)", consumerId)
}

allowlist := k.GetAllowList(ctx, consumerId)
strAllowlist := make([]string, len(allowlist))
Expand All @@ -93,15 +134,22 @@ func (k Keeper) GetConsumerChain(ctx sdk.Context, consumerId string) (types.Chai
strDenylist[i] = addr.String()
}

metadata, err := k.GetConsumerMetadata(ctx, consumerId)
if err != nil {
return types.Chain{}, fmt.Errorf("cannot get metadata for consumer (%s): %w", consumerId, err)
}

return types.Chain{
ChainId: consumerId,
ClientId: clientID,
Top_N: topN,
ChainId: chainID,
ClientId: clientId,
Top_N: k.GetTopN(ctx, consumerId),
MinPowerInTop_N: minPowerInTopN,
ValidatorSetCap: validatorSetCap,
ValidatorsPowerCap: validatorsPowerCap,
ValidatorSetCap: k.GetValidatorSetCap(ctx, consumerId),
ValidatorsPowerCap: k.GetValidatorsPowerCap(ctx, consumerId),
Allowlist: strAllowlist,
Denylist: strDenylist,
Phase: phase,
Metadata: metadata,
}, nil
}

Expand Down
Loading
Loading