Skip to content

Commit

Permalink
init commit
Browse files Browse the repository at this point in the history
  • Loading branch information
insumity committed Oct 29, 2024
1 parent dd09294 commit a7fa6e6
Show file tree
Hide file tree
Showing 10 changed files with 301 additions and 130 deletions.
6 changes: 6 additions & 0 deletions docs/docs/build/modules/02-provider.md
Original file line number Diff line number Diff line change
Expand Up @@ -538,6 +538,9 @@ If the `power_shaping_parameters` field is set and `power_shaping_parameters.top

If the `new_owner_address` field is set to a value different than the gov module account address, then `top_N` needs to be zero.

We can also update the `chain_id` of a consumer chain by using the optional `new_chain_id` field. Note that the chain id of a consumer chain
can only be updated if the chain has not yet launched. After launch, the chain id of a consumer chain cannot be updated anymore.

```proto
message MsgUpdateConsumer {
option (cosmos.msg.v1.signer) = "owner";
Expand All @@ -562,6 +565,9 @@ message MsgUpdateConsumer {
// allowlisted reward denoms by the consumer chain
AllowlistedRewardDenoms allowlisted_reward_denoms = 7;
// to update the chain id of the chain (can only be updated if the chain has not yet launched)
string new_chain_id = 8;
}
```

Expand Down
5 changes: 5 additions & 0 deletions proto/interchain_security/ccv/provider/v1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -394,6 +394,11 @@ message MsgUpdateConsumer {

// allowlisted reward denoms of the consumer (if provided they overwrite previously set reward denoms)
AllowlistedRewardDenoms allowlisted_reward_denoms = 7;

// (optional) If the consumer chain has NOT yet launched, the chain id can be updated. After a chain has launched
// the chain id CANNOT be updated.
// This field is optional and can remain empty (i.e., `new_chain_id = ""`) or correspond to the chain id the chain already has.
string new_chain_id = 8;
}

// MsgUpdateConsumerResponse defines response type for MsgUpdateConsumer messages
Expand Down
3 changes: 2 additions & 1 deletion x/ccv/provider/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -359,6 +359,7 @@ where update_consumer.json has the following structure:
"allowlisted_reward_denoms": {
"denoms": ["ibc/...", "ibc/..."]
}
"new_chain_id": "newConsumer-1",
}
Note that only 'consumer_id' is mandatory. The others are optional.
Expand Down Expand Up @@ -397,7 +398,7 @@ If one of the fields is missing, it will be set to its zero value.
}

msg, err := types.NewMsgUpdateConsumer(owner, consUpdate.ConsumerId, consUpdate.NewOwnerAddress, consUpdate.Metadata,
consUpdate.InitializationParameters, consUpdate.PowerShapingParameters, consUpdate.AllowlistedRewardDenoms)
consUpdate.InitializationParameters, consUpdate.PowerShapingParameters, consUpdate.AllowlistedRewardDenoms, consUpdate.NewChainId)
if err != nil {
return err
}
Expand Down
10 changes: 10 additions & 0 deletions x/ccv/provider/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,16 @@ func (k msgServer) UpdateConsumer(goCtx context.Context, msg *types.MsgUpdateCon
return &resp, errorsmod.Wrapf(ccvtypes.ErrInvalidConsumerState, "cannot get consumer chain ID: %s", err.Error())
}

if strings.TrimSpace(msg.NewChainId) != "" && msg.NewChainId != chainId {
if k.IsConsumerPrelaunched(ctx, consumerId) {
chainId = msg.NewChainId
k.SetConsumerChainId(ctx, consumerId, chainId)
} else {
// the chain id cannot be updated if the chain is NOT in a prelaunched (i.e., registered or initialized) phase
return &resp, errorsmod.Wrapf(types.ErrInvalidPhase, "cannot update chain id of a non-prelaunched chain: %s", k.GetConsumerPhase(ctx, consumerId))
}
}

// add event attributes
eventAttributes = append(eventAttributes, []sdk.Attribute{
sdk.NewAttribute(sdk.AttributeKeyModule, types.ModuleName),
Expand Down
52 changes: 51 additions & 1 deletion x/ccv/provider/keeper/msg_server_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,9 +82,10 @@ func TestUpdateConsumer(t *testing.T) {
require.Error(t, err, "cannot update consumer chain")

// create a chain before updating it
chainId := "chainId-1"
createConsumerResponse, err := msgServer.CreateConsumer(ctx,
&providertypes.MsgCreateConsumer{
Submitter: "submitter", ChainId: "chainId-1",
Submitter: "submitter", ChainId: chainId,
Metadata: providertypes.ConsumerMetadata{
Name: "name",
Description: "description",
Expand All @@ -106,6 +107,21 @@ func TestUpdateConsumer(t *testing.T) {
})
require.Error(t, err, "expected owner address")

// assert that we can change the chain id of a registered chain
expectedChainId := "newChainId-1"
_, err = msgServer.UpdateConsumer(ctx,
&providertypes.MsgUpdateConsumer{
Owner: "submitter", ConsumerId: consumerId,
Metadata: nil,
InitializationParameters: nil,
PowerShapingParameters: nil,
NewChainId: expectedChainId,
})
require.NoError(t, err)
chainId, err = providerKeeper.GetConsumerChainId(ctx, consumerId)
require.NoError(t, err)
require.Equal(t, expectedChainId, chainId)

expectedConsumerMetadata := providertypes.ConsumerMetadata{
Name: "name2",
Description: "description2",
Expand All @@ -117,12 +133,14 @@ func TestUpdateConsumer(t *testing.T) {
expectedPowerShapingParameters := testkeeper.GetTestPowerShapingParameters()

expectedOwnerAddress := "cosmos1dkas8mu4kyhl5jrh4nzvm65qz588hy9qcz08la"
expectedChainId = "updatedChainId-1"
_, err = msgServer.UpdateConsumer(ctx,
&providertypes.MsgUpdateConsumer{
Owner: "submitter", ConsumerId: consumerId, NewOwnerAddress: expectedOwnerAddress,
Metadata: &expectedConsumerMetadata,
InitializationParameters: &expectedInitializationParameters,
PowerShapingParameters: &expectedPowerShapingParameters,
NewChainId: expectedChainId,
})
require.NoError(t, err)

Expand All @@ -146,6 +164,11 @@ func TestUpdateConsumer(t *testing.T) {
require.NoError(t, err)
require.Equal(t, expectedPowerShapingParameters, actualPowerShapingParameters)

// assert that the chain id has been updated
actualChainId, err := providerKeeper.GetConsumerChainId(ctx, consumerId)
require.NoError(t, err)
require.Equal(t, expectedChainId, actualChainId)

// assert phase
phase := providerKeeper.GetConsumerPhase(ctx, consumerId)
require.Equal(t, providertypes.CONSUMER_PHASE_INITIALIZED, phase)
Expand Down Expand Up @@ -191,6 +214,33 @@ func TestUpdateConsumer(t *testing.T) {
})
require.ErrorContains(t, err, "cannot update the initialization parameters of an an already launched chain")

// assert that we CANNOT change the chain id of a launched chain
providerKeeper.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED)
_, err = msgServer.UpdateConsumer(ctx,
&providertypes.MsgUpdateConsumer{
Owner: expectedOwnerAddress, ConsumerId: consumerId,
Metadata: nil,
InitializationParameters: nil,
PowerShapingParameters: nil,
NewChainId: "newChainId",
})
require.ErrorContains(t, err, "cannot update chain id of a non-prelaunched chain")

// assert that we can use the chain's current chain id as `NewChainId` even if the chain has launched
// as effectively this does not change anything
chainId, err = providerKeeper.GetConsumerChainId(ctx, consumerId)
require.NoError(t, err)
providerKeeper.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED)
_, err = msgServer.UpdateConsumer(ctx,
&providertypes.MsgUpdateConsumer{
Owner: expectedOwnerAddress, ConsumerId: consumerId,
Metadata: nil,
InitializationParameters: nil,
PowerShapingParameters: nil,
NewChainId: chainId,
})
require.NoError(t, err)

// assert that we can update the consumer metadata of a launched chain
providerKeeper.SetConsumerPhase(ctx, consumerId, providertypes.CONSUMER_PHASE_LAUNCHED)
expectedConsumerMetadata.Name = "name of a launched chain"
Expand Down
7 changes: 7 additions & 0 deletions x/ccv/provider/keeper/permissionless.go
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,13 @@ func (k Keeper) DeleteConsumerPhase(ctx sdk.Context, consumerId string) {
store.Delete(types.ConsumerIdToPhaseKey(consumerId))
}

// IsConsumerPrelaunched checks if a consumer chain is in its prelaunch phase
func (k Keeper) IsConsumerPrelaunched(ctx sdk.Context, consumerId string) bool {
phase := k.GetConsumerPhase(ctx, consumerId)
return phase == types.CONSUMER_PHASE_REGISTERED ||
phase == types.CONSUMER_PHASE_INITIALIZED
}

// IsConsumerActive checks if a consumer chain is either registered, initialized, or launched.
func (k Keeper) IsConsumerActive(ctx sdk.Context, consumerId string) bool {
phase := k.GetConsumerPhase(ctx, consumerId)
Expand Down
20 changes: 20 additions & 0 deletions x/ccv/provider/keeper/permissionless_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -198,3 +198,23 @@ func TestConsumerPhase(t *testing.T) {
phase = providerKeeper.GetConsumerPhase(ctx, CONSUMER_ID)
require.Equal(t, providertypes.CONSUMER_PHASE_LAUNCHED, phase)
}

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

providerKeeper.SetConsumerPhase(ctx, CONSUMER_ID, providertypes.CONSUMER_PHASE_REGISTERED)
require.True(t, providerKeeper.IsConsumerPrelaunched(ctx, CONSUMER_ID))

providerKeeper.SetConsumerPhase(ctx, CONSUMER_ID, providertypes.CONSUMER_PHASE_INITIALIZED)
require.True(t, providerKeeper.IsConsumerPrelaunched(ctx, CONSUMER_ID))

providerKeeper.SetConsumerPhase(ctx, CONSUMER_ID, providertypes.CONSUMER_PHASE_LAUNCHED)
require.False(t, providerKeeper.IsConsumerPrelaunched(ctx, CONSUMER_ID))

providerKeeper.SetConsumerPhase(ctx, CONSUMER_ID, providertypes.CONSUMER_PHASE_STOPPED)
require.False(t, providerKeeper.IsConsumerPrelaunched(ctx, CONSUMER_ID))

providerKeeper.SetConsumerPhase(ctx, CONSUMER_ID, providertypes.CONSUMER_PHASE_DELETED)
require.False(t, providerKeeper.IsConsumerPrelaunched(ctx, CONSUMER_ID))
}
8 changes: 7 additions & 1 deletion x/ccv/provider/types/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -343,7 +343,7 @@ func (msg MsgCreateConsumer) ValidateBasic() error {
// NewMsgUpdateConsumer creates a new MsgUpdateConsumer instance
func NewMsgUpdateConsumer(owner, consumerId, ownerAddress string, metadata *ConsumerMetadata,
initializationParameters *ConsumerInitializationParameters, powerShapingParameters *PowerShapingParameters,
allowlistedRewardDenoms *AllowlistedRewardDenoms,
allowlistedRewardDenoms *AllowlistedRewardDenoms, newChainId string,
) (*MsgUpdateConsumer, error) {
return &MsgUpdateConsumer{
Owner: owner,
Expand All @@ -353,6 +353,7 @@ func NewMsgUpdateConsumer(owner, consumerId, ownerAddress string, metadata *Cons
InitializationParameters: initializationParameters,
PowerShapingParameters: powerShapingParameters,
AllowlistedRewardDenoms: allowlistedRewardDenoms,
NewChainId: newChainId,
}, nil
}

Expand Down Expand Up @@ -388,6 +389,11 @@ func (msg MsgUpdateConsumer) ValidateBasic() error {
}
}

if msg.NewChainId != "" && len(msg.NewChainId) > cmttypes.MaxChainIDLen {
return errorsmod.Wrapf(ErrInvalidMsgUpdateConsumer, "NewChainId (%s) is too long; got: %d, max: %d",
msg.NewChainId, len(msg.NewChainId), cmttypes.MaxChainIDLen)
}

return nil
}

Expand Down
13 changes: 12 additions & 1 deletion x/ccv/provider/types/msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,6 +490,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) {
testCases := []struct {
name string
powerShapingParameters types.PowerShapingParameters
newChainId string
expPass bool
}{
{
Expand All @@ -504,6 +505,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) {
AllowInactiveVals: false,
Prioritylist: []string{consAddr1},
},
"validchainid-0",
true,
},
{
Expand All @@ -516,6 +518,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) {
Denylist: nil,
Prioritylist: nil,
},
"validchainid-0",
false,
},
{
Expand All @@ -530,6 +533,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) {
AllowInactiveVals: false,
Prioritylist: nil,
},
"validchainid-0",
false,
},
{
Expand All @@ -544,13 +548,20 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) {
AllowInactiveVals: false,
Prioritylist: []string{consAddr1},
},
"validchainid-0",
true,
},
{
"too long new chain id",
types.PowerShapingParameters{},
"this is an extremely long chain id that is so long that the validation would fail",
false,
},
}

for _, tc := range testCases {
// TODO (PERMISSIONLESS) add more tests
msg, _ := types.NewMsgUpdateConsumer("", "0", "cosmos1p3ucd3ptpw902fluyjzhq3ffgq4ntddac9sa3s", nil, nil, &tc.powerShapingParameters, nil)
msg, _ := types.NewMsgUpdateConsumer("", "0", "cosmos1p3ucd3ptpw902fluyjzhq3ffgq4ntddac9sa3s", nil, nil, &tc.powerShapingParameters, nil, tc.newChainId)
err := msg.ValidateBasic()
if tc.expPass {
require.NoError(t, err, "valid case: %s should not return error. got %w", tc.name, err)
Expand Down
Loading

0 comments on commit a7fa6e6

Please sign in to comment.