Skip to content

Commit

Permalink
feat: add fields to consumer validators query (#2167)
Browse files Browse the repository at this point in the history
* extend consumer validators query

* nit

* nits

* fix msg order

* deprecate power for consumer_power
  • Loading branch information
sainoe authored Aug 23, 2024
1 parent 96ef414 commit 563774b
Show file tree
Hide file tree
Showing 5 changed files with 672 additions and 186 deletions.
32 changes: 29 additions & 3 deletions proto/interchain_security/ccv/provider/v1/query.proto
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import "interchain_security/ccv/v1/shared_consumer.proto";
import "interchain_security/ccv/v1/wire.proto";
import "tendermint/crypto/keys.proto";
import "cosmos_proto/cosmos.proto";
import "cosmos/staking/v1beta1/staking.proto";

service Query {
// ConsumerGenesis queries the genesis state needed to start a consumer chain
Expand Down Expand Up @@ -339,13 +340,38 @@ message QueryConsumerValidatorsValidator {
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;
// [DEPRECATED] use consumer_power instead
int64 power = 3 [deprecated = true];
// The power of the validator used on the consumer chain
int64 consumer_power = 4;
// The rate to charge delegators on the consumer chain, as a fraction
string rate = 4 [
string consumer_commission_rate = 5 [
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// The rate to charge delegators on the provider chain, as a fraction
string provider_commission_rate = 6 [
(gogoproto.customtype) = "cosmossdk.io/math.LegacyDec",
(gogoproto.nullable) = false
];
// description defines the description terms for the validator
cosmos.staking.v1beta1.Description description = 7 [(gogoproto.nullable) = false];
// provider_operator_address defines the address of the validator's operator
string provider_operator_address = 8 [(cosmos_proto.scalar) = "cosmos.ValidatorAddressString"];
// jailed defined whether the validator has been jailed from bonded status or not.
bool jailed = 9;
// status is the validator status (bonded/unbonding/unbonded).
cosmos.staking.v1beta1.BondStatus status = 10;
// provider_tokens defines the delegated tokens (incl. self-delegation).
string provider_tokens = 11 [
(cosmos_proto.scalar) = "cosmos.Int",
(gogoproto.customtype) = "cosmossdk.io/math.Int",
(gogoproto.nullable) = false
];
// The power of the validator used on the provider chain
int64 provider_power = 12;
// validates_current_epoch defines whether the validator has to validate for the current epoch or not
bool validates_current_epoch = 13;
}

message QueryConsumerValidatorsResponse {
Expand Down
44 changes: 27 additions & 17 deletions x/ccv/provider/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import (
"google.golang.org/grpc/status"

errorsmod "cosmossdk.io/errors"
"cosmossdk.io/math"

sdk "github.com/cosmos/cosmos-sdk/types"

Expand Down Expand Up @@ -346,30 +345,41 @@ func (k Keeper) QueryConsumerValidators(goCtx context.Context, req *types.QueryC
return nil, status.Error(codes.Internal, err.Error())
}

for _, v := range consumerValSet {
for _, consumerVal := range consumerValSet {
provAddr := types.ProviderConsAddress{Address: consumerVal.ProviderConsAddr}
consAddr := provAddr.ToSdkConsAddr()

consAddr, err := sdk.ConsAddressFromBech32(sdk.ConsAddress(v.ProviderConsAddr).String())
providerVal, err := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "invalid provider address")
k.Logger(ctx).Error("cannot find consensus address for provider address:%s", provAddr.String())
continue
}

hasToValidate, err := k.hasToValidate(ctx, provAddr, consumerId)
if err != nil {
k.Logger(ctx).Error("cannot define if validator %s has to validate for consumer %s for current epoch",
provAddr.String(), consumerId)
continue
}

var rate math.LegacyDec
consumerRate, found := k.GetConsumerCommissionRate(ctx, consumerId, types.NewProviderConsAddress(consAddr))
if found {
rate = consumerRate
} else {
v, err := k.stakingKeeper.GetValidatorByConsAddr(ctx, consAddr)
if err != nil {
return nil, status.Error(codes.InvalidArgument, fmt.Sprintf("unknown validator: %s", consAddr.String()))
}
rate = v.Commission.Rate
if !found {
consumerRate = providerVal.Commission.Rate
}

validators = append(validators, &types.QueryConsumerValidatorsValidator{
ProviderAddress: sdk.ConsAddress(v.ProviderConsAddr).String(),
ConsumerKey: v.PublicKey,
Power: v.Power,
Rate: rate,
ProviderAddress: sdk.ConsAddress(consumerVal.ProviderConsAddr).String(),
ConsumerKey: consumerVal.PublicKey,
ConsumerPower: consumerVal.Power,
ConsumerCommissionRate: consumerRate,
Description: providerVal.Description,
ProviderOperatorAddress: providerVal.OperatorAddress,
Jailed: providerVal.Jailed,
Status: providerVal.Status,
ProviderTokens: providerVal.Tokens,
ProviderCommissionRate: providerVal.Commission.Rate,
ProviderPower: providerVal.GetConsensusPower(k.stakingKeeper.PowerReduction(ctx)),
ValidatesCurrentEpoch: hasToValidate,
})
}
return &types.QueryConsumerValidatorsResponse{
Expand Down
81 changes: 59 additions & 22 deletions x/ccv/provider/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,43 +112,80 @@ func TestQueryConsumerValidators(t *testing.T) {
_, err := pk.QueryConsumerValidators(ctx, &req)
require.Error(t, err)

providerAddr1 := types.NewProviderConsAddress([]byte("providerAddr1"))
consumerKey1 := cryptotestutil.NewCryptoIdentityFromIntSeed(1).TMProtoCryptoPublicKey()
consumerValidator1 := types.ConsensusValidator{ProviderConsAddr: providerAddr1.ToSdkConsAddr(), Power: 1, PublicKey: &consumerKey1}
expectedCommissionRate1 := math.LegacyMustNewDecFromStr("0.123")
pk.SetConsumerCommissionRate(ctx, consumerId, providerAddr1, expectedCommissionRate1)
val1 := createStakingValidator(ctx, mocks, 1, 1, 1)
valConsAddr1, _ := val1.GetConsAddr()
providerAddr1 := types.NewProviderConsAddress(valConsAddr1)
pk1, _ := val1.CmtConsPublicKey()
consumerValidator1 := types.ConsensusValidator{ProviderConsAddr: providerAddr1.ToSdkConsAddr(), Power: 1, PublicKey: &pk1}
val1.Tokens = sdk.TokensFromConsensusPower(1, sdk.DefaultPowerReduction)
val1.Description = stakingtypes.Description{Moniker: "ConsumerValidator1"}
val1.Commission.Rate = math.LegacyMustNewDecFromStr("0.123")

val2 := createStakingValidator(ctx, mocks, 1, 2, 2)
valConsAddr2, _ := val2.GetConsAddr()
providerAddr2 := types.NewProviderConsAddress(valConsAddr2)
pk2, _ := val2.CmtConsPublicKey()
consumerValidator2 := types.ConsensusValidator{ProviderConsAddr: providerAddr2.ToSdkConsAddr(), Power: 2, PublicKey: &pk2}
val2.Tokens = sdk.TokensFromConsensusPower(2, sdk.DefaultPowerReduction)
val2.Description = stakingtypes.Description{Moniker: "ConsumerValidator2"}
val2.Commission.Rate = math.LegacyMustNewDecFromStr("0.123")

providerAddr2 := types.NewProviderConsAddress([]byte("providerAddr2"))
consumerKey2 := cryptotestutil.NewCryptoIdentityFromIntSeed(2).TMProtoCryptoPublicKey()
consumerValidator2 := types.ConsensusValidator{ProviderConsAddr: providerAddr2.ToSdkConsAddr(), Power: 2, PublicKey: &consumerKey2}
expectedCommissionRate2 := math.LegacyMustNewDecFromStr("0.123")
pk.SetConsumerCommissionRate(ctx, consumerId, providerAddr2, expectedCommissionRate2)
// set up the client id so the chain looks like it "started"
pk.SetConsumerClientId(ctx, consumerId, "clientID")
pk.SetConsumerValSet(ctx, consumerId, []types.ConsensusValidator{consumerValidator1, consumerValidator2})
// set a consumer commission rate for val1
val1ConsComRate := math.LegacyMustNewDecFromStr("0.456")
pk.SetConsumerCommissionRate(ctx, consumerId, providerAddr1, val1ConsComRate)

expectedResponse := types.QueryConsumerValidatorsResponse{
Validators: []*types.QueryConsumerValidatorsValidator{
{ProviderAddress: providerAddr1.String(), ConsumerKey: &consumerKey1, Power: 1, Rate: expectedCommissionRate1},
{ProviderAddress: providerAddr2.String(), ConsumerKey: &consumerKey2, Power: 2, Rate: expectedCommissionRate2},
{
ProviderAddress: providerAddr1.String(),
ConsumerKey: &pk1,
ConsumerPower: 1,
ConsumerCommissionRate: val1ConsComRate,
Description: val1.Description,
ProviderOperatorAddress: val1.OperatorAddress,
Jailed: val1.Jailed,
Status: val1.Status,
ProviderTokens: val1.Tokens,
ProviderCommissionRate: val1.Commission.Rate,
ProviderPower: 1,
ValidatesCurrentEpoch: true,
},
{
ProviderAddress: providerAddr2.String(),
ConsumerKey: &pk2,
ConsumerPower: 2,
ConsumerCommissionRate: val2.Commission.Rate,
Description: val2.Description,
ProviderOperatorAddress: val2.OperatorAddress,
Jailed: val2.Jailed,
Status: val2.Status,
ProviderTokens: val2.Tokens,
ProviderCommissionRate: val2.Commission.Rate,
ProviderPower: 2,
ValidatesCurrentEpoch: true,
},
},
}

// set up the client id so the chain looks like it "started"
pk.SetConsumerClientId(ctx, consumerId, "clientID")
pk.SetConsumerValSet(ctx, consumerId, []types.ConsensusValidator{consumerValidator1, consumerValidator2})
mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valConsAddr1).Return(val1, nil).AnyTimes()
mocks.MockStakingKeeper.EXPECT().GetValidatorByConsAddr(ctx, valConsAddr2).Return(val2, nil).AnyTimes()
mocks.MockStakingKeeper.EXPECT().PowerReduction(ctx).Return(sdk.DefaultPowerReduction).AnyTimes()

testkeeper.SetupMocksForLastBondedValidatorsExpectation(mocks.MockStakingKeeper, 2, []stakingtypes.Validator{val1, val2}, []int64{1, 2}, -1) // -1 to allow the calls "AnyTimes"

res, err := pk.QueryConsumerValidators(ctx, &req)
require.NoError(t, err)
require.Equal(t, &expectedResponse, res)

// validator with no set consumer commission rate
pk.DeleteConsumerCommissionRate(ctx, consumerId, providerAddr1)
expectedCommissionRate := math.LegacyMustNewDecFromStr("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, providerAddr1.ToSdkConsAddr()).Return(val, nil).Times(1)
res, _ = pk.QueryConsumerValidators(ctx, &req)
require.Equal(t, expectedCommissionRate, res.Validators[0].Rate)

res, err = pk.QueryConsumerValidators(ctx, &req)
require.NoError(t, err)
require.Equal(t, val1.Commission.Rate, res.Validators[0].ConsumerCommissionRate)
}

func TestQueryConsumerChainsValidatorHasToValidate(t *testing.T) {
Expand Down
1 change: 1 addition & 0 deletions x/ccv/provider/keeper/validator_set_update_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,7 @@ func createStakingValidator(ctx sdk.Context, mocks testkeeper.MockedKeepers, ind
return stakingtypes.Validator{
OperatorAddress: providerValidatorAddr.String(),
ConsensusPubkey: pkAny,
Status: stakingtypes.Bonded,
}
}

Expand Down
Loading

0 comments on commit 563774b

Please sign in to comment.