Skip to content

Commit

Permalink
resolve merge conflicts
Browse files Browse the repository at this point in the history
  • Loading branch information
mpoke committed Aug 29, 2024
2 parents 04d5eb3 + 4ed2723 commit fc801fb
Show file tree
Hide file tree
Showing 6 changed files with 569 additions and 185 deletions.
18 changes: 14 additions & 4 deletions proto/interchain_security/ccv/provider/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,14 @@ message QueryConsumerGenesisResponse {
[ (gogoproto.nullable) = false ];
}

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

message QueryConsumerChainsResponse { repeated Chain chains = 1; }

Expand All @@ -198,11 +205,14 @@ 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)
ConsumerPhase phase = 9;
// The metadata of the consumer chain
ConsumerMetadata metadata = 10 [(gogoproto.nullable) = false ];
// Corresponds to the minimal amount of (provider chain) stake required to validate on the consumer chain.
uint64 min_stake = 9;
uint64 min_stake = 11;
// Corresponds to whether inactive validators are allowed to validate the consumer chain.
bool allow_inactive_vals = 10;

bool allow_inactive_vals = 12;
}

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

import (
"fmt"
"strconv"
"strings"

"github.com/spf13/cobra"
Expand Down Expand Up @@ -72,9 +73,12 @@ func CmdConsumerGenesis() *cobra.Command {

func CmdConsumerChains() *cobra.Command {
cmd := &cobra.Command{
Use: "list-consumer-chains",
Short: "Query active consumer chains for provider chain.",
Args: cobra.ExactArgs(0),
Use: "list-consumer-chains [phase] [limit]",
Short: "Query consumer chains for provider chain.",
Long: `Query consumer chains for provider chain. An optional
integer parameter can be passed for phase filtering of consumer chains,
(Registered=1|Initialized=2|Launched=3|Stopped=4).`,
Args: cobra.MaximumNArgs(2),
RunE: func(cmd *cobra.Command, args []string) (err error) {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
Expand All @@ -83,6 +87,23 @@ func CmdConsumerChains() *cobra.Command {
queryClient := types.NewQueryClient(clientCtx)

req := &types.QueryConsumerChainsRequest{}

if args[0] != "" {
phase, err := strconv.ParseInt(args[0], 10, 32)
if err != nil {
return err
}
req.Phase = types.ConsumerPhase(phase)
}

if args[1] != "" {
limit, err := strconv.ParseInt(args[1], 10, 32)
if err != nil {
return err
}
req.Limit = int32(limit)
}

res, err := queryClient.QueryConsumerChains(cmd.Context(), req)
if err != nil {
return err
Expand Down
74 changes: 58 additions & 16 deletions x/ccv/provider/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import (
"context"
"fmt"
"sort"
"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 @@ -51,13 +52,51 @@ 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{}
phaseFilter := req.Phase

// if the phase filter is set Launched get consumer from the state directly
if phaseFilter == 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 phase filter is set, verify that the consumer has the same phase
if phaseFilter != types.ConsumerPhase_CONSUMER_PHASE_UNSPECIFIED {
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 != phaseFilter {
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
Expand All @@ -70,11 +109,7 @@ func (k Keeper) GetConsumerChain(ctx sdk.Context, consumerId string) (types.Chai
return types.Chain{}, fmt.Errorf("cannot find chainID for consumer (%s)", consumerId)
}

clientID, found := k.GetConsumerClientId(ctx, consumerId)
if !found {
return types.Chain{}, fmt.Errorf("cannot find clientID for consumer (%s)", consumerId)
}

clientID, _ := k.GetConsumerClientId(ctx, consumerId)
topN := k.GetTopN(ctx, consumerId)

// Get the minimal power in the top N for the consumer chain
Expand All @@ -84,9 +119,10 @@ func (k Keeper) GetConsumerChain(ctx sdk.Context, consumerId string) (types.Chai
minPowerInTopN = -1
}

validatorSetCap := k.GetValidatorSetCap(ctx, consumerId)

validatorsPowerCap := k.GetValidatorsPowerCap(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 @@ -100,19 +136,25 @@ func (k Keeper) GetConsumerChain(ctx sdk.Context, consumerId string) (types.Chai
strDenylist[i] = addr.String()
}

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

allowInactiveVals := k.AllowsInactiveValidators(ctx, consumerId)
minStake := k.GetMinStake(ctx, consumerId)

return types.Chain{
ChainId: chainID,
ClientId: clientID,
Top_N: topN,
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,
AllowInactiveVals: allowInactiveVals,
MinStake: minStake,
}, nil
Expand Down
131 changes: 129 additions & 2 deletions x/ccv/provider/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import (
"bytes"
"fmt"
"sort"
"strconv"
"testing"
"time"

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"
Expand All @@ -18,6 +20,7 @@ import (

cryptotestutil "github.com/cosmos/interchain-security/v5/testutil/crypto"
testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper"
"github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper"
"github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
ccvtypes "github.com/cosmos/interchain-security/v5/x/ccv/types"
)
Expand Down Expand Up @@ -427,6 +430,8 @@ func TestGetConsumerChain(t *testing.T) {
math.NewInt(300),
}

metadataLists := []types.ConsumerMetadata{}

expectedGetAllOrder := []types.Chain{}
for i, consumerID := range consumerIDs {
pk.SetConsumerChainId(ctx, consumerID, chainIDs[i])
Expand All @@ -437,6 +442,8 @@ func TestGetConsumerChain(t *testing.T) {
Top_N: topN,
ValidatorSetCap: validatorSetCaps[i],
ValidatorsPowerCap: validatorPowerCaps[i],
MinStake: minStakes[i].Uint64(),
AllowInactiveVals: allowInactiveVals[i],
})
pk.SetMinimumPowerInTopN(ctx, consumerID, expectedMinPowerInTopNs[i])
for _, addr := range allowlists[i] {
Expand All @@ -455,6 +462,12 @@ func TestGetConsumerChain(t *testing.T) {
strDenylist[j] = addr.String()
}

metadataLists = append(metadataLists, types.ConsumerMetadata{Name: chainIDs[i]})
pk.SetConsumerMetadata(ctx, consumerID, metadataLists[i])

phase := types.ConsumerPhase(int32(i + 1))
pk.SetConsumerPhase(ctx, consumerID, phase)

expectedGetAllOrder = append(expectedGetAllOrder,
types.Chain{
ChainId: chainIDs[i],
Expand All @@ -465,13 +478,15 @@ func TestGetConsumerChain(t *testing.T) {
ValidatorsPowerCap: validatorPowerCaps[i],
Allowlist: strAllowlist,
Denylist: strDenylist,
Phase: phase,
Metadata: metadataLists[i],
AllowInactiveVals: allowInactiveVals[i],
MinStake: minStakes[i].Uint64(),
})
}

for i, chainID := range pk.GetAllActiveConsumerIds(ctx) {
c, err := pk.GetConsumerChain(ctx, chainID)
for i, cId := range consumerIDs {
c, err := pk.GetConsumerChain(ctx, cId)
require.NoError(t, err)
require.Equal(t, expectedGetAllOrder[i], c)
}
Expand Down Expand Up @@ -562,3 +577,115 @@ func TestQueryConsumerIdFromClientId(t *testing.T) {
require.NoError(t, err)
require.Equal(t, expectedConsumerId, res.ConsumerId)
}

func TestQueryConsumerChains(t *testing.T) {
pk, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t))
defer ctrl.Finish()

consumerNum := 4
consumerIds := make([]string, consumerNum)
consumers := make([]*types.Chain, consumerNum)

// expect no error and returned chains
res, err := pk.QueryConsumerChains(ctx, &types.QueryConsumerChainsRequest{})
require.NoError(t, err)
require.Len(t, res.Chains, 0)

// create four consumer chains in different phase
for i := 0; i < consumerNum; i++ {
cID := pk.FetchAndIncrementConsumerId(ctx)
chainID := "consumer-" + strconv.Itoa(i)
c := types.Chain{
ChainId: chainID,
MinPowerInTop_N: -1,
ValidatorsPowerCap: 0,
ValidatorSetCap: 0,
Allowlist: []string{},
Denylist: []string{},
Phase: types.ConsumerPhase(i + 1),
Metadata: types.ConsumerMetadata{Name: chainID},
}
pk.SetConsumerPhase(ctx, cID, c.Phase)
pk.SetConsumerMetadata(ctx, cID, c.Metadata)
pk.SetConsumerChainId(ctx, cID, chainID)

consumerIds[i] = cID
consumers[i] = &c
}

testCases := []struct {
name string
setup func(ctx sdk.Context, pk keeper.Keeper)
phase_filter types.ConsumerPhase
limit int32
expConsumers []*types.Chain
}{
{
name: "expect all consumers when phase filter isn't set",
setup: func(ctx sdk.Context, pk keeper.Keeper) {},
expConsumers: consumers,
},
{
name: "expect an amount of consumer equal to the limit",
setup: func(ctx sdk.Context, pk keeper.Keeper) {},
expConsumers: consumers[:3],
limit: int32(3),
},
{
name: "expect registered consumers when phase filter is set to Registered",
setup: func(ctx sdk.Context, pk keeper.Keeper) {
consumers[0].Phase = types.ConsumerPhase_CONSUMER_PHASE_REGISTERED
pk.SetConsumerPhase(ctx, consumerIds[0], types.ConsumerPhase_CONSUMER_PHASE_REGISTERED)
},
phase_filter: types.ConsumerPhase_CONSUMER_PHASE_REGISTERED,
expConsumers: consumers[0:1],
},
{
name: "expect initialized consumers when phase is set to Initialized",
setup: func(ctx sdk.Context, pk keeper.Keeper) {
consumers[1].Phase = types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED
err := pk.AppendConsumerToBeLaunchedOnSpawnTime(ctx, consumerIds[1], time.Now())
require.NoError(t, err)
pk.SetConsumerPhase(ctx, consumerIds[1], types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)
},
phase_filter: types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED,
expConsumers: consumers[1:2],
},
{
name: "expect launched consumers when phase is set to Launched",
setup: func(ctx sdk.Context, pk keeper.Keeper) {
consumers[2].Phase = types.ConsumerPhase_CONSUMER_PHASE_LAUNCHED
consumers[2].ClientId = "ClientID"
pk.SetConsumerClientId(ctx, consumerIds[2], consumers[2].ClientId)
pk.SetConsumerPhase(ctx, consumerIds[2], types.ConsumerPhase_CONSUMER_PHASE_LAUNCHED)
},
phase_filter: types.ConsumerPhase_CONSUMER_PHASE_LAUNCHED,
expConsumers: consumers[2:3],
},
{
name: "expect stopped consumers when phase is set to Stopped",
setup: func(ctx sdk.Context, pk keeper.Keeper) {
consumers[3].Phase = types.ConsumerPhase_CONSUMER_PHASE_STOPPED
pk.SetConsumerPhase(ctx, consumerIds[3], types.ConsumerPhase_CONSUMER_PHASE_STOPPED)
},
phase_filter: types.ConsumerPhase_CONSUMER_PHASE_STOPPED,
expConsumers: consumers[3:],
},
}

for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
tc.setup(ctx, pk)
req := types.QueryConsumerChainsRequest{
Phase: tc.phase_filter,
Limit: tc.limit,
}
expectedResponse := types.QueryConsumerChainsResponse{
Chains: tc.expConsumers,
}
res, err := pk.QueryConsumerChains(ctx, &req)
require.NoError(t, err)
require.Equal(t, &expectedResponse, res)
})
}
}
Loading

0 comments on commit fc801fb

Please sign in to comment.