From a7fa6e68d969ff31e9b6524803721993d8fbf243 Mon Sep 17 00:00:00 2001 From: insumity Date: Tue, 29 Oct 2024 11:39:28 +0100 Subject: [PATCH 1/5] init commit --- docs/docs/build/modules/02-provider.md | 6 + .../ccv/provider/v1/tx.proto | 5 + x/ccv/provider/client/cli/tx.go | 3 +- x/ccv/provider/keeper/msg_server.go | 10 + x/ccv/provider/keeper/msg_server_test.go | 52 ++- x/ccv/provider/keeper/permissionless.go | 7 + x/ccv/provider/keeper/permissionless_test.go | 20 ++ x/ccv/provider/types/msg.go | 8 +- x/ccv/provider/types/msg_test.go | 13 +- x/ccv/provider/types/tx.pb.go | 307 +++++++++++------- 10 files changed, 301 insertions(+), 130 deletions(-) diff --git a/docs/docs/build/modules/02-provider.md b/docs/docs/build/modules/02-provider.md index bbbaad0cf7..dac75768b3 100644 --- a/docs/docs/build/modules/02-provider.md +++ b/docs/docs/build/modules/02-provider.md @@ -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"; @@ -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; } ``` diff --git a/proto/interchain_security/ccv/provider/v1/tx.proto b/proto/interchain_security/ccv/provider/v1/tx.proto index ea4c8e503e..ea86835759 100644 --- a/proto/interchain_security/ccv/provider/v1/tx.proto +++ b/proto/interchain_security/ccv/provider/v1/tx.proto @@ -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 diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index 52a53f3ebe..4ae23c7e6a 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -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. @@ -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 } diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index 89970c4b70..0fccc43575 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -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), diff --git a/x/ccv/provider/keeper/msg_server_test.go b/x/ccv/provider/keeper/msg_server_test.go index 7100f44079..6fe265eeea 100644 --- a/x/ccv/provider/keeper/msg_server_test.go +++ b/x/ccv/provider/keeper/msg_server_test.go @@ -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", @@ -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", @@ -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) @@ -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) @@ -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" diff --git a/x/ccv/provider/keeper/permissionless.go b/x/ccv/provider/keeper/permissionless.go index dc96a5a062..7b55635312 100644 --- a/x/ccv/provider/keeper/permissionless.go +++ b/x/ccv/provider/keeper/permissionless.go @@ -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) diff --git a/x/ccv/provider/keeper/permissionless_test.go b/x/ccv/provider/keeper/permissionless_test.go index 3039d7b282..156fb0a48e 100644 --- a/x/ccv/provider/keeper/permissionless_test.go +++ b/x/ccv/provider/keeper/permissionless_test.go @@ -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)) +} diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index 91a5282c4f..0128cc9f5f 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -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, @@ -353,6 +353,7 @@ func NewMsgUpdateConsumer(owner, consumerId, ownerAddress string, metadata *Cons InitializationParameters: initializationParameters, PowerShapingParameters: powerShapingParameters, AllowlistedRewardDenoms: allowlistedRewardDenoms, + NewChainId: newChainId, }, nil } @@ -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 } diff --git a/x/ccv/provider/types/msg_test.go b/x/ccv/provider/types/msg_test.go index f1eaa3124a..87ee0bb0fd 100644 --- a/x/ccv/provider/types/msg_test.go +++ b/x/ccv/provider/types/msg_test.go @@ -490,6 +490,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) { testCases := []struct { name string powerShapingParameters types.PowerShapingParameters + newChainId string expPass bool }{ { @@ -504,6 +505,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) { AllowInactiveVals: false, Prioritylist: []string{consAddr1}, }, + "validchainid-0", true, }, { @@ -516,6 +518,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) { Denylist: nil, Prioritylist: nil, }, + "validchainid-0", false, }, { @@ -530,6 +533,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) { AllowInactiveVals: false, Prioritylist: nil, }, + "validchainid-0", false, }, { @@ -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) diff --git a/x/ccv/provider/types/tx.pb.go b/x/ccv/provider/types/tx.pb.go index 05d4d43966..f2a5989b6a 100644 --- a/x/ccv/provider/types/tx.pb.go +++ b/x/ccv/provider/types/tx.pb.go @@ -1475,6 +1475,10 @@ type MsgUpdateConsumer struct { PowerShapingParameters *PowerShapingParameters `protobuf:"bytes,6,opt,name=power_shaping_parameters,json=powerShapingParameters,proto3" json:"power_shaping_parameters,omitempty"` // allowlisted reward denoms of the consumer (if provided they overwrite previously set reward denoms) AllowlistedRewardDenoms *AllowlistedRewardDenoms `protobuf:"bytes,7,opt,name=allowlisted_reward_denoms,json=allowlistedRewardDenoms,proto3" json:"allowlisted_reward_denoms,omitempty"` + // (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. + NewChainId string `protobuf:"bytes,8,opt,name=new_chain_id,json=newChainId,proto3" json:"new_chain_id,omitempty"` } func (m *MsgUpdateConsumer) Reset() { *m = MsgUpdateConsumer{} } @@ -1559,6 +1563,13 @@ func (m *MsgUpdateConsumer) GetAllowlistedRewardDenoms() *AllowlistedRewardDenom return nil } +func (m *MsgUpdateConsumer) GetNewChainId() string { + if m != nil { + return m.NewChainId + } + return "" +} + // MsgUpdateConsumerResponse defines response type for MsgUpdateConsumer messages type MsgUpdateConsumerResponse struct { } @@ -1630,136 +1641,137 @@ func init() { } var fileDescriptor_43221a4391e9fbf4 = []byte{ - // 2054 bytes of a gzipped FileDescriptorProto + // 2071 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xe4, 0x59, 0x4d, 0x6c, 0x1c, 0x49, 0x15, 0x76, 0x8f, 0xc7, 0xce, 0x4c, 0xd9, 0xf1, 0x4f, 0xd9, 0x59, 0xb7, 0x27, 0x59, 0x8f, 0x33, 0x2c, 0xbb, 0x56, 0x58, 0xf7, 0x6c, 0x0c, 0x1b, 0x84, 0x09, 0x48, 0xfe, 0x09, 0xc4, 0x0b, 0x8e, 0xbd, 0xed, 0x90, 0x95, 0x40, 0xa2, 0x55, 0xd3, 0x5d, 0xe9, 0x29, 0x65, 0xba, 0xab, 0xd5, 0x55, - 0x33, 0x8e, 0x39, 0xa1, 0x3d, 0xed, 0x71, 0x91, 0x38, 0x70, 0xdc, 0x03, 0x1c, 0x90, 0x40, 0xca, - 0x61, 0x8f, 0x5c, 0x91, 0x22, 0x71, 0x59, 0xf6, 0x84, 0x10, 0x0a, 0x28, 0x39, 0x2c, 0x17, 0x2e, - 0xdc, 0x38, 0x81, 0xea, 0xa7, 0x7b, 0xa6, 0x67, 0xc6, 0x76, 0x7b, 0xa2, 0x65, 0x0f, 0x7b, 0x19, - 0x75, 0xd7, 0xfb, 0xde, 0xf7, 0x7e, 0xaa, 0xea, 0xbd, 0xaa, 0x1e, 0xf0, 0x26, 0x09, 0x39, 0x8e, - 0xdd, 0x26, 0x22, 0xa1, 0xc3, 0xb0, 0xdb, 0x8e, 0x09, 0x3f, 0xa9, 0xbb, 0x6e, 0xa7, 0x1e, 0xc5, - 0xb4, 0x43, 0x3c, 0x1c, 0xd7, 0x3b, 0x37, 0xeb, 0xfc, 0xb1, 0x15, 0xc5, 0x94, 0x53, 0xf8, 0x95, - 0x21, 0x68, 0xcb, 0x75, 0x3b, 0x56, 0x82, 0xb6, 0x3a, 0x37, 0x2b, 0xf3, 0x28, 0x20, 0x21, 0xad, - 0xcb, 0x5f, 0xa5, 0x57, 0xb9, 0xe6, 0x53, 0xea, 0xb7, 0x70, 0x1d, 0x45, 0xa4, 0x8e, 0xc2, 0x90, - 0x72, 0xc4, 0x09, 0x0d, 0x99, 0x96, 0x56, 0xb5, 0x54, 0xbe, 0x35, 0xda, 0x0f, 0xeb, 0x9c, 0x04, - 0x98, 0x71, 0x14, 0x44, 0x1a, 0xb0, 0xd2, 0x0f, 0xf0, 0xda, 0xb1, 0x64, 0xd0, 0xf2, 0xe5, 0x7e, - 0x39, 0x0a, 0x4f, 0xb4, 0x68, 0xd1, 0xa7, 0x3e, 0x95, 0x8f, 0x75, 0xf1, 0x94, 0x28, 0xb8, 0x94, - 0x05, 0x94, 0x39, 0x4a, 0xa0, 0x5e, 0xb4, 0x68, 0x49, 0xbd, 0xd5, 0x03, 0xe6, 0x8b, 0xd0, 0x03, - 0xe6, 0x27, 0x5e, 0x92, 0x86, 0x5b, 0x77, 0x69, 0x8c, 0xeb, 0x6e, 0x8b, 0xe0, 0x90, 0x0b, 0xa9, - 0x7a, 0xd2, 0x80, 0x8d, 0x3c, 0xa9, 0x4c, 0x13, 0xa5, 0x74, 0xea, 0x82, 0xb4, 0x45, 0xfc, 0x26, - 0x57, 0x54, 0xac, 0xce, 0x71, 0xe8, 0xe1, 0x38, 0x20, 0xca, 0x40, 0xf7, 0x2d, 0xf1, 0xa2, 0x47, - 0xce, 0x4f, 0x22, 0xcc, 0xea, 0x58, 0xf0, 0x85, 0x2e, 0x56, 0x80, 0xda, 0x7f, 0x0c, 0xb0, 0xb8, - 0xcf, 0xfc, 0x2d, 0xc6, 0x88, 0x1f, 0xee, 0xd0, 0x90, 0xb5, 0x03, 0x1c, 0xff, 0x00, 0x9f, 0xc0, - 0x57, 0x41, 0x49, 0xf9, 0x46, 0x3c, 0xd3, 0x58, 0x35, 0xd6, 0xca, 0xdb, 0x05, 0xd3, 0xb0, 0x2f, - 0xc9, 0xb1, 0x3d, 0x0f, 0x7e, 0x13, 0x5c, 0x4e, 0x7c, 0x73, 0x90, 0xe7, 0xc5, 0x66, 0x41, 0x62, - 0xe0, 0xbf, 0x9f, 0x55, 0x67, 0x4e, 0x50, 0xd0, 0xda, 0xac, 0x89, 0x51, 0xcc, 0x58, 0xcd, 0x9e, - 0x4e, 0x80, 0x5b, 0x9e, 0x17, 0xc3, 0xeb, 0x60, 0xda, 0xd5, 0x66, 0x9c, 0x47, 0xf8, 0xc4, 0x1c, - 0x17, 0x7a, 0xf6, 0x94, 0xdb, 0x63, 0xfa, 0x2d, 0x30, 0x29, 0xbc, 0xc1, 0xb1, 0x59, 0x94, 0xa4, - 0xe6, 0xa7, 0x1f, 0xaf, 0x2f, 0xea, 0xac, 0x6f, 0x29, 0xd6, 0x23, 0x1e, 0x93, 0xd0, 0xb7, 0x35, - 0x0e, 0x56, 0x41, 0x4a, 0x20, 0xfc, 0x9d, 0x90, 0x9c, 0x20, 0x19, 0xda, 0xf3, 0x36, 0x17, 0x3e, - 0xf8, 0xa8, 0x3a, 0xf6, 0xcf, 0x8f, 0xaa, 0x63, 0xef, 0x7f, 0xf6, 0xe4, 0x86, 0xd6, 0xaa, 0xad, - 0x80, 0x6b, 0xc3, 0x42, 0xb7, 0x31, 0x8b, 0x68, 0xc8, 0x70, 0xed, 0xb9, 0x01, 0x5e, 0xdd, 0x67, - 0xfe, 0x51, 0xbb, 0x11, 0x10, 0x9e, 0x00, 0xf6, 0x09, 0x6b, 0xe0, 0x26, 0xea, 0x10, 0xda, 0x8e, - 0xe1, 0x2d, 0x50, 0x66, 0x52, 0xca, 0x71, 0xac, 0xb3, 0x74, 0xba, 0xb3, 0x5d, 0x28, 0x3c, 0x04, - 0xd3, 0x41, 0x0f, 0x8f, 0x4c, 0xde, 0xd4, 0xc6, 0x9b, 0x16, 0x69, 0xb8, 0x56, 0xef, 0xf4, 0x5a, - 0x3d, 0x13, 0xda, 0xb9, 0x69, 0xf5, 0xda, 0xb6, 0x33, 0x0c, 0xfd, 0x19, 0x18, 0x1f, 0xc8, 0xc0, - 0x2b, 0xbd, 0x19, 0xe8, 0xba, 0x52, 0x7b, 0x03, 0x7c, 0xf5, 0xcc, 0x18, 0xd3, 0x6c, 0xfc, 0xb9, - 0x30, 0x24, 0x1b, 0xbb, 0xb4, 0xdd, 0x68, 0xe1, 0x07, 0x94, 0x93, 0xd0, 0x1f, 0x39, 0x1b, 0x0e, - 0x58, 0xf2, 0xda, 0x51, 0x8b, 0xb8, 0x88, 0x63, 0xa7, 0x43, 0x39, 0x76, 0x92, 0x45, 0xaa, 0x13, - 0xf3, 0x46, 0x6f, 0x1e, 0xe4, 0x32, 0xb6, 0x76, 0x13, 0x85, 0x07, 0x94, 0xe3, 0x3b, 0x1a, 0x6e, - 0x5f, 0xf1, 0x86, 0x0d, 0xc3, 0x9f, 0x82, 0x25, 0x12, 0x3e, 0x8c, 0x91, 0x2b, 0x8a, 0x80, 0xd3, - 0x68, 0x51, 0xf7, 0x91, 0xd3, 0xc4, 0xc8, 0xc3, 0xb1, 0x4c, 0xd4, 0xd4, 0xc6, 0xeb, 0xe7, 0x65, - 0xfe, 0xae, 0x44, 0xdb, 0x57, 0xba, 0x34, 0xdb, 0x82, 0x45, 0x0d, 0xf7, 0x27, 0xbf, 0xf8, 0x52, - 0xc9, 0xef, 0x4d, 0x69, 0x9a, 0xfc, 0x5f, 0x1b, 0x60, 0x76, 0x9f, 0xf9, 0x3f, 0x8a, 0x3c, 0xc4, - 0xf1, 0x21, 0x8a, 0x51, 0xc0, 0x44, 0xba, 0x51, 0x9b, 0x37, 0xa9, 0x28, 0x1c, 0xe7, 0xa7, 0x3b, - 0x85, 0xc2, 0x3d, 0x30, 0x19, 0x49, 0x06, 0x9d, 0xdd, 0xaf, 0x59, 0x39, 0xca, 0xb4, 0xa5, 0x8c, - 0x6e, 0x17, 0x9f, 0x3e, 0xab, 0x8e, 0xd9, 0x9a, 0x60, 0x73, 0x46, 0xc6, 0x93, 0x52, 0xd7, 0x96, - 0xc1, 0x52, 0x9f, 0x97, 0x69, 0x04, 0x7f, 0x2b, 0x81, 0x85, 0x7d, 0xe6, 0x27, 0x51, 0x6e, 0x79, - 0x1e, 0x11, 0x69, 0x84, 0xcb, 0xfd, 0x75, 0xa6, 0x5b, 0x63, 0xbe, 0x0f, 0x66, 0x48, 0x48, 0x38, - 0x41, 0x2d, 0xa7, 0x89, 0xc5, 0xdc, 0x68, 0x87, 0x2b, 0x72, 0xb6, 0x44, 0x6d, 0xb5, 0x74, 0x45, - 0x95, 0x33, 0x24, 0x10, 0xda, 0xbf, 0xcb, 0x5a, 0x4f, 0x0d, 0x8a, 0x9a, 0xe3, 0xe3, 0x10, 0x33, - 0xc2, 0x9c, 0x26, 0x62, 0x4d, 0x39, 0xe9, 0xd3, 0xf6, 0x94, 0x1e, 0xbb, 0x8b, 0x58, 0x53, 0x4c, - 0x61, 0x83, 0x84, 0x28, 0x3e, 0x51, 0x88, 0xa2, 0x44, 0x00, 0x35, 0x24, 0x01, 0x3b, 0x00, 0xb0, - 0x08, 0x1d, 0x87, 0x8e, 0xe8, 0x36, 0xb2, 0xc2, 0x08, 0x47, 0x54, 0x27, 0xb1, 0x92, 0x4e, 0x62, - 0xdd, 0x4f, 0x5a, 0xd1, 0x76, 0x49, 0x38, 0xf2, 0xe1, 0xdf, 0xab, 0x86, 0x5d, 0x96, 0x7a, 0x42, - 0x02, 0xef, 0x81, 0xb9, 0x76, 0xd8, 0xa0, 0xa1, 0x47, 0x42, 0xdf, 0x89, 0x70, 0x4c, 0xa8, 0x67, - 0x4e, 0x4a, 0xaa, 0xe5, 0x01, 0xaa, 0x5d, 0xdd, 0xb4, 0x14, 0xd3, 0xaf, 0x04, 0xd3, 0x6c, 0xaa, - 0x7c, 0x28, 0x75, 0xe1, 0xbb, 0x00, 0xba, 0x6e, 0x47, 0xba, 0x44, 0xdb, 0x3c, 0x61, 0xbc, 0x94, - 0x9f, 0x71, 0xce, 0x75, 0x3b, 0xf7, 0x95, 0xb6, 0xa6, 0xfc, 0x09, 0x58, 0xe2, 0x31, 0x0a, 0xd9, - 0x43, 0x1c, 0xf7, 0xf3, 0x96, 0xf2, 0xf3, 0x5e, 0x49, 0x38, 0xb2, 0xe4, 0x77, 0xc1, 0x6a, 0xba, - 0x51, 0x62, 0xec, 0x11, 0xc6, 0x63, 0xd2, 0x68, 0xcb, 0x5d, 0x99, 0xec, 0x2b, 0xb3, 0x2c, 0x17, - 0xc1, 0x4a, 0x82, 0xb3, 0x33, 0xb0, 0xef, 0x69, 0x14, 0x3c, 0x00, 0xaf, 0xc9, 0x7d, 0xcc, 0x84, - 0x73, 0x4e, 0x86, 0x49, 0x9a, 0x0e, 0x08, 0x63, 0x82, 0x0d, 0xac, 0x1a, 0x6b, 0xe3, 0xf6, 0x75, - 0x85, 0x3d, 0xc4, 0xf1, 0x6e, 0x0f, 0xf2, 0x7e, 0x0f, 0x10, 0xae, 0x03, 0xd8, 0x24, 0x8c, 0xd3, - 0x98, 0xb8, 0xa8, 0xe5, 0xe0, 0x90, 0xc7, 0x04, 0x33, 0x73, 0x4a, 0xaa, 0xcf, 0x77, 0x25, 0x77, - 0x94, 0x00, 0xbe, 0x03, 0xae, 0x9f, 0x6a, 0xd4, 0x71, 0x9b, 0x28, 0x0c, 0x71, 0xcb, 0x9c, 0x96, - 0xa1, 0x54, 0xbd, 0x53, 0x6c, 0xee, 0x28, 0x18, 0x5c, 0x00, 0x13, 0x9c, 0x46, 0xce, 0x3d, 0xf3, - 0xf2, 0xaa, 0xb1, 0x76, 0xd9, 0x2e, 0x72, 0x1a, 0xdd, 0x83, 0x6f, 0x81, 0xc5, 0x0e, 0x6a, 0x11, - 0x0f, 0x71, 0x1a, 0x33, 0x27, 0xa2, 0xc7, 0x38, 0x76, 0x5c, 0x14, 0x99, 0x33, 0x12, 0x03, 0xbb, - 0xb2, 0x43, 0x21, 0xda, 0x41, 0x11, 0xbc, 0x01, 0xe6, 0xd3, 0x51, 0x87, 0x61, 0x2e, 0xe1, 0xb3, - 0x12, 0x3e, 0x9b, 0x0a, 0x8e, 0x30, 0x17, 0xd8, 0x6b, 0xa0, 0x8c, 0x5a, 0x2d, 0x7a, 0xdc, 0x22, - 0x8c, 0x9b, 0x73, 0xab, 0xe3, 0x6b, 0x65, 0xbb, 0x3b, 0x00, 0x2b, 0xa0, 0xe4, 0xe1, 0xf0, 0x44, - 0x0a, 0xe7, 0xa5, 0x30, 0x7d, 0xcf, 0x56, 0x1d, 0x98, 0xbf, 0xea, 0x5c, 0x05, 0xe5, 0x40, 0xd4, - 0x17, 0x8e, 0x1e, 0x61, 0x73, 0x61, 0xd5, 0x58, 0x2b, 0xda, 0xa5, 0x80, 0x84, 0x47, 0xe2, 0x1d, - 0x5a, 0x60, 0x41, 0x5a, 0x77, 0x48, 0x28, 0xe6, 0xb7, 0x83, 0x9d, 0x0e, 0x6a, 0x31, 0x73, 0x71, - 0xd5, 0x58, 0x2b, 0xd9, 0xf3, 0x52, 0xb4, 0xa7, 0x25, 0x0f, 0x50, 0x8b, 0x6d, 0xce, 0x65, 0xeb, - 0x8e, 0x69, 0xd4, 0xfe, 0x60, 0x00, 0xd8, 0x53, 0x5e, 0x6c, 0x1c, 0xd0, 0x0e, 0x6a, 0x9d, 0x55, - 0x5d, 0xb6, 0x40, 0x99, 0x89, 0xb4, 0xcb, 0xfd, 0x5c, 0xb8, 0xc0, 0x7e, 0x2e, 0x09, 0x35, 0xb9, - 0x9d, 0x33, 0xb9, 0x18, 0xcf, 0x9d, 0x8b, 0x21, 0xee, 0x47, 0x60, 0x7e, 0x9f, 0xf9, 0xd2, 0x6b, - 0x9c, 0xc4, 0xd0, 0xdf, 0x56, 0x8c, 0xfe, 0xb6, 0x02, 0x2d, 0x30, 0x41, 0x8f, 0xc5, 0x39, 0xa9, - 0x70, 0x8e, 0x6d, 0x05, 0xdb, 0x04, 0xc2, 0xae, 0x7a, 0xae, 0x5d, 0x05, 0xcb, 0x03, 0x16, 0xd3, - 0x62, 0xfd, 0x7b, 0x03, 0x5c, 0x11, 0xd9, 0x6c, 0xa2, 0xd0, 0xc7, 0x36, 0x3e, 0x46, 0xb1, 0xb7, - 0x8b, 0x43, 0x1a, 0x30, 0x58, 0x03, 0x97, 0x3d, 0xf9, 0xe4, 0x70, 0x2a, 0x0e, 0x7e, 0xa6, 0x21, - 0xd7, 0xc7, 0x94, 0x1a, 0xbc, 0x4f, 0xb7, 0x3c, 0x0f, 0xae, 0x81, 0xb9, 0x2e, 0x26, 0x96, 0x16, - 0xcc, 0x82, 0x84, 0xcd, 0x24, 0x30, 0x65, 0x77, 0xe4, 0x04, 0xf6, 0xf7, 0x9d, 0xaa, 0x3c, 0x9a, - 0x0c, 0xba, 0x9b, 0x06, 0xf4, 0x2f, 0x03, 0x94, 0xf6, 0x99, 0x7f, 0x10, 0xf1, 0xbd, 0xf0, 0xcb, - 0x70, 0xb4, 0x85, 0x60, 0x2e, 0x09, 0x37, 0xcd, 0xc1, 0x9f, 0x0c, 0x50, 0x56, 0x83, 0x07, 0x6d, - 0xfe, 0xb9, 0x25, 0xa1, 0x1b, 0xe1, 0xf8, 0x68, 0x11, 0x16, 0xf3, 0x45, 0xb8, 0x20, 0x77, 0x8c, - 0x0a, 0x26, 0x0d, 0xf1, 0x37, 0x05, 0x79, 0xa4, 0x17, 0x45, 0x4e, 0xab, 0xef, 0xd0, 0x40, 0x57, - 0x5b, 0x1b, 0x71, 0x3c, 0x18, 0x96, 0x91, 0x33, 0xac, 0xde, 0x74, 0x15, 0x06, 0xd3, 0x75, 0x07, - 0x14, 0x63, 0xc4, 0xb1, 0x8e, 0xf9, 0xa6, 0xa8, 0x15, 0x7f, 0x7d, 0x56, 0xbd, 0xaa, 0xe2, 0x66, - 0xde, 0x23, 0x8b, 0xd0, 0x7a, 0x80, 0x78, 0xd3, 0xfa, 0x21, 0xf6, 0x91, 0x7b, 0xb2, 0x8b, 0xdd, - 0x4f, 0x3f, 0x5e, 0x07, 0x3a, 0x2d, 0xbb, 0xd8, 0xb5, 0xa5, 0xfa, 0xff, 0x6d, 0x79, 0xbc, 0x0e, - 0x5e, 0x3b, 0x2b, 0x4d, 0x69, 0x3e, 0x9f, 0x8c, 0xcb, 0x03, 0x5d, 0x7a, 0x2f, 0xa0, 0x1e, 0x79, - 0x28, 0x8e, 0xd7, 0xa2, 0x61, 0x2e, 0x82, 0x09, 0x4e, 0x78, 0x0b, 0xeb, 0xba, 0xa4, 0x5e, 0xe0, - 0x2a, 0x98, 0xf2, 0x30, 0x73, 0x63, 0x12, 0xc9, 0x66, 0x5e, 0x50, 0x5b, 0xa0, 0x67, 0x28, 0x53, - 0x92, 0xc7, 0xb3, 0x25, 0x39, 0x6d, 0x84, 0xc5, 0x1c, 0x8d, 0x70, 0xe2, 0x62, 0x8d, 0x70, 0x32, - 0x47, 0x23, 0xbc, 0x74, 0x56, 0x23, 0x2c, 0x9d, 0xd5, 0x08, 0xcb, 0x23, 0x36, 0x42, 0x90, 0xaf, - 0x11, 0x4e, 0xe5, 0x6f, 0x84, 0xd7, 0x41, 0xf5, 0x94, 0x19, 0x4b, 0x67, 0xf5, 0x8f, 0x45, 0xb9, - 0x77, 0x76, 0x62, 0x8c, 0x78, 0xb7, 0xdb, 0x8c, 0x7a, 0x7b, 0x5b, 0xee, 0xdf, 0x19, 0xdd, 0xf9, - 0x7c, 0x0f, 0x94, 0x02, 0xcc, 0x91, 0x87, 0x38, 0xd2, 0x17, 0xad, 0xb7, 0x73, 0xdd, 0x35, 0x52, - 0xef, 0xb5, 0xb2, 0x3e, 0xd5, 0xa7, 0x64, 0xf0, 0x7d, 0x03, 0x2c, 0xeb, 0x23, 0x3e, 0xf9, 0x99, - 0x0c, 0xce, 0x91, 0x37, 0x12, 0xcc, 0x71, 0xcc, 0xe4, 0xea, 0x99, 0xda, 0xb8, 0x73, 0x21, 0x53, - 0x7b, 0x19, 0xb6, 0xc3, 0x94, 0xcc, 0x36, 0xc9, 0x29, 0x12, 0xd8, 0x06, 0xa6, 0x5a, 0x8d, 0xac, - 0x89, 0x22, 0x79, 0xa0, 0xef, 0xba, 0xa0, 0xee, 0x07, 0xdf, 0xce, 0x77, 0xb3, 0x12, 0x24, 0x47, - 0x8a, 0xa3, 0xc7, 0xf0, 0x2b, 0xd1, 0xd0, 0x71, 0xf8, 0x18, 0x2c, 0xa7, 0x0b, 0x14, 0x7b, 0x4e, - 0x2c, 0xdb, 0x9d, 0xa3, 0x1a, 0xab, 0xbe, 0x4c, 0xdc, 0xce, 0x65, 0x77, 0xab, 0xcb, 0x92, 0xe9, - 0x99, 0x4b, 0x68, 0xb8, 0x40, 0x77, 0xdd, 0xee, 0xed, 0xf5, 0xb6, 0x3c, 0x42, 0x64, 0x97, 0x51, - 0xb2, 0xc8, 0xce, 0x3d, 0xbc, 0xd4, 0xfe, 0xab, 0x56, 0xa1, 0xba, 0x2c, 0xa6, 0xab, 0x30, 0x3d, - 0xd2, 0x18, 0xb9, 0x8e, 0x34, 0xfd, 0x66, 0x0a, 0x03, 0x67, 0xa4, 0x5d, 0x30, 0x1f, 0xe2, 0x63, - 0x47, 0xa2, 0x1d, 0x5d, 0xdc, 0xcf, 0x6d, 0x4d, 0xb3, 0x21, 0x3e, 0x3e, 0x10, 0x1a, 0x7a, 0x18, - 0xbe, 0xdb, 0xb3, 0x92, 0x8b, 0x2f, 0xb1, 0x92, 0x73, 0xaf, 0xe1, 0x89, 0x2f, 0x7e, 0x0d, 0x4f, - 0x7e, 0x41, 0x6b, 0xf8, 0xd2, 0xe7, 0xb9, 0x86, 0x07, 0x8f, 0xc0, 0xd9, 0x05, 0x98, 0xac, 0xdf, - 0x8d, 0xa7, 0xd3, 0x60, 0x7c, 0x9f, 0xf9, 0xf0, 0x17, 0x06, 0x98, 0x1f, 0xfc, 0x3a, 0xfa, 0xad, - 0x5c, 0xde, 0x0d, 0xfb, 0xba, 0x58, 0xd9, 0x1a, 0x59, 0x35, 0xdd, 0x5b, 0xbf, 0x33, 0x40, 0xe5, - 0x8c, 0xaf, 0x92, 0xdb, 0x79, 0x2d, 0x9c, 0xce, 0x51, 0x79, 0xe7, 0xe5, 0x39, 0xce, 0x70, 0x37, - 0xf3, 0xd9, 0x70, 0x44, 0x77, 0x7b, 0x39, 0x46, 0x75, 0x77, 0xd8, 0xb7, 0x36, 0xf8, 0x81, 0x01, - 0x66, 0xfa, 0x7b, 0x63, 0x5e, 0xfa, 0xac, 0x5e, 0xe5, 0xbb, 0xa3, 0xe9, 0x65, 0x5c, 0xe9, 0x2b, - 0x90, 0xb9, 0x5d, 0xc9, 0xea, 0xe5, 0x77, 0x65, 0xf8, 0x7e, 0x90, 0xae, 0xf4, 0xdd, 0x4f, 0x73, - 0xbb, 0x92, 0xd5, 0xcb, 0xef, 0xca, 0xf0, 0xdb, 0xa9, 0xa8, 0x9c, 0xd3, 0x99, 0x2f, 0xa1, 0xdf, - 0xb8, 0x58, 0x6c, 0x4a, 0xab, 0x72, 0x7b, 0x14, 0xad, 0xd4, 0x89, 0x00, 0x4c, 0xa8, 0xdb, 0xe4, - 0x7a, 0x5e, 0x1a, 0x09, 0xaf, 0xbc, 0x7d, 0x21, 0x78, 0x6a, 0x2e, 0x02, 0x93, 0xfa, 0xe2, 0x66, - 0x5d, 0x80, 0xe0, 0xa0, 0xcd, 0x2b, 0xb7, 0x2e, 0x86, 0x4f, 0x2d, 0xfe, 0xd6, 0x00, 0xcb, 0xa7, - 0x5f, 0xa4, 0x72, 0x57, 0xb1, 0x53, 0x29, 0x2a, 0x7b, 0x2f, 0x4d, 0x91, 0xfa, 0xfa, 0x4b, 0x03, - 0xc0, 0x21, 0x1f, 0x2b, 0x36, 0x73, 0x6f, 0xbf, 0x01, 0xdd, 0xca, 0xf6, 0xe8, 0xba, 0x89, 0x5b, - 0x95, 0x89, 0x9f, 0x7f, 0xf6, 0xe4, 0x86, 0xb1, 0xfd, 0xde, 0xd3, 0xe7, 0x2b, 0xc6, 0x27, 0xcf, - 0x57, 0x8c, 0x7f, 0x3c, 0x5f, 0x31, 0x3e, 0x7c, 0xb1, 0x32, 0xf6, 0xc9, 0x8b, 0x95, 0xb1, 0xbf, - 0xbc, 0x58, 0x19, 0xfb, 0xf1, 0x77, 0x7c, 0xc2, 0x9b, 0xed, 0x86, 0xe5, 0xd2, 0x40, 0xff, 0xad, - 0x58, 0xef, 0x5a, 0x5d, 0x4f, 0xff, 0x15, 0xec, 0xdc, 0xaa, 0x3f, 0xce, 0xfe, 0x35, 0x28, 0xff, - 0x04, 0x69, 0x4c, 0xca, 0xef, 0x54, 0x5f, 0xff, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xea, 0xeb, - 0x11, 0x01, 0x96, 0x1d, 0x00, 0x00, + 0x33, 0x8e, 0x39, 0xa1, 0x3d, 0xed, 0x71, 0x91, 0x38, 0x70, 0x5c, 0x24, 0x38, 0x20, 0x81, 0x94, + 0xc3, 0x1e, 0xb9, 0x22, 0x45, 0xe2, 0xb2, 0xec, 0x09, 0x21, 0x14, 0x50, 0x72, 0x58, 0x2e, 0x5c, + 0xb8, 0x71, 0x43, 0xf5, 0xd3, 0x3d, 0xd3, 0x33, 0x63, 0xbb, 0x3d, 0xd1, 0xb2, 0x87, 0xbd, 0x58, + 0xd3, 0xf5, 0xbe, 0xf7, 0xbd, 0x9f, 0x7e, 0xf5, 0x5e, 0x55, 0x1b, 0xbc, 0x49, 0x42, 0x8e, 0x63, + 0xb7, 0x89, 0x48, 0xe8, 0x30, 0xec, 0xb6, 0x63, 0xc2, 0x4f, 0xea, 0xae, 0xdb, 0xa9, 0x47, 0x31, + 0xed, 0x10, 0x0f, 0xc7, 0xf5, 0xce, 0xcd, 0x3a, 0x7f, 0x6c, 0x45, 0x31, 0xe5, 0x14, 0x7e, 0x65, + 0x08, 0xda, 0x72, 0xdd, 0x8e, 0x95, 0xa0, 0xad, 0xce, 0xcd, 0xca, 0x3c, 0x0a, 0x48, 0x48, 0xeb, + 0xf2, 0xaf, 0xd2, 0xab, 0x5c, 0xf3, 0x29, 0xf5, 0x5b, 0xb8, 0x8e, 0x22, 0x52, 0x47, 0x61, 0x48, + 0x39, 0xe2, 0x84, 0x86, 0x4c, 0x4b, 0xab, 0x5a, 0x2a, 0x9f, 0x1a, 0xed, 0x87, 0x75, 0x4e, 0x02, + 0xcc, 0x38, 0x0a, 0x22, 0x0d, 0x58, 0xe9, 0x07, 0x78, 0xed, 0x58, 0x32, 0x68, 0xf9, 0x72, 0xbf, + 0x1c, 0x85, 0x27, 0x5a, 0xb4, 0xe8, 0x53, 0x9f, 0xca, 0x9f, 0x75, 0xf1, 0x2b, 0x51, 0x70, 0x29, + 0x0b, 0x28, 0x73, 0x94, 0x40, 0x3d, 0x68, 0xd1, 0x92, 0x7a, 0xaa, 0x07, 0xcc, 0x17, 0xa1, 0x07, + 0xcc, 0x4f, 0xbc, 0x24, 0x0d, 0xb7, 0xee, 0xd2, 0x18, 0xd7, 0xdd, 0x16, 0xc1, 0x21, 0x17, 0x52, + 0xf5, 0x4b, 0x03, 0x36, 0xf2, 0xa4, 0x32, 0x4d, 0x94, 0xd2, 0xa9, 0x0b, 0xd2, 0x16, 0xf1, 0x9b, + 0x5c, 0x51, 0xb1, 0x3a, 0xc7, 0xa1, 0x87, 0xe3, 0x80, 0x28, 0x03, 0xdd, 0xa7, 0xc4, 0x8b, 0x1e, + 0x39, 0x3f, 0x89, 0x30, 0xab, 0x63, 0xc1, 0x17, 0xba, 0x58, 0x01, 0x6a, 0xff, 0x35, 0xc0, 0xe2, + 0x3e, 0xf3, 0xb7, 0x18, 0x23, 0x7e, 0xb8, 0x43, 0x43, 0xd6, 0x0e, 0x70, 0xfc, 0x03, 0x7c, 0x02, + 0x5f, 0x05, 0x25, 0xe5, 0x1b, 0xf1, 0x4c, 0x63, 0xd5, 0x58, 0x2b, 0x6f, 0x17, 0x4c, 0xc3, 0xbe, + 0x24, 0xd7, 0xf6, 0x3c, 0xf8, 0x4d, 0x70, 0x39, 0xf1, 0xcd, 0x41, 0x9e, 0x17, 0x9b, 0x05, 0x89, + 0x81, 0xff, 0x79, 0x56, 0x9d, 0x39, 0x41, 0x41, 0x6b, 0xb3, 0x26, 0x56, 0x31, 0x63, 0x35, 0x7b, + 0x3a, 0x01, 0x6e, 0x79, 0x5e, 0x0c, 0xaf, 0x83, 0x69, 0x57, 0x9b, 0x71, 0x1e, 0xe1, 0x13, 0x73, + 0x5c, 0xe8, 0xd9, 0x53, 0x6e, 0x8f, 0xe9, 0xb7, 0xc0, 0xa4, 0xf0, 0x06, 0xc7, 0x66, 0x51, 0x92, + 0x9a, 0x9f, 0x7e, 0xbc, 0xbe, 0xa8, 0xb3, 0xbe, 0xa5, 0x58, 0x8f, 0x78, 0x4c, 0x42, 0xdf, 0xd6, + 0x38, 0x58, 0x05, 0x29, 0x81, 0xf0, 0x77, 0x42, 0x72, 0x82, 0x64, 0x69, 0xcf, 0xdb, 0x5c, 0xf8, + 0xe0, 0xa3, 0xea, 0xd8, 0xbf, 0x3e, 0xaa, 0x8e, 0xbd, 0xff, 0xd9, 0x93, 0x1b, 0x5a, 0xab, 0xb6, + 0x02, 0xae, 0x0d, 0x0b, 0xdd, 0xc6, 0x2c, 0xa2, 0x21, 0xc3, 0xb5, 0xe7, 0x06, 0x78, 0x75, 0x9f, + 0xf9, 0x47, 0xed, 0x46, 0x40, 0x78, 0x02, 0xd8, 0x27, 0xac, 0x81, 0x9b, 0xa8, 0x43, 0x68, 0x3b, + 0x86, 0xb7, 0x40, 0x99, 0x49, 0x29, 0xc7, 0xb1, 0xce, 0xd2, 0xe9, 0xce, 0x76, 0xa1, 0xf0, 0x10, + 0x4c, 0x07, 0x3d, 0x3c, 0x32, 0x79, 0x53, 0x1b, 0x6f, 0x5a, 0xa4, 0xe1, 0x5a, 0xbd, 0xaf, 0xd7, + 0xea, 0x79, 0xa1, 0x9d, 0x9b, 0x56, 0xaf, 0x6d, 0x3b, 0xc3, 0xd0, 0x9f, 0x81, 0xf1, 0x81, 0x0c, + 0xbc, 0xd2, 0x9b, 0x81, 0xae, 0x2b, 0xb5, 0x37, 0xc0, 0x57, 0xcf, 0x8c, 0x31, 0xcd, 0xc6, 0x5f, + 0x0a, 0x43, 0xb2, 0xb1, 0x4b, 0xdb, 0x8d, 0x16, 0x7e, 0x40, 0x39, 0x09, 0xfd, 0x91, 0xb3, 0xe1, + 0x80, 0x25, 0xaf, 0x1d, 0xb5, 0x88, 0x8b, 0x38, 0x76, 0x3a, 0x94, 0x63, 0x27, 0x29, 0x52, 0x9d, + 0x98, 0x37, 0x7a, 0xf3, 0x20, 0xcb, 0xd8, 0xda, 0x4d, 0x14, 0x1e, 0x50, 0x8e, 0xef, 0x68, 0xb8, + 0x7d, 0xc5, 0x1b, 0xb6, 0x0c, 0x7f, 0x0a, 0x96, 0x48, 0xf8, 0x30, 0x46, 0xae, 0x68, 0x02, 0x4e, + 0xa3, 0x45, 0xdd, 0x47, 0x4e, 0x13, 0x23, 0x0f, 0xc7, 0x32, 0x51, 0x53, 0x1b, 0xaf, 0x9f, 0x97, + 0xf9, 0xbb, 0x12, 0x6d, 0x5f, 0xe9, 0xd2, 0x6c, 0x0b, 0x16, 0xb5, 0xdc, 0x9f, 0xfc, 0xe2, 0x4b, + 0x25, 0xbf, 0x37, 0xa5, 0x69, 0xf2, 0x7f, 0x63, 0x80, 0xd9, 0x7d, 0xe6, 0xff, 0x28, 0xf2, 0x10, + 0xc7, 0x87, 0x28, 0x46, 0x01, 0x13, 0xe9, 0x46, 0x6d, 0xde, 0xa4, 0xa2, 0x71, 0x9c, 0x9f, 0xee, + 0x14, 0x0a, 0xf7, 0xc0, 0x64, 0x24, 0x19, 0x74, 0x76, 0xbf, 0x66, 0xe5, 0x68, 0xd3, 0x96, 0x32, + 0xba, 0x5d, 0x7c, 0xfa, 0xac, 0x3a, 0x66, 0x6b, 0x82, 0xcd, 0x19, 0x19, 0x4f, 0x4a, 0x5d, 0x5b, + 0x06, 0x4b, 0x7d, 0x5e, 0xa6, 0x11, 0xfc, 0xbd, 0x04, 0x16, 0xf6, 0x99, 0x9f, 0x44, 0xb9, 0xe5, + 0x79, 0x44, 0xa4, 0x11, 0x2e, 0xf7, 0xf7, 0x99, 0x6e, 0x8f, 0xf9, 0x3e, 0x98, 0x21, 0x21, 0xe1, + 0x04, 0xb5, 0x9c, 0x26, 0x16, 0xef, 0x46, 0x3b, 0x5c, 0x91, 0x6f, 0x4b, 0xf4, 0x56, 0x4b, 0x77, + 0x54, 0xf9, 0x86, 0x04, 0x42, 0xfb, 0x77, 0x59, 0xeb, 0xa9, 0x45, 0xd1, 0x73, 0x7c, 0x1c, 0x62, + 0x46, 0x98, 0xd3, 0x44, 0xac, 0x29, 0x5f, 0xfa, 0xb4, 0x3d, 0xa5, 0xd7, 0xee, 0x22, 0xd6, 0x14, + 0xaf, 0xb0, 0x41, 0x42, 0x14, 0x9f, 0x28, 0x44, 0x51, 0x22, 0x80, 0x5a, 0x92, 0x80, 0x1d, 0x00, + 0x58, 0x84, 0x8e, 0x43, 0x47, 0x4c, 0x1b, 0xd9, 0x61, 0x84, 0x23, 0x6a, 0x92, 0x58, 0xc9, 0x24, + 0xb1, 0xee, 0x27, 0xa3, 0x68, 0xbb, 0x24, 0x1c, 0xf9, 0xf0, 0x1f, 0x55, 0xc3, 0x2e, 0x4b, 0x3d, + 0x21, 0x81, 0xf7, 0xc0, 0x5c, 0x3b, 0x6c, 0xd0, 0xd0, 0x23, 0xa1, 0xef, 0x44, 0x38, 0x26, 0xd4, + 0x33, 0x27, 0x25, 0xd5, 0xf2, 0x00, 0xd5, 0xae, 0x1e, 0x5a, 0x8a, 0xe9, 0x57, 0x82, 0x69, 0x36, + 0x55, 0x3e, 0x94, 0xba, 0xf0, 0x5d, 0x00, 0x5d, 0xb7, 0x23, 0x5d, 0xa2, 0x6d, 0x9e, 0x30, 0x5e, + 0xca, 0xcf, 0x38, 0xe7, 0xba, 0x9d, 0xfb, 0x4a, 0x5b, 0x53, 0xfe, 0x04, 0x2c, 0xf1, 0x18, 0x85, + 0xec, 0x21, 0x8e, 0xfb, 0x79, 0x4b, 0xf9, 0x79, 0xaf, 0x24, 0x1c, 0x59, 0xf2, 0xbb, 0x60, 0x35, + 0xdd, 0x28, 0x31, 0xf6, 0x08, 0xe3, 0x31, 0x69, 0xb4, 0xe5, 0xae, 0x4c, 0xf6, 0x95, 0x59, 0x96, + 0x45, 0xb0, 0x92, 0xe0, 0xec, 0x0c, 0xec, 0x7b, 0x1a, 0x05, 0x0f, 0xc0, 0x6b, 0x72, 0x1f, 0x33, + 0xe1, 0x9c, 0x93, 0x61, 0x92, 0xa6, 0x03, 0xc2, 0x98, 0x60, 0x03, 0xab, 0xc6, 0xda, 0xb8, 0x7d, + 0x5d, 0x61, 0x0f, 0x71, 0xbc, 0xdb, 0x83, 0xbc, 0xdf, 0x03, 0x84, 0xeb, 0x00, 0x36, 0x09, 0xe3, + 0x34, 0x26, 0x2e, 0x6a, 0x39, 0x38, 0xe4, 0x31, 0xc1, 0xcc, 0x9c, 0x92, 0xea, 0xf3, 0x5d, 0xc9, + 0x1d, 0x25, 0x80, 0xef, 0x80, 0xeb, 0xa7, 0x1a, 0x75, 0xdc, 0x26, 0x0a, 0x43, 0xdc, 0x32, 0xa7, + 0x65, 0x28, 0x55, 0xef, 0x14, 0x9b, 0x3b, 0x0a, 0x06, 0x17, 0xc0, 0x04, 0xa7, 0x91, 0x73, 0xcf, + 0xbc, 0xbc, 0x6a, 0xac, 0x5d, 0xb6, 0x8b, 0x9c, 0x46, 0xf7, 0xe0, 0x5b, 0x60, 0xb1, 0x83, 0x5a, + 0xc4, 0x43, 0x9c, 0xc6, 0xcc, 0x89, 0xe8, 0x31, 0x8e, 0x1d, 0x17, 0x45, 0xe6, 0x8c, 0xc4, 0xc0, + 0xae, 0xec, 0x50, 0x88, 0x76, 0x50, 0x04, 0x6f, 0x80, 0xf9, 0x74, 0xd5, 0x61, 0x98, 0x4b, 0xf8, + 0xac, 0x84, 0xcf, 0xa6, 0x82, 0x23, 0xcc, 0x05, 0xf6, 0x1a, 0x28, 0xa3, 0x56, 0x8b, 0x1e, 0xb7, + 0x08, 0xe3, 0xe6, 0xdc, 0xea, 0xf8, 0x5a, 0xd9, 0xee, 0x2e, 0xc0, 0x0a, 0x28, 0x79, 0x38, 0x3c, + 0x91, 0xc2, 0x79, 0x29, 0x4c, 0x9f, 0xb3, 0x5d, 0x07, 0xe6, 0xef, 0x3a, 0x57, 0x41, 0x39, 0x10, + 0xfd, 0x85, 0xa3, 0x47, 0xd8, 0x5c, 0x58, 0x35, 0xd6, 0x8a, 0x76, 0x29, 0x20, 0xe1, 0x91, 0x78, + 0x86, 0x16, 0x58, 0x90, 0xd6, 0x1d, 0x12, 0x8a, 0xf7, 0xdb, 0xc1, 0x4e, 0x07, 0xb5, 0x98, 0xb9, + 0xb8, 0x6a, 0xac, 0x95, 0xec, 0x79, 0x29, 0xda, 0xd3, 0x92, 0x07, 0xa8, 0xc5, 0x36, 0xe7, 0xb2, + 0x7d, 0xc7, 0x34, 0x6a, 0x7f, 0x34, 0x00, 0xec, 0x69, 0x2f, 0x36, 0x0e, 0x68, 0x07, 0xb5, 0xce, + 0xea, 0x2e, 0x5b, 0xa0, 0xcc, 0x44, 0xda, 0xe5, 0x7e, 0x2e, 0x5c, 0x60, 0x3f, 0x97, 0x84, 0x9a, + 0xdc, 0xce, 0x99, 0x5c, 0x8c, 0xe7, 0xce, 0xc5, 0x10, 0xf7, 0x23, 0x30, 0xbf, 0xcf, 0x7c, 0xe9, + 0x35, 0x4e, 0x62, 0xe8, 0x1f, 0x2b, 0x46, 0xff, 0x58, 0x81, 0x16, 0x98, 0xa0, 0xc7, 0xe2, 0x9c, + 0x54, 0x38, 0xc7, 0xb6, 0x82, 0x6d, 0x02, 0x61, 0x57, 0xfd, 0xae, 0x5d, 0x05, 0xcb, 0x03, 0x16, + 0xd3, 0x66, 0xfd, 0x07, 0x03, 0x5c, 0x11, 0xd9, 0x6c, 0xa2, 0xd0, 0xc7, 0x36, 0x3e, 0x46, 0xb1, + 0xb7, 0x8b, 0x43, 0x1a, 0x30, 0x58, 0x03, 0x97, 0x3d, 0xf9, 0xcb, 0xe1, 0x54, 0x1c, 0xfc, 0x4c, + 0x43, 0xd6, 0xc7, 0x94, 0x5a, 0xbc, 0x4f, 0xb7, 0x3c, 0x0f, 0xae, 0x81, 0xb9, 0x2e, 0x26, 0x96, + 0x16, 0xcc, 0x82, 0x84, 0xcd, 0x24, 0x30, 0x65, 0x77, 0xe4, 0x04, 0xf6, 0xcf, 0x9d, 0xaa, 0x3c, + 0x9a, 0x0c, 0xba, 0x9b, 0x06, 0xf4, 0x6f, 0x03, 0x94, 0xf6, 0x99, 0x7f, 0x10, 0xf1, 0xbd, 0xf0, + 0xcb, 0x70, 0xb4, 0x85, 0x60, 0x2e, 0x09, 0x37, 0xcd, 0xc1, 0x9f, 0x0d, 0x50, 0x56, 0x8b, 0x07, + 0x6d, 0xfe, 0xb9, 0x25, 0xa1, 0x1b, 0xe1, 0xf8, 0x68, 0x11, 0x16, 0xf3, 0x45, 0xb8, 0x20, 0x77, + 0x8c, 0x0a, 0x26, 0x0d, 0xf1, 0xb7, 0x05, 0x79, 0xa4, 0x17, 0x4d, 0x4e, 0xab, 0xef, 0xd0, 0x40, + 0x77, 0x5b, 0x1b, 0x71, 0x3c, 0x18, 0x96, 0x91, 0x33, 0xac, 0xde, 0x74, 0x15, 0x06, 0xd3, 0x75, + 0x07, 0x14, 0x63, 0xc4, 0xb1, 0x8e, 0xf9, 0xa6, 0xe8, 0x15, 0x7f, 0x7b, 0x56, 0xbd, 0xaa, 0xe2, + 0x66, 0xde, 0x23, 0x8b, 0xd0, 0x7a, 0x80, 0x78, 0xd3, 0xfa, 0x21, 0xf6, 0x91, 0x7b, 0xb2, 0x8b, + 0xdd, 0x4f, 0x3f, 0x5e, 0x07, 0x3a, 0x2d, 0xbb, 0xd8, 0xb5, 0xa5, 0xfa, 0xff, 0xad, 0x3c, 0x5e, + 0x07, 0xaf, 0x9d, 0x95, 0xa6, 0x34, 0x9f, 0x4f, 0xc6, 0xe5, 0x81, 0x2e, 0xbd, 0x17, 0x50, 0x8f, + 0x3c, 0x14, 0xc7, 0x6b, 0x31, 0x30, 0x17, 0xc1, 0x04, 0x27, 0xbc, 0x85, 0x75, 0x5f, 0x52, 0x0f, + 0x70, 0x15, 0x4c, 0x79, 0x98, 0xb9, 0x31, 0x89, 0xe4, 0x30, 0x2f, 0xa8, 0x2d, 0xd0, 0xb3, 0x94, + 0x69, 0xc9, 0xe3, 0xd9, 0x96, 0x9c, 0x0e, 0xc2, 0x62, 0x8e, 0x41, 0x38, 0x71, 0xb1, 0x41, 0x38, + 0x99, 0x63, 0x10, 0x5e, 0x3a, 0x6b, 0x10, 0x96, 0xce, 0x1a, 0x84, 0xe5, 0x11, 0x07, 0x21, 0xc8, + 0x37, 0x08, 0xa7, 0xf2, 0x0f, 0xc2, 0xeb, 0xa0, 0x7a, 0xca, 0x1b, 0x4b, 0xdf, 0xea, 0x9f, 0x8a, + 0x72, 0xef, 0xec, 0xc4, 0x18, 0xf1, 0xee, 0xb4, 0x19, 0xf5, 0xf6, 0xb6, 0xdc, 0xbf, 0x33, 0xba, + 0xef, 0xf3, 0x3d, 0x50, 0x0a, 0x30, 0x47, 0x1e, 0xe2, 0x48, 0x5f, 0xb4, 0xde, 0xce, 0x75, 0xd7, + 0x48, 0xbd, 0xd7, 0xca, 0xfa, 0x54, 0x9f, 0x92, 0xc1, 0xf7, 0x0d, 0xb0, 0xac, 0x8f, 0xf8, 0xe4, + 0x67, 0x32, 0x38, 0x47, 0xde, 0x48, 0x30, 0xc7, 0x31, 0x93, 0xd5, 0x33, 0xb5, 0x71, 0xe7, 0x42, + 0xa6, 0xf6, 0x32, 0x6c, 0x87, 0x29, 0x99, 0x6d, 0x92, 0x53, 0x24, 0xb0, 0x0d, 0x4c, 0x55, 0x8d, + 0xac, 0x89, 0x22, 0x79, 0xa0, 0xef, 0xba, 0xa0, 0xee, 0x07, 0xdf, 0xce, 0x77, 0xb3, 0x12, 0x24, + 0x47, 0x8a, 0xa3, 0xc7, 0xf0, 0x2b, 0xd1, 0xd0, 0x75, 0xf8, 0x18, 0x2c, 0xa7, 0x05, 0x8a, 0x3d, + 0x27, 0x96, 0xe3, 0xce, 0x51, 0x83, 0x55, 0x5f, 0x26, 0x6e, 0xe7, 0xb2, 0xbb, 0xd5, 0x65, 0xc9, + 0xcc, 0xcc, 0x25, 0x34, 0x5c, 0xa0, 0xa7, 0x6e, 0xf7, 0xf6, 0x7a, 0x5b, 0x1e, 0x21, 0xb2, 0x65, + 0x94, 0x14, 0xd9, 0xb9, 0x87, 0x97, 0xda, 0xaf, 0x27, 0x64, 0x15, 0xaa, 0xcb, 0x62, 0x5a, 0x85, + 0xe9, 0x91, 0xc6, 0xc8, 0x75, 0xa4, 0xe9, 0x37, 0x53, 0x18, 0x38, 0x23, 0xed, 0x82, 0xf9, 0x10, + 0x1f, 0x3b, 0x12, 0xed, 0xe8, 0xe6, 0x7e, 0xee, 0x68, 0x9a, 0x0d, 0xf1, 0xf1, 0x81, 0xd0, 0xd0, + 0xcb, 0xf0, 0xdd, 0x9e, 0x4a, 0x2e, 0xbe, 0x44, 0x25, 0xe7, 0xae, 0xe1, 0x89, 0x2f, 0xbe, 0x86, + 0x27, 0xbf, 0xa0, 0x1a, 0xbe, 0xf4, 0x39, 0xd6, 0x30, 0x5c, 0x05, 0xd3, 0xa2, 0x1c, 0xd2, 0x8e, + 0x55, 0x52, 0x05, 0x13, 0xe2, 0xe3, 0x1d, 0xd5, 0xb4, 0x86, 0x1c, 0x92, 0xb3, 0x25, 0x9a, 0x54, + 0xf8, 0xc6, 0xd3, 0x69, 0x30, 0xbe, 0xcf, 0x7c, 0xf8, 0x0b, 0x03, 0xcc, 0x0f, 0x7e, 0x3f, 0xfd, + 0x56, 0x2e, 0xff, 0x87, 0x7d, 0x7f, 0xac, 0x6c, 0x8d, 0xac, 0x9a, 0xee, 0xbe, 0xdf, 0x1b, 0xa0, + 0x72, 0xc6, 0x77, 0xcb, 0xed, 0xbc, 0x16, 0x4e, 0xe7, 0xa8, 0xbc, 0xf3, 0xf2, 0x1c, 0x67, 0xb8, + 0x9b, 0xf9, 0xb0, 0x38, 0xa2, 0xbb, 0xbd, 0x1c, 0xa3, 0xba, 0x3b, 0xec, 0x6b, 0x1c, 0xfc, 0xc0, + 0x00, 0x33, 0xfd, 0xd3, 0x33, 0x2f, 0x7d, 0x56, 0xaf, 0xf2, 0xdd, 0xd1, 0xf4, 0x32, 0xae, 0xf4, + 0xb5, 0xd0, 0xdc, 0xae, 0x64, 0xf5, 0xf2, 0xbb, 0x32, 0x7c, 0x3f, 0x48, 0x57, 0xfa, 0x6e, 0xb0, + 0xb9, 0x5d, 0xc9, 0xea, 0xe5, 0x77, 0x65, 0xf8, 0xfd, 0x55, 0xf4, 0xd6, 0xe9, 0xcc, 0xb7, 0xd2, + 0x6f, 0x5c, 0x2c, 0x36, 0xa5, 0x55, 0xb9, 0x3d, 0x8a, 0x56, 0xea, 0x44, 0x00, 0x26, 0xd4, 0x7d, + 0x73, 0x3d, 0x2f, 0x8d, 0x84, 0x57, 0xde, 0xbe, 0x10, 0x3c, 0x35, 0x17, 0x81, 0x49, 0x7d, 0xb5, + 0xb3, 0x2e, 0x40, 0x70, 0xd0, 0xe6, 0x95, 0x5b, 0x17, 0xc3, 0xa7, 0x16, 0x7f, 0x67, 0x80, 0xe5, + 0xd3, 0xaf, 0x5a, 0xb9, 0xbb, 0xd8, 0xa9, 0x14, 0x95, 0xbd, 0x97, 0xa6, 0x48, 0x7d, 0xfd, 0xa5, + 0x01, 0xe0, 0x90, 0xcf, 0x19, 0x9b, 0xb9, 0xb7, 0xdf, 0x80, 0x6e, 0x65, 0x7b, 0x74, 0xdd, 0xc4, + 0xad, 0xca, 0xc4, 0xcf, 0x3f, 0x7b, 0x72, 0xc3, 0xd8, 0x7e, 0xef, 0xe9, 0xf3, 0x15, 0xe3, 0x93, + 0xe7, 0x2b, 0xc6, 0x3f, 0x9f, 0xaf, 0x18, 0x1f, 0xbe, 0x58, 0x19, 0xfb, 0xe4, 0xc5, 0xca, 0xd8, + 0x5f, 0x5f, 0xac, 0x8c, 0xfd, 0xf8, 0x3b, 0x3e, 0xe1, 0xcd, 0x76, 0xc3, 0x72, 0x69, 0xa0, 0xff, + 0xf1, 0x58, 0xef, 0x5a, 0x5d, 0x4f, 0xff, 0x6f, 0xd8, 0xb9, 0x55, 0x7f, 0x9c, 0xfd, 0xe7, 0xa1, + 0xfc, 0x37, 0x49, 0x63, 0x52, 0x7e, 0xc9, 0xfa, 0xfa, 0xff, 0x02, 0x00, 0x00, 0xff, 0xff, 0x84, + 0xa1, 0x79, 0x6d, 0xb8, 0x1d, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -3347,6 +3359,13 @@ func (m *MsgUpdateConsumer) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.NewChainId) > 0 { + i -= len(m.NewChainId) + copy(dAtA[i:], m.NewChainId) + i = encodeVarintTx(dAtA, i, uint64(len(m.NewChainId))) + i-- + dAtA[i] = 0x42 + } if m.AllowlistedRewardDenoms != nil { { size, err := m.AllowlistedRewardDenoms.MarshalToSizedBuffer(dAtA[:i]) @@ -3981,6 +4000,10 @@ func (m *MsgUpdateConsumer) Size() (n int) { l = m.AllowlistedRewardDenoms.Size() n += 1 + l + sovTx(uint64(l)) } + l = len(m.NewChainId) + if l > 0 { + n += 1 + l + sovTx(uint64(l)) + } return n } @@ -7720,6 +7743,38 @@ func (m *MsgUpdateConsumer) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field NewChainId", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowTx + } + if iNdEx >= l { + return io.ErrUnexpectedEOF + } + b := dAtA[iNdEx] + iNdEx++ + stringLen |= uint64(b&0x7F) << shift + if b < 0x80 { + break + } + } + intStringLen := int(stringLen) + if intStringLen < 0 { + return ErrInvalidLengthTx + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthTx + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.NewChainId = string(dAtA[iNdEx:postIndex]) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipTx(dAtA[iNdEx:]) From 75e90778ce073f3a1eee08d7a88438451dfc8492 Mon Sep 17 00:00:00 2001 From: insumity Date: Tue, 29 Oct 2024 12:27:10 +0100 Subject: [PATCH 2/5] add CHANGELOG files --- .changelog/unreleased/features/2378-allow-chain-id-updates.md | 2 ++ .../unreleased/state-breaking/2378-allow-chain-id-updates.md | 2 ++ 2 files changed, 4 insertions(+) create mode 100644 .changelog/unreleased/features/2378-allow-chain-id-updates.md create mode 100644 .changelog/unreleased/state-breaking/2378-allow-chain-id-updates.md diff --git a/.changelog/unreleased/features/2378-allow-chain-id-updates.md b/.changelog/unreleased/features/2378-allow-chain-id-updates.md new file mode 100644 index 0000000000..cab2fdc62b --- /dev/null +++ b/.changelog/unreleased/features/2378-allow-chain-id-updates.md @@ -0,0 +1,2 @@ +- Allow the chain id of a consumer chain to be updated before the chain + launches. ([\#2378](https://github.com/cosmos/interchain-security/pull/2378)) \ No newline at end of file diff --git a/.changelog/unreleased/state-breaking/2378-allow-chain-id-updates.md b/.changelog/unreleased/state-breaking/2378-allow-chain-id-updates.md new file mode 100644 index 0000000000..cab2fdc62b --- /dev/null +++ b/.changelog/unreleased/state-breaking/2378-allow-chain-id-updates.md @@ -0,0 +1,2 @@ +- Allow the chain id of a consumer chain to be updated before the chain + launches. ([\#2378](https://github.com/cosmos/interchain-security/pull/2378)) \ No newline at end of file From 506bb3ca4e29ab69ff795e00a9f5a595efd01342 Mon Sep 17 00:00:00 2001 From: insumity Date: Tue, 5 Nov 2024 13:10:16 +0100 Subject: [PATCH 3/5] took into account comments --- x/ccv/provider/keeper/msg_server.go | 11 ++++-- x/ccv/provider/keeper/msg_server_test.go | 11 ++++++ x/ccv/provider/types/msg.go | 40 +++++++++++++------ x/ccv/provider/types/msg_test.go | 50 +++++++++++++++++++++++- 4 files changed, 96 insertions(+), 16 deletions(-) diff --git a/x/ccv/provider/keeper/msg_server.go b/x/ccv/provider/keeper/msg_server.go index 0fccc43575..d55a8a1201 100644 --- a/x/ccv/provider/keeper/msg_server.go +++ b/x/ccv/provider/keeper/msg_server.go @@ -474,7 +474,13 @@ func (k msgServer) UpdateConsumer(goCtx context.Context, msg *types.MsgUpdateCon return &resp, errorsmod.Wrapf(ccvtypes.ErrInvalidConsumerState, "cannot get consumer chain ID: %s", err.Error()) } + // We only validate and use `NewChainId` if it is not empty (because `NewChainId` is an optional argument) + // or `NewChainId` is different from the current chain id of the consumer chain. if strings.TrimSpace(msg.NewChainId) != "" && msg.NewChainId != chainId { + if err = types.ValidateChainId("NewChainId", msg.NewChainId); err != nil { + return &resp, errorsmod.Wrapf(types.ErrInvalidMsgUpdateConsumer, "invalid new chain id: %s", err.Error()) + } + if k.IsConsumerPrelaunched(ctx, consumerId) { chainId = msg.NewChainId k.SetConsumerChainId(ctx, consumerId, chainId) @@ -521,14 +527,13 @@ func (k msgServer) UpdateConsumer(goCtx context.Context, msg *types.MsgUpdateCon previousSpawnTime := previousInitializationParameters.SpawnTime if msg.InitializationParameters != nil { - phase := k.GetConsumerPhase(ctx, consumerId) - - if phase == types.CONSUMER_PHASE_LAUNCHED { + if !k.IsConsumerPrelaunched(ctx, consumerId) { return &resp, errorsmod.Wrap(types.ErrInvalidMsgUpdateConsumer, "cannot update the initialization parameters of an an already launched chain; "+ "do not provide any initialization parameters when updating a launched chain") } + phase := k.GetConsumerPhase(ctx, consumerId) if msg.InitializationParameters.SpawnTime.IsZero() { if phase == types.CONSUMER_PHASE_INITIALIZED { // chain was previously ready to launch at `previousSpawnTime` so we remove the diff --git a/x/ccv/provider/keeper/msg_server_test.go b/x/ccv/provider/keeper/msg_server_test.go index 6fe265eeea..9e60ab484f 100644 --- a/x/ccv/provider/keeper/msg_server_test.go +++ b/x/ccv/provider/keeper/msg_server_test.go @@ -122,6 +122,17 @@ func TestUpdateConsumer(t *testing.T) { require.NoError(t, err) require.Equal(t, expectedChainId, chainId) + // assert that we cannot change the chain to that of a reserved chain id + _, err = msgServer.UpdateConsumer(ctx, + &providertypes.MsgUpdateConsumer{ + Owner: "submitter", ConsumerId: consumerId, + Metadata: nil, + InitializationParameters: nil, + PowerShapingParameters: nil, + NewChainId: "stride-1", // reversed chain id + }) + require.ErrorContains(t, err, "cannot use a reserved chain id") + expectedConsumerMetadata := providertypes.ConsumerMetadata{ Name: "name2", Description: "description2", diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index 0128cc9f5f..e5f36d2bc6 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -295,20 +295,35 @@ func NewMsgCreateConsumer(submitter, chainId string, metadata ConsumerMetadata, }, nil } -// ValidateBasic implements the sdk.HasValidateBasic interface. -func (msg MsgCreateConsumer) ValidateBasic() error { - if err := ValidateStringField("ChainId", msg.ChainId, cmttypes.MaxChainIDLen); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgCreateConsumer, "ChainId: %s", err.Error()) - } - +// IsReservedChainId returns true if the specific chain id is reserved and cannot be used by other consumer chains +func IsReservedChainId(chainId string) bool { // With permissionless ICS, we can have multiple consumer chains with the exact same chain id. // However, as we already have the Neutron and Stride Top N chains running, as a first step we would like to // prevent permissionless chains from re-using the chain ids of Neutron and Stride. Note that this is just a // preliminary measure that will be removed later on as part of: // TODO (#2242): find a better way of ignoring past misbehaviors - if msg.ChainId == "neutron-1" || msg.ChainId == "stride-1" { - return errorsmod.Wrapf(ErrInvalidMsgCreateConsumer, - "cannot reuse chain ids of existing Neutron and Stride Top N consumer chains") + return chainId == "neutron-1" || chainId == "stride-1" +} + +// ValidateChainId validates that the chain id is valid and is not reserved. +// Can be called for the `MsgUpdateConsumer.NewChainId` field as well, so this method takes the `field` as an argument +// to return more appropriate error messages in case the validation fails. +func ValidateChainId(field string, chainId string) error { + if err := ValidateStringField(field, chainId, cmttypes.MaxChainIDLen); err != nil { + return errorsmod.Wrapf(ErrInvalidMsgCreateConsumer, "%s: %s", field, err.Error()) + } + + if IsReservedChainId(chainId) { + return errorsmod.Wrapf(ErrInvalidMsgCreateConsumer, "cannot use a reserved chain id") + } + + return nil +} + +// ValidateBasic implements the sdk.HasValidateBasic interface. +func (msg MsgCreateConsumer) ValidateBasic() error { + if err := ValidateChainId("ChainId", msg.ChainId); err != nil { + return errorsmod.Wrapf(ErrInvalidMsgCreateConsumer, "ChainId: %s", err.Error()) } if err := ValidateConsumerMetadata(msg.Metadata); err != nil { @@ -389,9 +404,10 @@ 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) + if strings.TrimSpace(msg.NewChainId) != "" { + if err := ValidateStringField("NewChainId", msg.NewChainId, cmttypes.MaxChainIDLen); err != nil { + return errorsmod.Wrapf(ErrInvalidMsgUpdateConsumer, "NewChainId: %s", err.Error()) + } } return nil diff --git a/x/ccv/provider/types/msg_test.go b/x/ccv/provider/types/msg_test.go index 87ee0bb0fd..2a0adc70a1 100644 --- a/x/ccv/provider/types/msg_test.go +++ b/x/ccv/provider/types/msg_test.go @@ -1,6 +1,7 @@ package types_test import ( + "strings" "testing" "time" @@ -554,7 +555,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) { { "too long new chain id", types.PowerShapingParameters{}, - "this is an extremely long chain id that is so long that the validation would fail", + strings.Repeat("thisIsAnExtremelyLongChainId", 2), false, }, } @@ -725,3 +726,50 @@ func TestValidateInitialHeight(t *testing.T) { } } } + +func TestValidateChainId(t *testing.T) { + testCases := []struct { + name string + chainId string + expPass bool + }{ + { + name: "valid chain id", + chainId: "chain-1", + expPass: true, + }, + { + name: "valid chain id with no revision", + chainId: "chainId", + expPass: true, + }, + { + name: "invalid (too long) chain id", + chainId: strings.Repeat("thisIsAnExtremelyLongChainId", 2), + expPass: false, + }, + { + name: "reserved chain id", + chainId: "stride-1", + expPass: false, + }, + { + name: "reserved chain id", + chainId: "neutron-1", + expPass: false, + }, + { + name: "empty chain id", + chainId: " ", + expPass: false, + }, + } + for _, tc := range testCases { + err := types.ValidateChainId("ChainId", tc.chainId) + if tc.expPass { + require.NoError(t, err, "valid case: '%s' should not return error. got %w", tc.name, err) + } else { + require.Error(t, err, "invalid case: '%s' must return error but got none", tc.name) + } + } +} From 44969efe4aee4a0c73f1e7ab586761ff3ceba339 Mon Sep 17 00:00:00 2001 From: insumity Date: Tue, 5 Nov 2024 13:25:16 +0100 Subject: [PATCH 4/5] removed unecessary check --- x/ccv/provider/types/msg.go | 6 ------ x/ccv/provider/types/msg_test.go | 6 ------ 2 files changed, 12 deletions(-) diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index e5f36d2bc6..bfc433126a 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -404,12 +404,6 @@ func (msg MsgUpdateConsumer) ValidateBasic() error { } } - if strings.TrimSpace(msg.NewChainId) != "" { - if err := ValidateStringField("NewChainId", msg.NewChainId, cmttypes.MaxChainIDLen); err != nil { - return errorsmod.Wrapf(ErrInvalidMsgUpdateConsumer, "NewChainId: %s", err.Error()) - } - } - return nil } diff --git a/x/ccv/provider/types/msg_test.go b/x/ccv/provider/types/msg_test.go index 2a0adc70a1..1c826d350d 100644 --- a/x/ccv/provider/types/msg_test.go +++ b/x/ccv/provider/types/msg_test.go @@ -552,12 +552,6 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) { "validchainid-0", true, }, - { - "too long new chain id", - types.PowerShapingParameters{}, - strings.Repeat("thisIsAnExtremelyLongChainId", 2), - false, - }, } for _, tc := range testCases { From 882ae229850aa6791bac8952b4c0fa1dd00f346c Mon Sep 17 00:00:00 2001 From: insumity Date: Tue, 5 Nov 2024 16:11:15 +0100 Subject: [PATCH 5/5] add a small comment in the CLI of UpdateConsumer that NewChainId can be empty --- x/ccv/provider/client/cli/tx.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index 4ae23c7e6a..1894ad7b36 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -359,7 +359,7 @@ where update_consumer.json has the following structure: "allowlisted_reward_denoms": { "denoms": ["ibc/...", "ibc/..."] } - "new_chain_id": "newConsumer-1", + "new_chain_id": "newConsumer-1", // is optional and can be empty (i.e., "new_chain_id": "") } Note that only 'consumer_id' is mandatory. The others are optional.