Skip to content

Commit

Permalink
Merge branch 'feat/permissionless' into sainoe/consu-valset-query
Browse files Browse the repository at this point in the history
  • Loading branch information
sainoe committed Aug 28, 2024
2 parents 06bdfc4 + 50475e6 commit 7b48b97
Show file tree
Hide file tree
Showing 29 changed files with 533 additions and 446 deletions.
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
- Fix incorrect message defitions in the proto files of the provider module
- Fix incorrect message definitions in the proto files of the provider module
([\#2095](https://github.com/cosmos/interchain-security/pull/2095))
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
- Fix incorrect message defitions in the proto files of the provider module
- Fix incorrect message definitions in the proto files of the provider module
([\#2095](https://github.com/cosmos/interchain-security/pull/2095))
4 changes: 2 additions & 2 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,13 @@
### API BREAKING

- [Provider](x/ccv/provider)
- Fix incorrect message defitions in the proto files of the provider module
- Fix incorrect message definitions in the proto files of the provider module
([\#2095](https://github.com/cosmos/interchain-security/pull/2095))

### STATE BREAKING

- [Provider](x/ccv/provider)
- Fix incorrect message defitions in the proto files of the provider module
- Fix incorrect message definitions in the proto files of the provider module
([\#2095](https://github.com/cosmos/interchain-security/pull/2095))

## v5.1.0
Expand Down
2 changes: 1 addition & 1 deletion docs/docs/integrators/integrating_inactive_validators.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ sidebar_position: 1

# Inactive Validators Integration Guide

With the [inactive validators feature of Interchain Security](../adrs/adr-017-allowing-inactive-validators.md), validators outside of the active set on the provider chain can validate on consumer chains that allow this. Technically, this is achieved by *increasing* the MaxValidators paramater in the staking module, to let additional validators be part of the set of bonded validators. However, to keep the set of validators participating in consensus on the Cosmos Hub the same, we introduce the MaxProviderConsensusValidators parameter in the provider module, which will restrict the number of validators that actively validate on the provider chain.
With the [inactive validators feature of Interchain Security](../adrs/adr-017-allowing-inactive-validators.md), validators outside of the active set on the provider chain can validate on consumer chains that allow this. Technically, this is achieved by *increasing* the MaxValidators parameter in the staking module, to let additional validators be part of the set of bonded validators. However, to keep the set of validators participating in consensus on the Cosmos Hub the same, we introduce the MaxProviderConsensusValidators parameter in the provider module, which will restrict the number of validators that actively validate on the provider chain.

To clarify the terminology:

Expand Down
17 changes: 17 additions & 0 deletions proto/interchain_security/ccv/provider/v1/provider.proto
Original file line number Diff line number Diff line change
Expand Up @@ -464,3 +464,20 @@ message PowerShapingParameters {
// ConsumerIds contains consumer ids of chains
// Used so we can easily (de)serialize slices of strings
message ConsumerIds { repeated string ids = 1; }

// ConsumerPhase indicates the phases of a consumer chain according to ADR 019
enum ConsumerPhase {
// UNSPECIFIED defines an empty phase.
CONSUMER_PHASE_UNSPECIFIED = 0;
// REGISTERED defines the phase in which a consumer chain has been assigned a unique consumer id.
// A chain in this phase cannot yet launch.
CONSUMER_PHASE_REGISTERED = 1;
// INITIALIZED defines the phase in which a consumer chain has set all the needed parameters to launch but
// has not yet launched (e.g., because the `spawnTime` of the consumer chain has not yet been reached).
CONSUMER_PHASE_INITIALIZED = 2;
// LAUNCHED defines the phase in which a consumer chain is running and consuming a subset of the validator
// set of the provider.
CONSUMER_PHASE_LAUNCHED = 3;
// STOPPED defines the phase in which a previously-launched chain has stopped.
CONSUMER_PHASE_STOPPED = 4;
}
5 changes: 3 additions & 2 deletions proto/interchain_security/ccv/provider/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ service Msg {
rpc ConsumerModification(MsgConsumerModification) returns (MsgConsumerModificationResponse) {
option deprecated = true;
}
rpc ChangeRewardDenoms(MsgChangeRewardDenoms) returns (MsgChangeRewardDenomsResponse);
}


Expand Down Expand Up @@ -223,7 +224,7 @@ message MsgConsumerRemovalResponse {}
// MsgRemoveConsumer defines the message used to remove (and stop) a consumer chain.
// If it passes, all the consumer chain's state is eventually removed from the provider chain.
message MsgRemoveConsumer {
option (cosmos.msg.v1.signer) = "authority";
option (cosmos.msg.v1.signer) = "signer";

// the consumer id of the consumer chain to be stopped
string consumer_id = 1;
Expand All @@ -232,7 +233,7 @@ message MsgRemoveConsumer {
google.protobuf.Timestamp stop_time = 2
[ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ];
// signer address
string authority = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string signer = 3 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}

// MsgRemoveConsumerResponse defines response type for MsgRemoveConsumer messages
Expand Down
10 changes: 5 additions & 5 deletions tests/e2e/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -2227,8 +2227,8 @@ func (tr Chain) submitChangeRewardDenomsProposal(action SubmitChangeRewardDenoms
"messages": [
{
"@type": "/interchain_security.ccv.provider.v1.MsgChangeRewardDenoms",
"denoms_to_add": %s,
"denoms_to_remove": %s,
"denoms_to_add": ["%s"],
"denoms_to_remove": ["%s"],
"authority": "cosmos10d07y265gmmuvt4z0w9aw880jnsr700j6zn9kn"
}
],
Expand All @@ -2239,15 +2239,15 @@ func (tr Chain) submitChangeRewardDenomsProposal(action SubmitChangeRewardDenoms
"expedited": false
}`

denomsToAdd := []string{action.Denom}
denomsToRemove := []string{"stake"}
denomsToAdd := action.Denom
denomsToRemove := "stake"
jsonStr := fmt.Sprintf(template,
denomsToAdd,
denomsToRemove,
action.Deposit)

//#nosec G204 -- bypass unsafe quoting warning (no production code)
proposalFile := "/consumer-addition.proposal"
proposalFile := "/change-reward.proposal"
bz, err := tr.target.ExecCommand(
"/bin/bash", "-c", fmt.Sprintf(`echo '%s' > %s`, jsonStr, proposalFile),
).CombinedOutput()
Expand Down
3 changes: 2 additions & 1 deletion tests/e2e/test_driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -221,7 +221,8 @@ func (td *DefaultDriver) runAction(action interface{}) error {
target.startConsumerEvidenceDetector(action, td.verbose)
case SubmitChangeRewardDenomsProposalAction:
target = td.getTargetDriver(action.Chain)
if semver.Compare(semver.Major(target.testConfig.providerVersion), "v5") < 0 {
version := target.testConfig.providerVersion
if semver.IsValid(version) && semver.Compare(semver.Major(version), "v5") < 0 {
target.submitChangeRewardDenomsLegacyProposal(action, td.verbose)
} else {
target.submitChangeRewardDenomsProposal(action, td.verbose)
Expand Down
4 changes: 2 additions & 2 deletions tests/integration/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package integration
import (
"context"
"fmt"
"github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper"
"testing"

transfertypes "github.com/cosmos/ibc-go/v8/modules/apps/transfer/types"
Expand All @@ -22,6 +21,7 @@ import (
icstestingutils "github.com/cosmos/interchain-security/v5/testutil/ibc_testing"
testutil "github.com/cosmos/interchain-security/v5/testutil/integration"
consumertypes "github.com/cosmos/interchain-security/v5/x/ccv/consumer/types"
providertypes "github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
ccv "github.com/cosmos/interchain-security/v5/x/ccv/types"
)

Expand Down Expand Up @@ -150,7 +150,7 @@ func (suite *CCVTestSuite) SetupTest() {
// 2. MakeGenesis is called on the provider chain
// 3. ibc/testing sets the tendermint header for the consumer chain app

providerKeeper.SetConsumerPhase(suite.providerCtx(), icstestingutils.FirstConsumerId, keeper.Initialized)
providerKeeper.SetConsumerPhase(suite.providerCtx(), icstestingutils.FirstConsumerId, providertypes.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)
preProposalKeyAssignment(suite, icstestingutils.FirstConsumerId)

// start consumer chains
Expand Down
6 changes: 3 additions & 3 deletions testutil/ibc_testing/generic_setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ package ibc_testing
import (
"encoding/json"
"fmt"
clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"
"github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper"
"testing"

clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types"

ibctesting "github.com/cosmos/ibc-go/v8/testing"
testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -158,7 +158,7 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp](
providerKeeper.SetConsumerMetadata(providerChain.GetContext(), consumerId, consumerMetadata)
providerKeeper.SetConsumerInitializationParameters(providerChain.GetContext(), consumerId, initializationParameters)
providerKeeper.SetConsumerPowerShapingParameters(providerChain.GetContext(), consumerId, powerShapingParameters)
providerKeeper.SetConsumerPhase(providerChain.GetContext(), consumerId, keeper.Initialized)
providerKeeper.SetConsumerPhase(providerChain.GetContext(), consumerId, providertypes.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)
providerKeeper.AppendConsumerToBeLaunchedOnSpawnTime(providerChain.GetContext(), consumerId, coordinator.CurrentTime)

// opt-in all validators
Expand Down
2 changes: 1 addition & 1 deletion testutil/keeper/unit_test_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ func SetupForStoppingConsumerChain(t *testing.T, ctx sdk.Context,
providerKeeper.SetConsumerMetadata(ctx, consumerId, GetTestConsumerMetadata())
providerKeeper.SetConsumerInitializationParameters(ctx, consumerId, GetTestInitializationParameters())
providerKeeper.SetConsumerPowerShapingParameters(ctx, consumerId, GetTestPowerShapingParameters())
providerKeeper.SetConsumerPhase(ctx, consumerId, providerkeeper.Initialized)
providerKeeper.SetConsumerPhase(ctx, consumerId, providertypes.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)

err := providerKeeper.CreateConsumerClient(ctx, consumerId)
require.NoError(t, err)
Expand Down
10 changes: 5 additions & 5 deletions x/ccv/provider/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ func TestAssignConsensusKeyMsgHandling(t *testing.T) {
setup: func(ctx sdk.Context,
k keeper.Keeper, mocks testkeeper.MockedKeepers,
) {
k.SetConsumerPhase(ctx, "consumerId", keeper.Initialized)
k.SetConsumerPhase(ctx, "consumerId", providertypes.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)
gomock.InOrder(
mocks.MockStakingKeeper.EXPECT().GetValidator(
ctx, providerCryptoId.SDKValOpAddress(),
Expand Down Expand Up @@ -88,7 +88,7 @@ func TestAssignConsensusKeyMsgHandling(t *testing.T) {
setup: func(ctx sdk.Context,
k keeper.Keeper, mocks testkeeper.MockedKeepers,
) {
k.SetConsumerPhase(ctx, "consumerId", keeper.Initialized)
k.SetConsumerPhase(ctx, "consumerId", providertypes.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)
gomock.InOrder(
mocks.MockStakingKeeper.EXPECT().GetValidator(
ctx, providerCryptoId.SDKValOpAddress(),
Expand All @@ -103,7 +103,7 @@ func TestAssignConsensusKeyMsgHandling(t *testing.T) {
setup: func(ctx sdk.Context,
k keeper.Keeper, mocks testkeeper.MockedKeepers,
) {
k.SetConsumerPhase(ctx, "consumerId", keeper.Initialized)
k.SetConsumerPhase(ctx, "consumerId", providertypes.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)

// Use the consumer key already used by some other validator
k.SetValidatorByConsumerAddr(ctx, "consumerId", consumerConsAddr, providerConsAddr2)
Expand All @@ -127,7 +127,7 @@ func TestAssignConsensusKeyMsgHandling(t *testing.T) {
setup: func(ctx sdk.Context,
k keeper.Keeper, mocks testkeeper.MockedKeepers,
) {
k.SetConsumerPhase(ctx, "consumerId", keeper.Initialized)
k.SetConsumerPhase(ctx, "consumerId", providertypes.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)

// Use the consumer key already
k.SetValidatorByConsumerAddr(ctx, "consumerId", consumerConsAddr, providerConsAddr)
Expand All @@ -149,7 +149,7 @@ func TestAssignConsensusKeyMsgHandling(t *testing.T) {
setup: func(ctx sdk.Context,
k keeper.Keeper, mocks testkeeper.MockedKeepers,
) {
k.SetConsumerPhase(ctx, "consumerId", keeper.Initialized)
k.SetConsumerPhase(ctx, "consumerId", providertypes.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)

// Use the consumer key already used by some other validator
k.SetValidatorByConsumerAddr(ctx, "consumerId", consumerConsAddr, providerConsAddr2)
Expand Down
12 changes: 6 additions & 6 deletions x/ccv/provider/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,9 +336,9 @@ func (k Keeper) QueryConsumerValidators(goCtx context.Context, req *types.QueryC
ctx := sdk.UnwrapSDKContext(goCtx)

// get the consumer phase
phase, ok := k.GetConsumerPhase(ctx, consumerId)
if !ok {
return nil, status.Error(codes.InvalidArgument, errorsmod.Wrap(types.ErrUnknownConsumerId, consumerId).Error())
phase := k.GetConsumerPhase(ctx, consumerId)
if phase == types.ConsumerPhase_CONSUMER_PHASE_UNSPECIFIED {
return nil, status.Errorf(codes.InvalidArgument, "cannot find a phase for consumer: %s", consumerId)
}

// query consumer validator set
Expand All @@ -347,22 +347,22 @@ func (k Keeper) QueryConsumerValidators(goCtx context.Context, req *types.QueryC
var err error

// if the consumer launched, the consumer valset has been persisted
if phase == Launched {
if phase == types.ConsumerPhase_CONSUMER_PHASE_LAUNCHED {
consumerValSet, err = k.GetConsumerValSet(ctx, consumerId)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
// if the consumer hasn't been launched or stopped, compute the consumer validator set
} else if phase != Stopped {
} else if phase != types.ConsumerPhase_CONSUMER_PHASE_STOPPED {
bondedValidators, err := k.GetLastBondedValidators(ctx)
if err != nil {
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to get last validators: %s", err))
}
minPower := int64(0)
// for TopN chains, compute the minPower that will be automatically opted in
if topN := k.GetTopN(ctx, consumerId); topN > 0 {
activeValidators, err := k.GetLastProviderConsensusActiveValidators(ctx)
if err != nil {
// something must be broken in the bonded validators, so we have to panic since there is no realistic way to proceed
return nil, status.Error(codes.Internal, fmt.Sprintf("failed to get active validators: %s", err))
}

Expand Down
14 changes: 6 additions & 8 deletions x/ccv/provider/keeper/grpc_query_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import (
"sort"
"testing"

"github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper"

"github.com/golang/mock/gomock"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -85,7 +83,7 @@ func TestQueryConsumerChainOptedInValidators(t *testing.T) {
require.Error(t, err)

pk.FetchAndIncrementConsumerId(ctx)
pk.SetConsumerPhase(ctx, consumerId, keeper.Initialized)
pk.SetConsumerPhase(ctx, consumerId, types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)

providerAddr1 := types.NewProviderConsAddress([]byte("providerAddr1"))
providerAddr2 := types.NewProviderConsAddress([]byte("providerAddr2"))
Expand Down Expand Up @@ -114,7 +112,7 @@ func TestQueryConsumerValidators(t *testing.T) {
require.Error(t, err)

// set the consumer to the "registered" phase
pk.SetConsumerPhase(ctx, consumerId, keeper.Registered)
pk.SetConsumerPhase(ctx, consumerId, types.ConsumerPhase_CONSUMER_PHASE_REGISTERED)

// expect empty valset
testkeeper.SetupMocksForLastBondedValidatorsExpectation(mocks.MockStakingKeeper, 0, []stakingtypes.Validator{}, 1) // -1 to allow the calls "AnyTimes"
Expand Down Expand Up @@ -228,13 +226,13 @@ func TestQueryConsumerValidators(t *testing.T) {
require.Equal(t, &expRes, res)

// expect same result when consumer is in "initialized" phase
pk.SetConsumerPhase(ctx, consumerId, keeper.Initialized)
pk.SetConsumerPhase(ctx, consumerId, types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)
res, err = pk.QueryConsumerValidators(ctx, &req)
require.NoError(t, err)
require.Equal(t, &expRes, res)

// set consumer to the "launched" phase
pk.SetConsumerPhase(ctx, consumerId, keeper.Launched)
pk.SetConsumerPhase(ctx, consumerId, types.ConsumerPhase_CONSUMER_PHASE_LAUNCHED)

// expect an empty consumer valset
// since neither QueueVSCPackets or MakeConsumerGenesis was called at this point
Expand Down Expand Up @@ -284,7 +282,7 @@ func TestQueryConsumerValidators(t *testing.T) {
require.Equal(t, val1.Commission.Rate, res.Validators[0].ConsumerCommissionRate)

// set consumer to stopped phase
pk.SetConsumerPhase(ctx, consumerId, keeper.Stopped)
pk.SetConsumerPhase(ctx, consumerId, types.ConsumerPhase_CONSUMER_PHASE_STOPPED)
// expect empty valset
res, err = pk.QueryConsumerValidators(ctx, &req)
require.NoError(t, err)
Expand Down Expand Up @@ -356,7 +354,7 @@ func TestQueryValidatorConsumerCommissionRate(t *testing.T) {
require.Error(t, err)

pk.FetchAndIncrementConsumerId(ctx)
pk.SetConsumerPhase(ctx, consumerId, keeper.Initialized)
pk.SetConsumerPhase(ctx, consumerId, types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)

// validator with set consumer commission rate
expectedCommissionRate := math.LegacyMustNewDecFromStr("0.123")
Expand Down
10 changes: 6 additions & 4 deletions x/ccv/provider/keeper/hooks_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
package keeper_test

import (
"testing"

sdk "github.com/cosmos/cosmos-sdk/types"
cryptotestutil "github.com/cosmos/interchain-security/v5/testutil/crypto"
testkeeper "github.com/cosmos/interchain-security/v5/testutil/keeper"
providerkeeper "github.com/cosmos/interchain-security/v5/x/ccv/provider/keeper"
"github.com/cosmos/interchain-security/v5/x/ccv/provider/types"
"github.com/golang/mock/gomock"
"testing"
)

func TestValidatorConsensusKeyInUse(t *testing.T) {
Expand All @@ -30,7 +32,7 @@ func TestValidatorConsensusKeyInUse(t *testing.T) {
name: "in use by another validator",
setup: func(ctx sdk.Context, k providerkeeper.Keeper) {
k.FetchAndIncrementConsumerId(ctx)
k.SetConsumerPhase(ctx, "0", providerkeeper.Initialized)
k.SetConsumerPhase(ctx, "0", types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)

// We are trying to add a new validator, but its address has already been used
// by another validator
Expand All @@ -47,8 +49,8 @@ func TestValidatorConsensusKeyInUse(t *testing.T) {
setup: func(ctx sdk.Context, k providerkeeper.Keeper) {
k.FetchAndIncrementConsumerId(ctx)
k.FetchAndIncrementConsumerId(ctx)
k.SetConsumerPhase(ctx, "0", providerkeeper.Initialized)
k.SetConsumerPhase(ctx, "1", providerkeeper.Initialized)
k.SetConsumerPhase(ctx, "0", types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)
k.SetConsumerPhase(ctx, "1", types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED)

// We are trying to add a new validator, but its address has already been used
// by another validator, of which there are several, across potentially several chains
Expand Down
6 changes: 4 additions & 2 deletions x/ccv/provider/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -752,8 +752,10 @@ func (k Keeper) GetAllActiveConsumerIds(ctx sdk.Context) []string {
consumerIds := []string{}
for i := uint64(0); i < latestConsumerId; i++ {
consumerId := fmt.Sprintf("%d", i)
phase, foundPhase := k.GetConsumerPhase(ctx, consumerId)
if !foundPhase || (phase != Registered && phase != Initialized && phase != Launched) {
phase := k.GetConsumerPhase(ctx, consumerId)
if phase != types.ConsumerPhase_CONSUMER_PHASE_REGISTERED &&
phase != types.ConsumerPhase_CONSUMER_PHASE_INITIALIZED &&
phase != types.ConsumerPhase_CONSUMER_PHASE_LAUNCHED {
continue
}
consumerIds = append(consumerIds, consumerId)
Expand Down
Loading

0 comments on commit 7b48b97

Please sign in to comment.