diff --git a/.changelog/unreleased/api-breaking/provider/xxxx-priority-validators.md b/.changelog/unreleased/api-breaking/provider/xxxx-priority-validators.md new file mode 100644 index 0000000000..a90e0a6e26 --- /dev/null +++ b/.changelog/unreleased/api-breaking/provider/xxxx-priority-validators.md @@ -0,0 +1,2 @@ +- Allow consumer chains to specify a list of priority validators that are included in the validator set before other validators are considered + ([\#2101](https://github.com/cosmos/interchain-security/pull/2101)) \ No newline at end of file diff --git a/.changelog/unreleased/features/provider/xxxx-priority-validators.md b/.changelog/unreleased/features/provider/xxxx-priority-validators.md new file mode 100644 index 0000000000..a90e0a6e26 --- /dev/null +++ b/.changelog/unreleased/features/provider/xxxx-priority-validators.md @@ -0,0 +1,2 @@ +- Allow consumer chains to specify a list of priority validators that are included in the validator set before other validators are considered + ([\#2101](https://github.com/cosmos/interchain-security/pull/2101)) \ No newline at end of file diff --git a/contrib/local-testnet.sh b/contrib/local-testnet.sh index 3aebbbe262..8df8319898 100755 --- a/contrib/local-testnet.sh +++ b/contrib/local-testnet.sh @@ -317,7 +317,8 @@ tee ${PROV_NODE_DIR}/consumer_prop.json< []byte{}`, wi Format: `byte(40) | len(consumerId) | []byte(consumerId) -> uint64` +#### Prioritylist + +`Prioritylist` is the list of provider validators that have priority to validate a given consumer chain. + +Format: `byte(56) | len(consumerId) | []byte(consumerId) | addr -> []byte{}`, with `addr` the validator's consensus address on the provider chain. + ### Validator Set Updates #### ValidatorSetUpdateId @@ -1089,6 +1095,7 @@ Output: chains: - allow_inactive_vals: true allowlist: [] + prioritylist: [] chain_id: pion-1 client_id: 07-tendermint-0 consumer_id: "0" @@ -1554,6 +1561,7 @@ power_shaping_params: top_N: 100 validator_set_cap: 0 validators_power_cap: 0 + prioritylist: [] ``` @@ -1679,8 +1687,9 @@ where `update-consumer-msg.json` contains: "validator_set_cap": 50, "allowlist":["cosmosvalcons1l9qq4m300z8c5ez86ak2mp8znftewkwgjlxh88"], "denylist":[], - "min_stake": 1000, - "allow_inactive_vals":true + "min_stake": "1000", + "allow_inactive_vals":true, + "prioritylist":[] }, "allowlisted_reward_denoms": { "denoms": ["ibc/0025F8A87464A471E66B234C4F93AEC5B4DA3D42D7986451A059273426290DD5"] diff --git a/docs/docs/consumer-development/onboarding.md b/docs/docs/consumer-development/onboarding.md index 4350db2c14..51761f2a52 100644 --- a/docs/docs/consumer-development/onboarding.md +++ b/docs/docs/consumer-development/onboarding.md @@ -126,7 +126,9 @@ Example of power-shaping parameters: // Corresponds to the minimal amount of (provider chain) stake required to validate on the consumer chain. "min_stake": 0, // Corresponds to whether inactive validators are allowed to validate the consumer chain. - "allow_inactive_vals": false + "allow_inactive_vals": false, + // Corresponds to a list of provider consensus addresses of validators that have priority + "prioritylist": [], } ``` diff --git a/docs/docs/features/power-shaping.md b/docs/docs/features/power-shaping.md index 7bfad38588..08b4e94cd6 100644 --- a/docs/docs/features/power-shaping.md +++ b/docs/docs/features/power-shaping.md @@ -80,6 +80,10 @@ This can be useful for chains that want to have a larger validator set than the Consumer chains that enable this feature should strongly consider setting a minimum validator stake to ensure that only validators with some reputation/stake can validate the chain. By default, this parameter is set to `false`, i.e., validators outside of the provider's active set are not eligible to opt in. +### Prioritylist + +The consumer chain can specify a priority list of validators for participation in the validator set. Validators on the priority list are considered first when forming the consumer chain's validator set. If a priority list isn't set, the remaining slots are filled based on validator power. + ## Setting Power Shaping Parameters All the power shaping parameters can be set by the consumer chain in the `MsgCreateConsumer` or `MsgUpdateConsumer` messages. diff --git a/proto/interchain_security/ccv/provider/v1/provider.proto b/proto/interchain_security/ccv/provider/v1/provider.proto index e2e6b32c30..138e5fa23b 100644 --- a/proto/interchain_security/ccv/provider/v1/provider.proto +++ b/proto/interchain_security/ccv/provider/v1/provider.proto @@ -2,24 +2,24 @@ syntax = "proto3"; package interchain_security.ccv.provider.v1; -option go_package = "github.com/cosmos/interchain-security/v6/x/ccv/provider/types"; - -import "interchain_security/ccv/v1/wire.proto"; +import "amino/amino.proto"; +import "cosmos/base/v1beta1/coin.proto"; +import "cosmos/evidence/v1beta1/evidence.proto"; +import "cosmos_proto/cosmos.proto"; import "gogoproto/gogo.proto"; -import "google/protobuf/timestamp.proto"; import "google/protobuf/duration.proto"; +import "google/protobuf/timestamp.proto"; import "ibc/core/client/v1/client.proto"; import "ibc/lightclients/tendermint/v1/tendermint.proto"; +import "interchain_security/ccv/v1/wire.proto"; import "tendermint/crypto/keys.proto"; -import "cosmos/evidence/v1beta1/evidence.proto"; -import "cosmos/base/v1beta1/coin.proto"; -import "cosmos_proto/cosmos.proto"; -import "amino/amino.proto"; + +option go_package = "github.com/cosmos/interchain-security/v6/x/ccv/provider/types"; // // Note any type defined in this file is ONLY used internally to the provider CCV module. -// These schemas can change with proper consideration of compatibility or migration. -// +// These schemas can change with proper consideration of compatibility or migration. +// // WARNING: This message is deprecated in favor of `MsgCreateConsumer`. // ConsumerAdditionProposal is a governance proposal on the provider chain to @@ -44,7 +44,7 @@ message ConsumerAdditionProposal { // the proposed initial height of new consumer chain. // For a completely new chain, this will be {0,1}. However, it may be // different if this is a chain that is converting to a consumer chain. - ibc.core.client.v1.Height initial_height = 4 [ (gogoproto.nullable) = false ]; + ibc.core.client.v1.Height initial_height = 4 [(gogoproto.nullable) = false]; // The hash of the consumer chain genesis state without the consumer CCV // module genesis params. It is used for off-chain confirmation of // genesis.json validity by validators and other parties. @@ -56,19 +56,27 @@ message ConsumerAdditionProposal { // spawn time is the time on the provider chain at which the consumer chain // genesis is finalized and all validators will be responsible for starting // their consumer chain validator node. - google.protobuf.Timestamp spawn_time = 7 - [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; + google.protobuf.Timestamp spawn_time = 7 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false + ]; // Unbonding period for the consumer, // which should be smaller than that of the provider in general. - google.protobuf.Duration unbonding_period = 8 - [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + google.protobuf.Duration unbonding_period = 8 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true + ]; // Sent CCV related IBC packets will timeout after this duration - google.protobuf.Duration ccv_timeout_period = 9 - [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + google.protobuf.Duration ccv_timeout_period = 9 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true + ]; // Sent transfer related IBC packets will timeout after this duration - google.protobuf.Duration transfer_timeout_period = 10 - [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + google.protobuf.Duration transfer_timeout_period = 10 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true + ]; // The fraction of tokens allocated to the consumer redistribution address // during distribution events. The fraction is a string representing a // decimal number. For example "0.75" would represent 75%. @@ -124,7 +132,6 @@ message ConsumerRemovalProposal { option (cosmos_proto.implements_interface) = "cosmos.gov.v1beta1.Content"; option deprecated = true; - // the title of the proposal string title = 1; // the description of the proposal @@ -133,8 +140,10 @@ message ConsumerRemovalProposal { string chain_id = 3; // the time on the provider chain at which all validators are responsible to // stop their consumer chain validator node - google.protobuf.Timestamp stop_time = 4 - [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; + google.protobuf.Timestamp stop_time = 4 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false + ]; } // WARNING: This message is deprecated in favor of `MsgUpdateConsumer`. @@ -174,11 +183,10 @@ message ConsumerModificationProposal { bool allow_inactive_vals = 10; } - // EquivocationProposal is a governance proposal on the provider chain to // punish a validator for equivocation on a consumer chain. -// -// This type is only used internally to the consumer CCV module. +// +// This type is only used internally to the consumer CCV module. // WARNING: This message is deprecated now that equivocations can be submitted // and verified automatically on the provider. (see SubmitConsumerDoubleVoting in proto/interchain-security/ccv/provider/v1/tx.proto). message EquivocationProposal { @@ -213,10 +221,12 @@ message ChangeRewardDenomsProposal { message GlobalSlashEntry { // Block time that slash packet was received by provider chain. // This field is used for store key iteration ordering. - google.protobuf.Timestamp recv_time = 1 - [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; + google.protobuf.Timestamp recv_time = 1 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false + ]; // The consumer that sent a slash packet. - string consumer_chain_id = 2 [ (gogoproto.customname) = "ConsumerChainID" ]; + string consumer_chain_id = 2 [(gogoproto.customname) = "ConsumerChainID"]; // The IBC sequence number of the recv packet. // This field is used in the store key to ensure uniqueness. uint64 ibc_seq_num = 3; @@ -230,7 +240,6 @@ message GlobalSlashEntry { // Params defines the parameters for CCV Provider module message Params { - // Reserve 4th slot for removed init_timeout_period param reserved 4; @@ -245,12 +254,16 @@ message Params { // client's TrustingPeriod from the chain defined UnbondingPeriod string trusting_period_fraction = 2; // Sent IBC packets will timeout after this duration - google.protobuf.Duration ccv_timeout_period = 3 - [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + google.protobuf.Duration ccv_timeout_period = 3 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true + ]; // The period for which the slash meter is replenished - google.protobuf.Duration slash_meter_replenish_period = 6 - [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + google.protobuf.Duration slash_meter_replenish_period = 6 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true + ]; // The fraction of total voting power that is replenished to the slash meter // every replenish period. This param also serves as a maximum fraction of @@ -258,23 +271,24 @@ message Params { string slash_meter_replenish_fraction = 7; // The fee required to be paid to add a reward denom - cosmos.base.v1beta1.Coin consumer_reward_denom_registration_fee = 9 - [ (gogoproto.nullable) = false ]; + cosmos.base.v1beta1.Coin consumer_reward_denom_registration_fee = 9 [(gogoproto.nullable) = false]; // The number of blocks that comprise an epoch. int64 blocks_per_epoch = 10; // The number of epochs a validator has to validate a consumer chain in order to start receiving rewards from that chain. int64 number_of_epochs_to_start_receiving_rewards = 11; - + // The maximal number of validators that will be passed // to the consensus engine on the provider. int64 max_provider_consensus_validators = 12; } // SlashAcks contains cons addresses of consumer chain validators -// successfully slashed on the provider chain. -message SlashAcks { repeated string addresses = 1; } +// successfully slashed on the provider chain. +message SlashAcks { + repeated string addresses = 1; +} // ConsumerAdditionProposals holds pending governance proposals on the provider // chain to spawn a new chain. @@ -291,21 +305,22 @@ message ConsumerRemovalProposals { } // AddressList contains a list of consensus addresses -message AddressList { repeated bytes addresses = 1; } +message AddressList { + repeated bytes addresses = 1; +} // WARNING: This message is deprecated and is not used. // ChannelToChain is used to map a CCV channel ID to the consumer chainID message ChannelToChain { option deprecated = true; - + string channel_id = 1; string chain_id = 2; } // ValidatorSetChangePackets is a pb list of ccv.ValidatorSetChangePacketData. message ValidatorSetChangePackets { - repeated interchain_security.ccv.v1.ValidatorSetChangePacketData list = 1 - [ (gogoproto.nullable) = false ]; + repeated interchain_security.ccv.v1.ValidatorSetChangePacketData list = 1 [(gogoproto.nullable) = false]; } // @@ -340,15 +355,17 @@ message ValidatorByConsumerAddr { // ConsumerAddrsToPruneV2: (chainID, pruneTs time.Time) -> consumerAddrs AddressList message ConsumerAddrsToPruneV2 { string chain_id = 1; - google.protobuf.Timestamp prune_ts = 2 - [ (gogoproto.stdtime) = true, (gogoproto.nullable) = false ]; + google.protobuf.Timestamp prune_ts = 2 [ + (gogoproto.stdtime) = true, + (gogoproto.nullable) = false + ]; AddressList consumer_addrs = 3; } // ConsensusValidator is used to express a validator that -// should be validating on a chain. +// should be validating on a chain. // It contains relevant info for -// a validator that is expected to validate on +// a validator that is expected to validate on // either the provider or a consumer chain. message ConsensusValidator { // validator's consensus address on the provider chain @@ -363,13 +380,14 @@ message ConsensusValidator { // stops being a consumer validator during an epoch and later becomes again a consumer validator. int64 join_height = 4; } + // ConsumerRewardsAllocation stores the rewards allocated by a consumer chain -// to the consumer rewards pool. It is used to allocate the tokens to the consumer +// to the consumer rewards pool. It is used to allocate the tokens to the consumer // opted-in validators and the community pool during BeginBlock. message ConsumerRewardsAllocation { repeated cosmos.base.v1beta1.DecCoin rewards = 1 [ - (gogoproto.nullable) = false, - (amino.dont_omitempty) = true, + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true, (gogoproto.castrepeated) = "github.com/cosmos/cosmos-sdk/types.DecCoins" ]; } @@ -393,7 +411,7 @@ message ConsumerInitializationParameters { // the proposed initial height of new consumer chain. // For a completely new chain, this will be {0,1}. However, it may be // different if this is a chain that is converting to a consumer chain. - ibc.core.client.v1.Height initial_height = 1 [ (gogoproto.nullable) = false ]; + ibc.core.client.v1.Height initial_height = 1 [(gogoproto.nullable) = false]; // The hash of the consumer chain genesis state without the consumer CCV // module genesis params. It is used for off-chain confirmation of // genesis.json validity by validators and other parties. @@ -405,11 +423,16 @@ message ConsumerInitializationParameters { // spawn time is the time on the provider chain at which the consumer chain // genesis is finalized and all validators will be responsible for starting // their consumer chain validator node. - google.protobuf.Timestamp spawn_time = 4 [ (gogoproto.nullable) = false, (gogoproto.stdtime) = true ]; + google.protobuf.Timestamp spawn_time = 4 [ + (gogoproto.nullable) = false, + (gogoproto.stdtime) = true + ]; // Unbonding period for the consumer, // which should be smaller than that of the provider in general. - google.protobuf.Duration unbonding_period = 5 [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; - + google.protobuf.Duration unbonding_period = 5 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true + ]; // ---------- ---------- ---------- // Following fields are used to construct the consumer genesis of the to-be-launched consumer chain @@ -417,9 +440,15 @@ message ConsumerInitializationParameters { // ---------- ---------- ---------- // Sent CCV related IBC packets will timeout after this duration - google.protobuf.Duration ccv_timeout_period = 6 [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + google.protobuf.Duration ccv_timeout_period = 6 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true + ]; // Sent transfer related IBC packets will timeout after this duration - google.protobuf.Duration transfer_timeout_period = 7 [ (gogoproto.nullable) = false, (gogoproto.stdduration) = true ]; + google.protobuf.Duration transfer_timeout_period = 7 [ + (gogoproto.nullable) = false, + (gogoproto.stdduration) = true + ]; // The fraction of tokens allocated to the consumer redistribution address // during distribution events. The fraction is a string representing a // decimal number. For example "0.75" would represent 75%. @@ -489,11 +518,18 @@ message PowerShapingParameters { uint64 min_stake = 6; // Corresponds to whether inactive validators are allowed to validate the consumer chain. bool allow_inactive_vals = 7; + // Corresponds to a list of provider consensus addresses of validators that should have PRIORITY to validate on the consumer chain, + // meaning as long as they are eligible/opted in to validate on the consumer chain, the validator set will be + // filled with these validators first, and other validators will be added to the validator set only if there are + // not enough eligible priority validators. + repeated string prioritylist = 8; } // ConsumerIds contains consumer ids of chains // Used so we can easily (de)serialize slices of strings -message ConsumerIds { repeated string ids = 1; } +message ConsumerIds { + repeated string ids = 1; +} // ConsumerPhase indicates the phases of a consumer chain according to ADR 019 enum ConsumerPhase { @@ -517,4 +553,6 @@ enum ConsumerPhase { } // AllowlistedRewardDenoms corresponds to the denoms allowlisted by a specific consumer id -message AllowlistedRewardDenoms { repeated string denoms = 1; } \ No newline at end of file +message AllowlistedRewardDenoms { + repeated string denoms = 1; +} diff --git a/proto/interchain_security/ccv/provider/v1/query.proto b/proto/interchain_security/ccv/provider/v1/query.proto index 910af58278..e7ce6002eb 100644 --- a/proto/interchain_security/ccv/provider/v1/query.proto +++ b/proto/interchain_security/ccv/provider/v1/query.proto @@ -196,6 +196,11 @@ message Chain { string consumer_id = 13; // the reward denoms allowlisted by this consumer chain AllowlistedRewardDenoms allowlisted_reward_denoms = 14; + // Corresponds to a list of provider consensus addresses of validators that should have PRIORITY to validate on the consumer chain, + // meaning as long as they are eligible/opted in to validate on the consumer chain, the validator set will be + // filled with these validators first, and other validators will be added to the validator set only if there are + // not enough eligible priority validators. + repeated string prioritylist = 15; } message QueryValidatorConsumerAddrRequest { diff --git a/tests/e2e/actions.go b/tests/e2e/actions.go index 872d19ce6c..dba711b1e8 100644 --- a/tests/e2e/actions.go +++ b/tests/e2e/actions.go @@ -289,6 +289,7 @@ type PowerShapingParameters struct { Denylist []string MinStake uint64 AllowInactiveVals bool + Prioritylist []string } func (tr Chain) updateConsumerChain(action UpdateConsumerChainAction, verbose bool) { @@ -320,6 +321,7 @@ func (tr Chain) updateConsumerChain(action UpdateConsumerChainAction, verbose bo Denylist: action.PowerShapingParams.Denylist, MinStake: action.PowerShapingParams.MinStake, AllowInactiveVals: action.PowerShapingParams.AllowInactiveVals, + Prioritylist: action.PowerShapingParams.Prioritylist, } consumerId := tr.testConfig.chainConfigs[action.ConsumerChain].ConsumerId @@ -376,6 +378,7 @@ func (tr Chain) createConsumerChain(action CreateConsumerChainAction, verbose bo Denylist: action.PowerShapingParams.Denylist, MinStake: action.PowerShapingParams.MinStake, AllowInactiveVals: action.PowerShapingParams.AllowInactiveVals, + Prioritylist: action.PowerShapingParams.Prioritylist, } metadata := types.ConsumerMetadata{ @@ -463,6 +466,7 @@ type SubmitConsumerAdditionProposalAction struct { Denylist []string MinStake uint64 AllowInactiveVals bool + Prioritylist []string } func (tr Chain) UpdateConsumer(providerChain ChainID, validator ValidatorID, update types.MsgUpdateConsumer, verbose bool) { @@ -657,6 +661,7 @@ func (tr Chain) submitConsumerAdditionProposal( Denylist: action.Denylist, MinStake: action.MinStake, AllowInactiveVals: action.AllowInactiveVals, + Prioritylist: action.Prioritylist, } update.PowerShapingParameters = &powerShapingParameters tr.UpdateConsumer(action.Chain, action.From, *update, verbose) @@ -757,6 +762,7 @@ func (tr Chain) submitConsumerAdditionLegacyProposal( Denylist: action.Denylist, MinStake: action.MinStake, AllowInactiveVals: action.AllowInactiveVals, + Prioritylist: action.Prioritylist, } bz, err := json.Marshal(prop) @@ -937,6 +943,7 @@ type SubmitConsumerModificationProposalAction struct { AllowInactiveVals bool MinStake uint64 NewOwner string + Prioritylist []string } func (tr Chain) submitConsumerModificationProposal( @@ -962,6 +969,7 @@ func (tr Chain) submitConsumerModificationProposal( ValidatorSetCap: action.ValidatorSetCap, Allowlist: action.Allowlist, Denylist: action.Denylist, + Prioritylist: action.Prioritylist, }, } @@ -1019,6 +1027,7 @@ func (tr Chain) submitConsumerModificationLegacyProposal( ValidatorSetCap: action.ValidatorSetCap, Allowlist: action.Allowlist, Denylist: action.Denylist, + Prioritylist: action.Prioritylist, } bz, err := json.Marshal(prop) diff --git a/tests/e2e/main.go b/tests/e2e/main.go index 7b066a2020..e8e3e0640a 100644 --- a/tests/e2e/main.go +++ b/tests/e2e/main.go @@ -192,6 +192,12 @@ var stepChoices = map[string]StepChoice{ description: "test partial set security for an Opt-In chain that has a validator denylisted", testConfig: DefaultTestCfg, }, + "partial-set-security-validators-prioritylisted": { + name: "partial-set-security-validators-prioritylisted", + steps: stepsValidatorsPrioritylistedChain(), + description: "test partial set security for an Opt-In chain that has has some validators prioritylisted", + testConfig: DefaultTestCfg, + }, "partial-set-security-modification-proposal": { name: "partial-set-security-modification-proposal", steps: stepsModifyChain(), @@ -360,6 +366,7 @@ func getTestCases(selectedPredefinedTests, selectedTestFiles TestSet, providerVe "partial-set-security-validators-power-cap", "partial-set-security-validators-allowlisted", "partial-set-security-validators-denylisted", + "partial-set-security-validators-prioritylisted", "partial-set-security-modification-proposal", "active-set-changes", "inactive-provider-validators-on-consumer", diff --git a/tests/e2e/steps_partial_set_security.go b/tests/e2e/steps_partial_set_security.go index 6b23d675c2..06d41bf4d9 100644 --- a/tests/e2e/steps_partial_set_security.go +++ b/tests/e2e/steps_partial_set_security.go @@ -1840,6 +1840,190 @@ func stepsValidatorsDenylistedChain() []Step { return s } +// stepsValidatorsPrioritylistedChain starts a provider chain and an Opt-In chain with an prioritylist +func stepsValidatorsPrioritylistedChain() []Step { + s := []Step{ + { + Action: StartChainAction{ + Chain: ChainID("provi"), + Validators: []StartChainValidator{ + {Id: ValidatorID("alice"), Stake: 100000000, Allocation: 10000000000}, + {Id: ValidatorID("bob"), Stake: 200000000, Allocation: 10000000000}, + {Id: ValidatorID("carol"), Stake: 300000000, Allocation: 10000000000}, + }, + }, + State: State{ + ChainID("provi"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 200, + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + Action: CreateConsumerChainAction{ + Chain: ChainID("provi"), + From: ValidatorID("alice"), + ConsumerChain: ChainID("consu"), + InitParams: &InitializationParameters{ + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + SpawnTime: uint(time.Minute * 10), + }, + PowerShapingParams: &PowerShapingParameters{ + TopN: 0, + ValidatorSetCap: 2, + }, + }, + State: State{ + ChainID("provi"): ChainState{ + ProposedConsumerChains: &[]string{"consu"}, + }, + }, + }, + { + Action: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("alice"), + }, + State: State{ + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {}, + ValidatorID("bob"): {}, + ValidatorID("carol"): {}, + }, + }, + }, + }, + { + Action: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("bob"), + }, + State: State{ + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {}, + ValidatorID("bob"): {}, + ValidatorID("carol"): {}, + }, + }, + }, + }, + { + Action: OptInAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("carol"), + }, + State: State{ + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {}, + ValidatorID("bob"): {}, + ValidatorID("carol"): {}, + }, + }, + }, + }, + { + Action: AssignConsumerPubKeyAction{ + Chain: ChainID("consu"), + Validator: ValidatorID("carol"), + ConsumerPubkey: getDefaultValidators()[ValidatorID("carol")].ConsumerValPubKey, + ReconfigureNode: true, + }, + State: State{}, + }, + { + Action: UpdateConsumerChainAction{ + Chain: ChainID("provi"), + From: ValidatorID("alice"), + ConsumerChain: ChainID("consu"), + InitParams: &InitializationParameters{ + InitialHeight: clienttypes.Height{RevisionNumber: 0, RevisionHeight: 1}, + SpawnTime: 0, + }, + PowerShapingParams: &PowerShapingParameters{ + TopN: 0, + ValidatorSetCap: 2, + Prioritylist: []string{ + "cosmosvalcons1qmq08eruchr5sf5s3rwz7djpr5a25f7xw4mceq", //alice + }, + }, + }, + State: State{}, + }, + { + Action: StartConsumerChainAction{ + ConsumerChain: ChainID("consu"), + ProviderChain: ChainID("provi"), + Validators: []StartChainValidator{ + {Id: ValidatorID("alice"), Stake: 100000000, Allocation: 10000000000}, + {Id: ValidatorID("bob"), Stake: 200000000, Allocation: 10000000000}, + {Id: ValidatorID("carol"), Stake: 300000000, Allocation: 10000000000}, + }, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 0, // Bob is not in the validator set due to ValidatorSetCap and priority list + ValidatorID("carol"): 300, + }, + }, + }, + }, + { + Action: AddIbcConnectionAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + ClientA: 0, + ClientB: 0, + }, + State: State{}, + }, + { + Action: AddIbcChannelAction{ + ChainA: ChainID("consu"), + ChainB: ChainID("provi"), + ConnectionA: 0, + PortA: "consumer", + PortB: "provider", + Order: "ordered", + }, + State: State{}, + }, + { + Action: RelayPacketsAction{ + ChainA: ChainID("provi"), + ChainB: ChainID("consu"), + Port: "provider", + Channel: 0, + }, + State: State{ + ChainID("consu"): ChainState{ + ValPowers: &map[ValidatorID]uint{ + ValidatorID("alice"): 100, + ValidatorID("bob"): 0, + ValidatorID("carol"): 300, + }, + }, + ChainID("provi"): ChainState{ + HasToValidate: &map[ValidatorID][]ChainID{ + ValidatorID("alice"): {"consu"}, + ValidatorID("bob"): {}, + ValidatorID("carol"): {"consu"}, + }, + }, + }, + }, + } + + return s +} + // stepsModifyChain issues multiple `ConsumerModificationProposal`s on a consumer chain to assert that indeed // partial-set security parameters can be changed. func stepsModifyChain() []Step { diff --git a/testutil/keeper/unit_test_helpers.go b/testutil/keeper/unit_test_helpers.go index 9c967a739e..f2b61a122f 100644 --- a/testutil/keeper/unit_test_helpers.go +++ b/testutil/keeper/unit_test_helpers.go @@ -309,6 +309,7 @@ func GetTestPowerShapingParameters() providertypes.PowerShapingParameters { Denylist: nil, MinStake: 0, AllowInactiveVals: false, + Prioritylist: nil, } } diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index d1caeb1d6f..e2be4fa34d 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -251,10 +251,11 @@ where create_consumer.json has the following structure: "top_N": 0, "validators_power_cap": 10, "validator_set_cap": 0, - "allowlist": ["cosmosvalcons..."], - "denylist": ["cosmosvalcons..."], - "min_stake": 0, - "allow_inactive_vals": false + "allowlist": [], + "denylist": [], + "min_stake": "0", + "allow_inactive_vals": false, + "prioritylist": [] }, "allowlisted_reward_denoms": { "denoms": ["ibc/...", "ibc/..."] @@ -349,10 +350,11 @@ where update_consumer.json has the following structure: "top_N": 0, "validators_power_cap": 10, "validator_set_cap": 0, - "allowlist": ["cosmosvalcons..."], - "denylist": ["cosmosvalcons..."], - "min_stake": 0, - "allow_inactive_vals": false + "allowlist": [], + "denylist": [], + "min_stake": "0", + "allow_inactive_vals": false, + "prioritylist": [] }, "allowlisted_reward_denoms": { "denoms": ["ibc/...", "ibc/..."] diff --git a/x/ccv/provider/client/legacy_proposals.go b/x/ccv/provider/client/legacy_proposals.go index af96ec054b..8993ad9e73 100644 --- a/x/ccv/provider/client/legacy_proposals.go +++ b/x/ccv/provider/client/legacy_proposals.go @@ -43,6 +43,7 @@ type ConsumerAdditionProposalJSON struct { Denylist []string `json:"denylist"` MinStake uint64 `json:"min_stake"` AllowInactiveVals bool `json:"allow_inactive_vals"` + Prioritylist []string `json:"prioritylist"` } type ConsumerAdditionProposalReq struct { @@ -176,6 +177,7 @@ type ConsumerModificationProposalJSON struct { Denylist []string `json:"denylist"` MinStake uint64 `json:"min_stake"` AllowInactiveVals bool `json:"allow_inactive_vals"` + Prioritylist []string `json:"prioritylist"` Deposit string `json:"deposit"` } diff --git a/x/ccv/provider/keeper/consumer_lifecycle.go b/x/ccv/provider/keeper/consumer_lifecycle.go index 7bde45df8a..51d2120f89 100644 --- a/x/ccv/provider/keeper/consumer_lifecycle.go +++ b/x/ccv/provider/keeper/consumer_lifecycle.go @@ -486,6 +486,7 @@ func (k Keeper) DeleteConsumerChain(ctx sdk.Context, consumerId string) (err err k.DeleteDenylist(ctx, consumerId) k.DeleteAllOptedIn(ctx, consumerId) k.DeleteConsumerValSet(ctx, consumerId) + k.DeletePrioritylist(ctx, consumerId) k.DeleteConsumerRemovalTime(ctx, consumerId) diff --git a/x/ccv/provider/keeper/consumer_lifecycle_test.go b/x/ccv/provider/keeper/consumer_lifecycle_test.go index 6b258ae003..22b84e5870 100644 --- a/x/ccv/provider/keeper/consumer_lifecycle_test.go +++ b/x/ccv/provider/keeper/consumer_lifecycle_test.go @@ -222,6 +222,7 @@ func TestBeginBlockLaunchConsumers(t *testing.T) { ValidatorSetCap: 0, Allowlist: []string{}, Denylist: []string{}, + Prioritylist: []string{}, }, { Top_N: 50, @@ -229,6 +230,7 @@ func TestBeginBlockLaunchConsumers(t *testing.T) { ValidatorSetCap: 0, Allowlist: []string{}, Denylist: []string{}, + Prioritylist: []string{}, }, { Top_N: 50, @@ -236,6 +238,7 @@ func TestBeginBlockLaunchConsumers(t *testing.T) { ValidatorSetCap: 0, Allowlist: []string{}, Denylist: []string{}, + Prioritylist: []string{}, }, { Top_N: 0, @@ -243,6 +246,7 @@ func TestBeginBlockLaunchConsumers(t *testing.T) { ValidatorSetCap: 0, Allowlist: []string{}, Denylist: []string{}, + Prioritylist: []string{}, }, { Top_N: 0, @@ -250,6 +254,7 @@ func TestBeginBlockLaunchConsumers(t *testing.T) { ValidatorSetCap: 0, Allowlist: []string{}, Denylist: []string{}, + Prioritylist: []string{}, }, } diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index 9a16e8c5f9..dfc6b06501 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -114,6 +114,12 @@ func (k Keeper) GetConsumerChain(ctx sdk.Context, consumerId string) (types.Chai strDenylist[i] = addr.String() } + prioritylist := k.GetPriorityList(ctx, consumerId) + strPrioritylist := make([]string, len(prioritylist)) + for i, addr := range prioritylist { + strPrioritylist[i] = addr.String() + } + metadata, err := k.GetConsumerMetadata(ctx, consumerId) if err != nil { return types.Chain{}, fmt.Errorf("cannot find metadata (%s): %s", consumerId, err.Error()) @@ -139,6 +145,7 @@ func (k Keeper) GetConsumerChain(ctx sdk.Context, consumerId string) (types.Chai MinStake: powerShapingParameters.MinStake, ConsumerId: consumerId, AllowlistedRewardDenoms: &types.AllowlistedRewardDenoms{Denoms: allowlistedRewardDenoms}, + Prioritylist: strPrioritylist, }, nil } diff --git a/x/ccv/provider/keeper/grpc_query_test.go b/x/ccv/provider/keeper/grpc_query_test.go index 28658d7970..3323eb3e53 100644 --- a/x/ccv/provider/keeper/grpc_query_test.go +++ b/x/ccv/provider/keeper/grpc_query_test.go @@ -447,7 +447,12 @@ func TestGetConsumerChain(t *testing.T) { {types.NewProviderConsAddress([]byte("providerAddr6"))}, {}, } - + prioritylists := [][]types.ProviderConsAddress{ + {}, + {types.NewProviderConsAddress([]byte("providerAddr1")), types.NewProviderConsAddress([]byte("providerAddr2"))}, + {types.NewProviderConsAddress([]byte("providerAddr3"))}, + {}, + } allowInactiveVals := []bool{true, false, true, false} minStakes := []math.Int{ @@ -486,6 +491,9 @@ func TestGetConsumerChain(t *testing.T) { for _, addr := range denylists[i] { pk.SetDenylist(ctx, consumerID, addr) } + for _, addr := range prioritylists[i] { + pk.SetPrioritylist(ctx, consumerID, addr) + } strAllowlist := make([]string, len(allowlists[i])) for j, addr := range allowlists[i] { strAllowlist[j] = addr.String() @@ -496,6 +504,11 @@ func TestGetConsumerChain(t *testing.T) { strDenylist[j] = addr.String() } + strPrioritylist := make([]string, len(prioritylists[i])) + for j, addr := range allowlists[i] { + strPrioritylist[j] = addr.String() + } + metadataLists = append(metadataLists, types.ConsumerMetadata{Name: chainIDs[i]}) pk.SetConsumerMetadata(ctx, consumerID, metadataLists[i]) @@ -520,6 +533,7 @@ func TestGetConsumerChain(t *testing.T) { MinStake: minStakes[i].Uint64(), ConsumerId: consumerIDs[i], AllowlistedRewardDenoms: allowlistedRewardDenoms[i], + Prioritylist: strPrioritylist, }) } @@ -666,6 +680,7 @@ func TestQueryConsumerChains(t *testing.T) { Metadata: metadata, ConsumerId: consumerId, AllowlistedRewardDenoms: &types.AllowlistedRewardDenoms{Denoms: []string{}}, + Prioritylist: []string{}, } consumerIds[i] = consumerId consumers[i] = &c diff --git a/x/ccv/provider/keeper/power_shaping.go b/x/ccv/provider/keeper/power_shaping.go index 87624922b0..7bf4674b18 100644 --- a/x/ccv/provider/keeper/power_shaping.go +++ b/x/ccv/provider/keeper/power_shaping.go @@ -88,27 +88,37 @@ func (k Keeper) UpdateMinimumPowerInTopN(ctx sdk.Context, consumerId string, old } // CapValidatorSet caps the provided `validators` if chain with `consumerId` is an Opt In chain with a validator-set cap. -// If cap is `k`, `CapValidatorSet` returns the first `k` validators from `validators` with the highest power. +// It prioritizes validators from the priority list and then adds remaining validators. func (k Keeper) CapValidatorSet( ctx sdk.Context, powerShapingParameters types.PowerShapingParameters, - validators []types.ConsensusValidator, + priorityValidators []types.ConsensusValidator, + nonPriorityValidators []types.ConsensusValidator, ) []types.ConsensusValidator { if powerShapingParameters.Top_N > 0 { // is a no-op if the chain is a Top N chain - return validators + return append(priorityValidators, nonPriorityValidators...) } validatorSetCap := powerShapingParameters.ValidatorSetCap - if validatorSetCap != 0 && int(validatorSetCap) < len(validators) { - sort.Slice(validators, func(i, j int) bool { - return validators[i].Power > validators[j].Power - }) + totalValidators := len(priorityValidators) + len(nonPriorityValidators) + if validatorSetCap == 0 || int(validatorSetCap) >= totalValidators { + return append(priorityValidators, nonPriorityValidators...) + } - return validators[:int(validatorSetCap)] - } else { - return validators + resultValidators := make([]types.ConsensusValidator, 0, validatorSetCap) + + // Add priority validators first + for i := 0; i < len(priorityValidators) && len(resultValidators) < int(validatorSetCap); i++ { + resultValidators = append(resultValidators, priorityValidators[i]) + } + + // Add remaining validators up to the cap + for i := 0; i < len(nonPriorityValidators) && len(resultValidators) < int(validatorSetCap); i++ { + resultValidators = append(resultValidators, nonPriorityValidators[i]) } + + return resultValidators } // CapValidatorsPower caps the power of the validators on chain with `consumerId` and returns an updated slice of validators @@ -337,13 +347,16 @@ func (k Keeper) SetConsumerPowerShapingParameters(ctx sdk.Context, consumerId st store.Set(types.ConsumerIdToPowerShapingParametersKey(consumerId), bz) - // update allowlist and denylist indexes if needed + // update allowlist, denylist and priority indexes if needed if !equalStringSlices(oldParameters.Allowlist, parameters.Allowlist) { k.UpdateAllowlist(ctx, consumerId, parameters.Allowlist) } if !equalStringSlices(oldParameters.Denylist, parameters.Denylist) { k.UpdateDenylist(ctx, consumerId, parameters.Denylist) } + if !equalStringSlices(oldParameters.Prioritylist, parameters.Prioritylist) { + k.UpdatePrioritylist(ctx, consumerId, parameters.Prioritylist) + } return nil } @@ -551,3 +564,146 @@ func (k Keeper) DeleteMinimumPowerInTopN( store := ctx.KVStore(k.storeKey) store.Delete(types.MinimumPowerInTopNKey(consumerId)) } + +// SetPrioritylist prioritylists validator with `providerAddr` address on chain `consumerId` +func (k Keeper) SetPrioritylist( + ctx sdk.Context, + consumerId string, + providerAddr types.ProviderConsAddress, +) { + store := ctx.KVStore(k.storeKey) + store.Set(types.PrioritylistKey(consumerId, providerAddr), []byte{}) +} + +// GetPriorityList returns all prioritylisted validators +func (k Keeper) GetPriorityList( + ctx sdk.Context, + consumerId string, +) (providerConsAddresses []types.ProviderConsAddress) { + store := ctx.KVStore(k.storeKey) + key := types.StringIdWithLenKey(types.PrioritylistKeyPrefix(), consumerId) + iterator := storetypes.KVStorePrefixIterator(store, key) + defer iterator.Close() + + for ; iterator.Valid(); iterator.Next() { + providerConsAddresses = append(providerConsAddresses, types.NewProviderConsAddress(iterator.Key()[len(key):])) + } + + return providerConsAddresses +} + +// IsPrioritylisted returns `true` if validator with `providerAddr` has been prioritylisted on chain `consumerId` +func (k Keeper) IsPrioritylisted( + ctx sdk.Context, + consumerId string, + providerAddr types.ProviderConsAddress, +) bool { + store := ctx.KVStore(k.storeKey) + bz := store.Get(types.PrioritylistKey(consumerId, providerAddr)) + return bz != nil +} + +// DeletePrioritylist deletes all prioritylisted validators +func (k Keeper) DeletePrioritylist(ctx sdk.Context, consumerId string) { + store := ctx.KVStore(k.storeKey) + iterator := storetypes.KVStorePrefixIterator(store, types.StringIdWithLenKey(types.PrioritylistKeyPrefix(), consumerId)) + defer iterator.Close() + + keysToDel := [][]byte{} + for ; iterator.Valid(); iterator.Next() { + keysToDel = append(keysToDel, iterator.Key()) + } + + for _, key := range keysToDel { + store.Delete(key) + } +} + +// IsPrioritylistEmpty returns `true` if no validator is prioritylisted on chain `consumerId` +func (k Keeper) IsPrioritylistEmpty(ctx sdk.Context, consumerId string) bool { + store := ctx.KVStore(k.storeKey) + iterator := storetypes.KVStorePrefixIterator(store, types.StringIdWithLenKey(types.PrioritylistKeyPrefix(), consumerId)) + defer iterator.Close() + + return !iterator.Valid() +} + +// UpdatePrioritylist populates the prioritylist store for the consumer chain with this consumer id +func (k Keeper) UpdatePrioritylist(ctx sdk.Context, consumerId string, prioritylist []string) { + k.DeletePrioritylist(ctx, consumerId) + for _, address := range prioritylist { + consAddr, err := sdk.ConsAddressFromBech32(address) + if err != nil { + continue + } + + k.SetPrioritylist(ctx, consumerId, types.NewProviderConsAddress(consAddr)) + } +} + +// // FilterAndSortPriorityList filters the priority list to include only validators that can validate the chain +// // by ensuring they are present in the validators list. +// // It then sorts the filtered list of validators in descending order based on their power. +// func (k Keeper) FilterAndSortPriorityList(priorityList []string, validators []types.ConsensusValidator) []types.ConsensusValidator { +// validatorMap := make(map[string]types.ConsensusValidator) +// for _, v := range validators { +// validatorMap[string(v.ProviderConsAddr)] = v +// } + +// filteredPriority := make([]types.ConsensusValidator, 0) +// addedAddresses := make(map[string]bool) + +// for _, address := range priorityList { +// if validator, exists := validatorMap[address]; exists { +// if !addedAddresses[address] { +// filteredPriority = append(filteredPriority, validator) +// addedAddresses[address] = true +// } +// } +// } + +// sort.Slice(filteredPriority, func(i, j int) bool { +// return filteredPriority[i].Power > filteredPriority[j].Power +// }) + +// return filteredPriority +// } + +// FilterAndSortPriorityList filters the priority list to include only validators that can validate the chain +// and splits the validators into priority and non-priority sets. +func (k Keeper) FilterAndSortPriorityList(ctx sdk.Context, priorityList []string, nextValidators []types.ConsensusValidator) ([]types.ConsensusValidator, []types.ConsensusValidator) { + validatorMap := make(map[string]types.ConsensusValidator) + for _, v := range nextValidators { + validatorMap[string(v.ProviderConsAddr)] = v + } + + priorityValidators := make([]types.ConsensusValidator, 0) + nonPriorityValidators := make([]types.ConsensusValidator, 0) + addedAddresses := make(map[string]bool) + + // Form priorityValidators + for _, address := range priorityList { + if validator, exists := validatorMap[address]; exists { + if !addedAddresses[address] { + priorityValidators = append(priorityValidators, validator) + addedAddresses[address] = true + delete(validatorMap, address) + } + } + } + + // Add remaining validators to nonPriorityValidators + for _, validator := range validatorMap { + nonPriorityValidators = append(nonPriorityValidators, validator) + } + + sort.Slice(priorityValidators, func(i, j int) bool { + return priorityValidators[i].Power > priorityValidators[j].Power + }) + + sort.Slice(nonPriorityValidators, func(i, j int) bool { + return nonPriorityValidators[i].Power > nonPriorityValidators[j].Power + }) + + return priorityValidators, nonPriorityValidators +} diff --git a/x/ccv/provider/keeper/power_shaping_test.go b/x/ccv/provider/keeper/power_shaping_test.go index b0853588ee..0fb6a03092 100644 --- a/x/ccv/provider/keeper/power_shaping_test.go +++ b/x/ccv/provider/keeper/power_shaping_test.go @@ -246,78 +246,182 @@ func TestCanValidateChain(t *testing.T) { require.False(t, canValidateChain) } -func TestCapValidatorSet(t *testing.T) { +func TestCapValidatorSetAndFilterAndSortPriorityList(t *testing.T) { providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) defer ctrl.Finish() - validatorA := providertypes.ConsensusValidator{ - ProviderConsAddr: []byte("providerConsAddrA"), - Power: 1, - PublicKey: &crypto.PublicKey{}, - } + validatorA := providertypes.ConsensusValidator{ProviderConsAddr: []byte("providerConsAddrA"), Power: 1, PublicKey: &crypto.PublicKey{}} + validatorB := providertypes.ConsensusValidator{ProviderConsAddr: []byte("providerConsAddrB"), Power: 2, PublicKey: &crypto.PublicKey{}} + validatorC := providertypes.ConsensusValidator{ProviderConsAddr: []byte("providerConsAddrC"), Power: 3, PublicKey: &crypto.PublicKey{}} + validatorD := providertypes.ConsensusValidator{ProviderConsAddr: []byte("providerConsAddrD"), Power: 4, PublicKey: &crypto.PublicKey{}} + validators := []providertypes.ConsensusValidator{validatorA, validatorB, validatorC, validatorD} - validatorB := providertypes.ConsensusValidator{ - ProviderConsAddr: []byte("providerConsAddrB"), - Power: 2, - PublicKey: &crypto.PublicKey{}, + // Initial error check + powerShapingParameters, err := providerKeeper.GetConsumerPowerShapingParameters(ctx, CONSUMER_ID) + require.Error(t, err) + priorityValidators, nonPriorityValidators := providerKeeper.FilterAndSortPriorityList(ctx, powerShapingParameters.Prioritylist, validators) + consumerValidators := providerKeeper.CapValidatorSet(ctx, powerShapingParameters, priorityValidators, nonPriorityValidators) + require.Equal(t, []providertypes.ConsensusValidator{validatorD, validatorC, validatorB, validatorA}, consumerValidators) + + testCases := []struct { + name string + powerShapingParameters providertypes.PowerShapingParameters + expectedValidators []providertypes.ConsensusValidator + expectError bool + }{ + { + name: "ValidatorSetCap = 0 (no capping)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 0}, + expectedValidators: []providertypes.ConsensusValidator{validatorD, validatorC, validatorB, validatorA}, + }, + { + name: "ValidatorSetCap > len(validators) (no capping)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 100}, + expectedValidators: []providertypes.ConsensusValidator{validatorD, validatorC, validatorB, validatorA}, + }, + { + name: "ValidatorSetCap = 1 (capping to highest power, no priority list)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 1}, + expectedValidators: []providertypes.ConsensusValidator{validatorD}, + }, + { + name: "ValidatorSetCap = 2 (capping to two highest power, no priority list)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 2}, + expectedValidators: []providertypes.ConsensusValidator{validatorD, validatorC}, + }, + { + name: "ValidatorSetCap = 3 (capping to three highest power, no priority list)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 3}, + expectedValidators: []providertypes.ConsensusValidator{validatorD, validatorC, validatorB}, + }, + { + name: "ValidatorSetCap = 2, with priority list", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 2, Prioritylist: []string{string(validatorA.ProviderConsAddr), string(validatorB.ProviderConsAddr)}}, + expectedValidators: []providertypes.ConsensusValidator{validatorB, validatorA}, + }, + { + name: "ValidatorSetCap = 3, with partial priority list", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 3, Prioritylist: []string{string(validatorA.ProviderConsAddr)}}, + expectedValidators: []providertypes.ConsensusValidator{validatorA, validatorD, validatorC}, + }, + { + name: "All validators in priority list", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 4, Prioritylist: []string{string(validatorC.ProviderConsAddr), string(validatorA.ProviderConsAddr), string(validatorD.ProviderConsAddr), string(validatorB.ProviderConsAddr)}}, + expectedValidators: []providertypes.ConsensusValidator{validatorD, validatorC, validatorB, validatorA}, + }, + { + name: "ValidatorSetCap = 1 (capping to highest power, with priority list)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 1, Prioritylist: []string{string(validatorA.ProviderConsAddr)}}, + expectedValidators: []providertypes.ConsensusValidator{validatorA}, + }, } - validatorC := providertypes.ConsensusValidator{ - ProviderConsAddr: []byte("providerConsAddrC"), - Power: 3, - PublicKey: &crypto.PublicKey{}, + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := providerKeeper.SetConsumerPowerShapingParameters(ctx, CONSUMER_ID, tc.powerShapingParameters) + require.NoError(t, err) + + powerShapingParameters, err := providerKeeper.GetConsumerPowerShapingParameters(ctx, CONSUMER_ID) + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tc.powerShapingParameters, powerShapingParameters) + } + + priorityValidators, nonPriorityValidators := providerKeeper.FilterAndSortPriorityList(ctx, powerShapingParameters.Prioritylist, validators) + consumerValidators := providerKeeper.CapValidatorSet(ctx, powerShapingParameters, priorityValidators, nonPriorityValidators) + require.Equal(t, tc.expectedValidators, consumerValidators) + }) } - validators := []providertypes.ConsensusValidator{validatorA, validatorB, validatorC} +} + +func TestCapValidatorSet(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + validatorA := providertypes.ConsensusValidator{ProviderConsAddr: []byte("providerConsAddrA"), Power: 1, PublicKey: &crypto.PublicKey{}} + validatorB := providertypes.ConsensusValidator{ProviderConsAddr: []byte("providerConsAddrB"), Power: 2, PublicKey: &crypto.PublicKey{}} + validatorC := providertypes.ConsensusValidator{ProviderConsAddr: []byte("providerConsAddrC"), Power: 3, PublicKey: &crypto.PublicKey{}} + validatorD := providertypes.ConsensusValidator{ProviderConsAddr: []byte("providerConsAddrD"), Power: 4, PublicKey: &crypto.PublicKey{}} + + validators := []providertypes.ConsensusValidator{validatorA, validatorB, validatorC, validatorD} powerShapingParameters, err := providerKeeper.GetConsumerPowerShapingParameters(ctx, CONSUMER_ID) require.Error(t, err) - consumerValidators := providerKeeper.CapValidatorSet(ctx, powerShapingParameters, validators) + consumerValidators := providerKeeper.CapValidatorSet(ctx, powerShapingParameters, []providertypes.ConsensusValidator{}, validators) require.Equal(t, validators, consumerValidators) - err = providerKeeper.SetConsumerPowerShapingParameters(ctx, CONSUMER_ID, providertypes.PowerShapingParameters{ - ValidatorSetCap: 0, - }) - require.NoError(t, err) - powerShapingParameters, err = providerKeeper.GetConsumerPowerShapingParameters(ctx, CONSUMER_ID) - require.NoError(t, err) - consumerValidators = providerKeeper.CapValidatorSet(ctx, powerShapingParameters, validators) - require.Equal(t, validators, consumerValidators) - - err = providerKeeper.SetConsumerPowerShapingParameters(ctx, CONSUMER_ID, providertypes.PowerShapingParameters{ - ValidatorSetCap: 100, - }) - require.NoError(t, err) - powerShapingParameters, err = providerKeeper.GetConsumerPowerShapingParameters(ctx, CONSUMER_ID) - require.NoError(t, err) - consumerValidators = providerKeeper.CapValidatorSet(ctx, powerShapingParameters, validators) - require.Equal(t, validators, consumerValidators) + testCases := []struct { + name string + powerShapingParameters providertypes.PowerShapingParameters + priorityValidators []providertypes.ConsensusValidator + nonPriorityValidators []providertypes.ConsensusValidator + expectedValidators []providertypes.ConsensusValidator + }{ + { + name: "ValidatorSetCap = 0 (no capping)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 0}, + priorityValidators: []providertypes.ConsensusValidator{validatorB, validatorA}, + nonPriorityValidators: []providertypes.ConsensusValidator{validatorD, validatorC}, + expectedValidators: []providertypes.ConsensusValidator{validatorB, validatorA, validatorD, validatorC}, + }, + { + name: "ValidatorSetCap > total validators (no capping)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 100}, + priorityValidators: []providertypes.ConsensusValidator{validatorB, validatorA}, + nonPriorityValidators: []providertypes.ConsensusValidator{validatorD, validatorC}, + expectedValidators: []providertypes.ConsensusValidator{validatorB, validatorA, validatorD, validatorC}, + }, + { + name: "ValidatorSetCap = 1 (capping to highest priority)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 1}, + priorityValidators: []providertypes.ConsensusValidator{validatorB, validatorA}, + nonPriorityValidators: []providertypes.ConsensusValidator{validatorD, validatorC}, + expectedValidators: []providertypes.ConsensusValidator{validatorB}, + }, + { + name: "ValidatorSetCap = 2 (capping to two highest priority)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 2}, + priorityValidators: []providertypes.ConsensusValidator{validatorB, validatorA}, + nonPriorityValidators: []providertypes.ConsensusValidator{validatorD, validatorC}, + expectedValidators: []providertypes.ConsensusValidator{validatorB, validatorA}, + }, + { + name: "ValidatorSetCap = 3 (capping to all priority and one non-priority)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 3}, + priorityValidators: []providertypes.ConsensusValidator{validatorB, validatorA}, + nonPriorityValidators: []providertypes.ConsensusValidator{validatorD, validatorC}, + expectedValidators: []providertypes.ConsensusValidator{validatorB, validatorA, validatorD}, + }, + { + name: "ValidatorSetCap = 2, with only non-priority validators", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 2}, + priorityValidators: []providertypes.ConsensusValidator{}, + nonPriorityValidators: []providertypes.ConsensusValidator{validatorD, validatorC, validatorB, validatorA}, + expectedValidators: []providertypes.ConsensusValidator{validatorD, validatorC}, + }, + { + name: "ValidatorSetCap = 3, with partial priority list", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 3}, + priorityValidators: []providertypes.ConsensusValidator{validatorA}, + nonPriorityValidators: []providertypes.ConsensusValidator{validatorD, validatorC, validatorB}, + expectedValidators: []providertypes.ConsensusValidator{validatorA, validatorD, validatorC}, + }, + } - err = providerKeeper.SetConsumerPowerShapingParameters(ctx, CONSUMER_ID, providertypes.PowerShapingParameters{ - ValidatorSetCap: 1, - }) - require.NoError(t, err) - powerShapingParameters, err = providerKeeper.GetConsumerPowerShapingParameters(ctx, CONSUMER_ID) - require.NoError(t, err) - consumerValidators = providerKeeper.CapValidatorSet(ctx, powerShapingParameters, validators) - require.Equal(t, []providertypes.ConsensusValidator{validatorC}, consumerValidators) + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + err := providerKeeper.SetConsumerPowerShapingParameters(ctx, CONSUMER_ID, tc.powerShapingParameters) + require.NoError(t, err) - err = providerKeeper.SetConsumerPowerShapingParameters(ctx, CONSUMER_ID, providertypes.PowerShapingParameters{ - ValidatorSetCap: 2, - }) - require.NoError(t, err) - powerShapingParameters, err = providerKeeper.GetConsumerPowerShapingParameters(ctx, CONSUMER_ID) - require.NoError(t, err) - consumerValidators = providerKeeper.CapValidatorSet(ctx, powerShapingParameters, validators) - require.Equal(t, []providertypes.ConsensusValidator{validatorC, validatorB}, consumerValidators) + powerShapingParameters, err := providerKeeper.GetConsumerPowerShapingParameters(ctx, CONSUMER_ID) + require.NoError(t, err) - err = providerKeeper.SetConsumerPowerShapingParameters(ctx, CONSUMER_ID, providertypes.PowerShapingParameters{ - ValidatorSetCap: 3, - }) - require.NoError(t, err) - powerShapingParameters, err = providerKeeper.GetConsumerPowerShapingParameters(ctx, CONSUMER_ID) - require.NoError(t, err) - consumerValidators = providerKeeper.CapValidatorSet(ctx, powerShapingParameters, validators) - require.Equal(t, []providertypes.ConsensusValidator{validatorC, validatorB, validatorA}, consumerValidators) + consumerValidators := providerKeeper.CapValidatorSet(ctx, powerShapingParameters, tc.priorityValidators, tc.nonPriorityValidators) + require.Equal(t, tc.expectedValidators, consumerValidators) + }) + } } func TestCapValidatorsPower(t *testing.T) { @@ -745,6 +849,7 @@ func TestConsumerPowerShapingParameters(t *testing.T) { Denylist: []string{consAddrs[2], consAddrs[3]}, MinStake: 234, AllowInactiveVals: true, + Prioritylist: []string{consAddrs[1]}, } expectedAllowlist := []providertypes.ProviderConsAddress{providerConsAddr[0], providerConsAddr[1]} sortProviderConsAddr(expectedAllowlist) @@ -767,6 +872,7 @@ func TestConsumerPowerShapingParameters(t *testing.T) { Denylist: []string{consAddrs[2], consAddrs[3]}, MinStake: 567, AllowInactiveVals: false, + Prioritylist: []string{consAddrs[4], consAddrs[5]}, } expectedAllowlist = []providertypes.ProviderConsAddress{providerConsAddr[4], providerConsAddr[5]} sortProviderConsAddr(expectedAllowlist) @@ -1006,3 +1112,148 @@ func TestUpdateMinimumPowerInTopN(t *testing.T) { require.True(t, found) require.Equal(t, int64(10), minimumPowerInTopN) } + +func TestPrioritylist(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerID := CONSUMER_ID + + // no validator was prioritylisted and hence the prioritylist is empty + require.True(t, providerKeeper.IsPrioritylistEmpty(ctx, consumerID)) + + providerAddr1 := providertypes.NewProviderConsAddress([]byte("providerAddr1")) + providerKeeper.SetPrioritylist(ctx, consumerID, providerAddr1) + require.True(t, providerKeeper.IsPrioritylisted(ctx, consumerID, providerAddr1)) + + // prioritylist is not empty anymore + require.False(t, providerKeeper.IsPrioritylistEmpty(ctx, consumerID)) + + providerAddr2 := providertypes.NewProviderConsAddress([]byte("providerAddr2")) + providerKeeper.SetPrioritylist(ctx, consumerID, providerAddr2) + require.True(t, providerKeeper.IsPrioritylisted(ctx, consumerID, providerAddr2)) + require.False(t, providerKeeper.IsPrioritylistEmpty(ctx, consumerID)) + + providerKeeper.DeletePrioritylist(ctx, consumerID) + require.False(t, providerKeeper.IsPrioritylisted(ctx, consumerID, providerAddr1)) + require.False(t, providerKeeper.IsPrioritylisted(ctx, consumerID, providerAddr2)) + require.True(t, providerKeeper.IsPrioritylistEmpty(ctx, consumerID)) +} + +func TestUpdatePrioritylist(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + consumerId := "0" + + providerConsAddr1 := "cosmosvalcons1qmq08eruchr5sf5s3rwz7djpr5a25f7xw4mceq" + consAddr1, _ := sdk.ConsAddressFromBech32(providerConsAddr1) + providerConsAddr2 := "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39" + consAddr2, _ := sdk.ConsAddressFromBech32(providerConsAddr2) + + providerKeeper.UpdatePrioritylist(ctx, consumerId, []string{providerConsAddr1, providerConsAddr2}) + + expectedPrioritylist := []providertypes.ProviderConsAddress{ + providertypes.NewProviderConsAddress(consAddr1), + providertypes.NewProviderConsAddress(consAddr2), + } + require.Equal(t, expectedPrioritylist, providerKeeper.GetPriorityList(ctx, consumerId)) +} + +func TestFilterAndSortPriorityList(t *testing.T) { + providerKeeper, ctx, ctrl, _ := testkeeper.GetProviderKeeperAndCtx(t, testkeeper.NewInMemKeeperParams(t)) + defer ctrl.Finish() + + // Create test validators + validator1 := providertypes.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr1"), + Power: 100, + PublicKey: &crypto.PublicKey{}, + } + validator2 := providertypes.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr2"), + Power: 200, + PublicKey: &crypto.PublicKey{}, + } + validator3 := providertypes.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr3"), + Power: 150, + PublicKey: &crypto.PublicKey{}, + } + validator4 := providertypes.ConsensusValidator{ + ProviderConsAddr: []byte("providerConsAddr4"), + Power: 50, + PublicKey: &crypto.PublicKey{}, + } + + validators := []providertypes.ConsensusValidator{validator1, validator2, validator3, validator4} + + testCases := []struct { + name string + priorityList []string + expectedPriority []providertypes.ConsensusValidator + expectedNonPriority []providertypes.ConsensusValidator + }{ + { + name: "Empty priority list", + priorityList: []string{}, + expectedPriority: []providertypes.ConsensusValidator{}, + expectedNonPriority: []providertypes.ConsensusValidator{validator2, validator3, validator1, validator4}, + }, + { + name: "Priority list with non-existent addresses", + priorityList: []string{"providerConsAddr5", "providerConsAddr6"}, + expectedPriority: []providertypes.ConsensusValidator{}, + expectedNonPriority: []providertypes.ConsensusValidator{validator2, validator3, validator1, validator4}, + }, + { + name: "Priority list with some existing addresses", + priorityList: []string{"providerConsAddr2", "providerConsAddr5", "providerConsAddr4"}, + expectedPriority: []providertypes.ConsensusValidator{validator2, validator4}, + expectedNonPriority: []providertypes.ConsensusValidator{validator3, validator1}, + }, + { + name: "Priority list with all existing addresses in different order", + priorityList: []string{"providerConsAddr4", "providerConsAddr1", "providerConsAddr3", "providerConsAddr2"}, + expectedPriority: []providertypes.ConsensusValidator{validator2, validator3, validator1, validator4}, + expectedNonPriority: []providertypes.ConsensusValidator{}, + }, + { + name: "Priority list with duplicate addresses", + priorityList: []string{"providerConsAddr1", "providerConsAddr2", "providerConsAddr1", "providerConsAddr3"}, + expectedPriority: []providertypes.ConsensusValidator{validator2, validator3, validator1}, + expectedNonPriority: []providertypes.ConsensusValidator{validator4}, + }, + } + + for _, tc := range testCases { + t.Run(tc.name, func(t *testing.T) { + priorityResult, nonPriorityResult := providerKeeper.FilterAndSortPriorityList(ctx, tc.priorityList, validators) + + // Check priority validators + require.Equal(t, len(tc.expectedPriority), len(priorityResult), "Length of priority result doesn't match expected") + for i, v := range priorityResult { + require.Equal(t, tc.expectedPriority[i].ProviderConsAddr, v.ProviderConsAddr, "Priority validator address doesn't match expected at index %d", i) + require.Equal(t, tc.expectedPriority[i].Power, v.Power, "Priority validator power doesn't match expected at index %d", i) + } + + // Check non-priority validators + require.Equal(t, len(tc.expectedNonPriority), len(nonPriorityResult), "Length of non-priority result doesn't match expected") + for i, v := range nonPriorityResult { + require.Equal(t, tc.expectedNonPriority[i].ProviderConsAddr, v.ProviderConsAddr, "Non-priority validator address doesn't match expected at index %d", i) + require.Equal(t, tc.expectedNonPriority[i].Power, v.Power, "Non-priority validator power doesn't match expected at index %d", i) + } + + // Check if both results are sorted by power in descending order + checkSortedByPower(t, priorityResult) + checkSortedByPower(t, nonPriorityResult) + }) + } +} + +// Helper function to check if validators are sorted by power in descending order +func checkSortedByPower(t *testing.T, validators []providertypes.ConsensusValidator) { + for i := 1; i < len(validators); i++ { + require.GreaterOrEqual(t, validators[i-1].Power, validators[i].Power, "Validators are not sorted by power in descending order") + } +} diff --git a/x/ccv/provider/keeper/validator_set_update.go b/x/ccv/provider/keeper/validator_set_update.go index d375d42d8f..5f43101de1 100644 --- a/x/ccv/provider/keeper/validator_set_update.go +++ b/x/ccv/provider/keeper/validator_set_update.go @@ -233,7 +233,9 @@ func (k Keeper) ComputeNextValidators( return []types.ConsensusValidator{}, err } - nextValidators = k.CapValidatorSet(ctx, powerShapingParameters, nextValidators) + priorityValidators, nonPriorityValidators := k.FilterAndSortPriorityList(ctx, powerShapingParameters.Prioritylist, nextValidators) + + nextValidators = k.CapValidatorSet(ctx, powerShapingParameters, priorityValidators, nonPriorityValidators) nextValidators = k.CapValidatorsPower(ctx, powerShapingParameters.ValidatorsPowerCap, nextValidators) diff --git a/x/ccv/provider/migrations/v8/migrations.go b/x/ccv/provider/migrations/v8/migrations.go index c7b94c95e8..57be71f062 100644 --- a/x/ccv/provider/migrations/v8/migrations.go +++ b/x/ccv/provider/migrations/v8/migrations.go @@ -218,6 +218,12 @@ func MigrateLaunchedConsumerChains(ctx sdk.Context, store storetypes.KVStore, pk return err } + // chainId -> Prioritylist + err = rekeyChainIdAndConsAddrKey(store, providertypes.PrioritylistKeyPrefix(), chainId, consumerId) + if err != nil { + return err + } + // chainId -> ConsumerRewardsAllocations rekeyFromChainIdToConsumerId(store, ConsumerRewardsAllocationKeyPrefix, chainId, consumerId) @@ -286,6 +292,7 @@ func MigrateLaunchedConsumerChains(ctx sdk.Context, store storetypes.KVStore, pk allowlist := TransformConsAddressesToBech32Addresses(pk.GetAllowList(ctx, consumerId)) denylist := TransformConsAddressesToBech32Addresses(pk.GetDenyList(ctx, consumerId)) + prioritylist := TransformConsAddressesToBech32Addresses(pk.GetPriorityList(ctx, consumerId)) powerShapingParameters := providertypes.PowerShapingParameters{ Top_N: topN, @@ -296,6 +303,7 @@ func MigrateLaunchedConsumerChains(ctx sdk.Context, store storetypes.KVStore, pk // do not set those since they do not exist in a previous interchain-security version and hence cannot be set MinStake: 0, AllowInactiveVals: false, + Prioritylist: prioritylist, } err = pk.SetConsumerPowerShapingParameters(ctx, consumerId, powerShapingParameters) if err != nil { diff --git a/x/ccv/provider/migrations/v8/migrations_test.go b/x/ccv/provider/migrations/v8/migrations_test.go index 01dc0f0a2e..23196a8004 100644 --- a/x/ccv/provider/migrations/v8/migrations_test.go +++ b/x/ccv/provider/migrations/v8/migrations_test.go @@ -209,6 +209,8 @@ func StoreChainDataUsingChainIdAsKey(ctx sdk.Context, store storetypes.KVStore, providerKeeper.AppendConsumerAddrsToPrune(ctx, data.ChainId, data.PruneTs, data.ConsumerAddr) + providerKeeper.SetPrioritylist(ctx, data.ChainId, data.ProviderAddr) + // set Top N topNKey := providertypes.StringIdWithLenKey(LegacyTopNKeyPrefix, data.ChainId) buf := make([]byte, 4) @@ -289,6 +291,14 @@ func GetChainDataUsingStringId(ctx sdk.Context, providerKeeper providerkeeper.Ke } } + prioritylist := providerKeeper.GetPriorityList(ctx, id) + if len(prioritylist) > 0 { + tempProviderAddr := prioritylist[0] + if stopEarly && tempProviderAddr.String() != providerAddr.String() { + return ChainData{}, fmt.Errorf("retrieved providerAddr (%s) should be (%s)", tempProviderAddr.String(), providerAddr.String()) + } + } + consumerCommissionRate, found := providerKeeper.GetConsumerCommissionRate(ctx, id, providerAddr) if found { data.ConsumerCommissionRate = consumerCommissionRate diff --git a/x/ccv/provider/types/keys.go b/x/ccv/provider/types/keys.go index ca78611fd8..2e712b3e6e 100644 --- a/x/ccv/provider/types/keys.go +++ b/x/ccv/provider/types/keys.go @@ -154,6 +154,8 @@ const ( ConsumerIdToAllowlistedRewardDenomKeyName = "ConsumerIdToAllowlistedRewardDenomKey" ConsumerRewardsAllocationByDenomKeyName = "ConsumerRewardsAllocationByDenomKey" + + PrioritylistKeyName = "PrioritylistKey" ) // getKeyPrefixes returns a constant map of all the byte prefixes for existing keys @@ -391,6 +393,10 @@ func getKeyPrefixes() map[string]byte { // ConsumerRewardsAllocationByDenomKeyName is the key for storing the consumer rewards for a specific consumer chain and denom ConsumerRewardsAllocationByDenomKeyName: 55, + // PrioritylistKey is the key for storing the mapping from a consumer chain to the set of validators that are + // prioritylisted. + PrioritylistKeyName: 56, + // NOTE: DO NOT ADD NEW BYTE PREFIXES HERE WITHOUT ADDING THEM TO TestPreserveBytePrefix() IN keys_test.go } } @@ -597,6 +603,16 @@ func DenylistKey(consumerId string, providerAddr ProviderConsAddress) []byte { return StringIdAndConsAddrKey(DenylistKeyPrefix(), consumerId, providerAddr.ToSdkConsAddr()) } +// PrioritylistKeyPrefix returns the key prefix for storing consumer chains prioritylists +func PrioritylistKeyPrefix() byte { + return mustGetKeyPrefix(PrioritylistKeyName) +} + +// PrioritylistKey returns the key for storing consumer chains prioritylists +func PrioritylistKey(consumerId string, providerAddr ProviderConsAddress) []byte { + return StringIdAndConsAddrKey(PrioritylistKeyPrefix(), consumerId, providerAddr.ToSdkConsAddr()) +} + // OptedInKeyPrefix returns the key prefix for storing whether a validator is opted in on a consumer chain. func OptedInKeyPrefix() byte { return mustGetKeyPrefix(OptedInKeyName) diff --git a/x/ccv/provider/types/keys_test.go b/x/ccv/provider/types/keys_test.go index 814ece665a..de8156c8ec 100644 --- a/x/ccv/provider/types/keys_test.go +++ b/x/ccv/provider/types/keys_test.go @@ -147,6 +147,8 @@ func TestPreserveBytePrefix(t *testing.T) { i++ require.Equal(t, byte(55), providertypes.ConsumerRewardsAllocationByDenomKey("13", "denom")[0]) i++ + require.Equal(t, byte(56), providertypes.PrioritylistKeyPrefix()) + i++ prefixes := providertypes.GetAllKeyPrefixes() require.Equal(t, len(prefixes), i) @@ -216,6 +218,7 @@ func getAllFullyDefinedKeys() [][]byte { providertypes.ClientIdToConsumerIdKey("clientId"), providertypes.ConsumerIdToAllowlistedRewardDenomKey("13"), providertypes.ConsumerRewardsAllocationByDenomKey("13", "denom"), + providertypes.PrioritylistKey("13", providertypes.NewProviderConsAddress([]byte{0x05})), } } diff --git a/x/ccv/provider/types/msg.go b/x/ccv/provider/types/msg.go index 05fa7c6ee1..02b383df09 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -527,6 +527,9 @@ func ValidatePowerShapingParameters(powerShapingParameters PowerShapingParameter if err := ValidateConsAddressList(powerShapingParameters.Denylist, MaxValidatorCount); err != nil { return errorsmod.Wrapf(ErrInvalidPowerShapingParameters, "Denylist: %s", err.Error()) } + if err := ValidateConsAddressList(powerShapingParameters.Prioritylist, MaxValidatorCount); err != nil { + return errorsmod.Wrapf(ErrInvalidPowerShapingParameters, "Prioritylist: %s", err.Error()) + } return nil } diff --git a/x/ccv/provider/types/msg_test.go b/x/ccv/provider/types/msg_test.go index 84b40c043e..c2951d794d 100644 --- a/x/ccv/provider/types/msg_test.go +++ b/x/ccv/provider/types/msg_test.go @@ -502,6 +502,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) { Denylist: nil, MinStake: 0, AllowInactiveVals: false, + Prioritylist: []string{consAddr1}, }, true, }, @@ -513,6 +514,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) { ValidatorSetCap: 0, Allowlist: nil, Denylist: nil, + Prioritylist: nil, }, false, }, @@ -526,6 +528,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) { Denylist: nil, MinStake: 0, AllowInactiveVals: false, + Prioritylist: nil, }, false, }, @@ -539,6 +542,7 @@ func TestMsgUpdateConsumerValidateBasic(t *testing.T) { Denylist: []string{consAddr2, consAddr3}, MinStake: 0, AllowInactiveVals: false, + Prioritylist: []string{consAddr1}, }, true, }, diff --git a/x/ccv/provider/types/provider.pb.go b/x/ccv/provider/types/provider.pb.go index c390ab752b..ae7402200e 100644 --- a/x/ccv/provider/types/provider.pb.go +++ b/x/ccv/provider/types/provider.pb.go @@ -1699,6 +1699,11 @@ type PowerShapingParameters struct { MinStake uint64 `protobuf:"varint,6,opt,name=min_stake,json=minStake,proto3" json:"min_stake,omitempty"` // Corresponds to whether inactive validators are allowed to validate the consumer chain. AllowInactiveVals bool `protobuf:"varint,7,opt,name=allow_inactive_vals,json=allowInactiveVals,proto3" json:"allow_inactive_vals,omitempty"` + // Corresponds to a list of provider consensus addresses of validators that should have PRIORITY to validate on the consumer chain, + // meaning as long as they are eligible/opted in to validate on the consumer chain, the validator set will be + // filled with these validators first, and other validators will be added to the validator set only if there are + // not enough eligible priority validators. + Prioritylist []string `protobuf:"bytes,8,rep,name=prioritylist,proto3" json:"prioritylist,omitempty"` } func (m *PowerShapingParameters) Reset() { *m = PowerShapingParameters{} } @@ -1783,6 +1788,13 @@ func (m *PowerShapingParameters) GetAllowInactiveVals() bool { return false } +func (m *PowerShapingParameters) GetPrioritylist() []string { + if m != nil { + return m.Prioritylist + } + return nil +} + // ConsumerIds contains consumer ids of chains // Used so we can easily (de)serialize slices of strings type ConsumerIds struct { @@ -1907,149 +1919,150 @@ func init() { } var fileDescriptor_f22ec409a72b7b72 = []byte{ - // 2267 bytes of a gzipped FileDescriptorProto - 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0xcb, 0x6f, 0x1b, 0xc9, - 0xd1, 0xd7, 0x88, 0x94, 0x44, 0x16, 0xf5, 0xa0, 0xda, 0x5e, 0x99, 0x92, 0xb5, 0x24, 0xcd, 0xfd, - 0xbc, 0xe0, 0x67, 0xc7, 0xe4, 0x4a, 0x0b, 0x04, 0x86, 0x93, 0x85, 0x41, 0x93, 0xb4, 0x4d, 0x3f, - 0x64, 0x66, 0x48, 0x6b, 0x01, 0xe7, 0x30, 0x68, 0xce, 0xb4, 0xc8, 0x8e, 0xe6, 0xe5, 0xe9, 0x26, - 0x6d, 0xe6, 0x90, 0xf3, 0x22, 0x40, 0x80, 0x4d, 0x4e, 0x8b, 0x5c, 0xb2, 0x40, 0x2e, 0x41, 0x4e, - 0x39, 0x04, 0xf9, 0x03, 0x72, 0xda, 0x04, 0x08, 0xb0, 0xb9, 0xe5, 0xb4, 0x1b, 0xd8, 0x87, 0x1c, - 0x02, 0x24, 0xe7, 0xdc, 0x82, 0xee, 0x79, 0x70, 0xa8, 0x97, 0x69, 0xd8, 0xce, 0x45, 0x9a, 0xae, - 0xfa, 0x55, 0x75, 0x75, 0x77, 0xbd, 0xba, 0x09, 0xbb, 0xd4, 0xe6, 0xc4, 0xd3, 0x07, 0x98, 0xda, - 0x1a, 0x23, 0xfa, 0xd0, 0xa3, 0x7c, 0x5c, 0xd5, 0xf5, 0x51, 0xd5, 0xf5, 0x9c, 0x11, 0x35, 0x88, - 0x57, 0x1d, 0xed, 0x44, 0xdf, 0x15, 0xd7, 0x73, 0xb8, 0x83, 0x3e, 0x38, 0x41, 0xa6, 0xa2, 0xeb, - 0xa3, 0x4a, 0x84, 0x1b, 0xed, 0x6c, 0x5d, 0x3e, 0x4d, 0xf1, 0x68, 0xa7, 0xfa, 0x8c, 0x7a, 0xc4, - 0xd7, 0xb5, 0x75, 0xbe, 0xef, 0xf4, 0x1d, 0xf9, 0x59, 0x15, 0x5f, 0x01, 0xb5, 0xd0, 0x77, 0x9c, - 0xbe, 0x49, 0xaa, 0x72, 0xd4, 0x1b, 0x1e, 0x54, 0x39, 0xb5, 0x08, 0xe3, 0xd8, 0x72, 0x03, 0x40, - 0xfe, 0x28, 0xc0, 0x18, 0x7a, 0x98, 0x53, 0xc7, 0x0e, 0x15, 0xd0, 0x9e, 0x5e, 0xd5, 0x1d, 0x8f, - 0x54, 0x75, 0x93, 0x12, 0x9b, 0x8b, 0x59, 0xfd, 0xaf, 0x00, 0x50, 0x15, 0x00, 0x93, 0xf6, 0x07, - 0xdc, 0x27, 0xb3, 0x2a, 0x27, 0xb6, 0x41, 0x3c, 0x8b, 0xfa, 0xe0, 0xc9, 0x28, 0x10, 0xd8, 0x8e, - 0xf1, 0x75, 0x6f, 0xec, 0x72, 0xa7, 0x7a, 0x48, 0xc6, 0x2c, 0xe0, 0x7e, 0xa8, 0x3b, 0xcc, 0x72, - 0x58, 0x95, 0x88, 0xf5, 0xdb, 0x3a, 0xa9, 0x8e, 0x76, 0x7a, 0x84, 0xe3, 0x9d, 0x88, 0x10, 0xda, - 0x1d, 0xe0, 0x7a, 0x98, 0x4d, 0x30, 0xba, 0x43, 0x43, 0xbb, 0x37, 0x7d, 0xbe, 0xe6, 0xef, 0x88, - 0x3f, 0x08, 0x58, 0xeb, 0xd8, 0xa2, 0xb6, 0x53, 0x95, 0x7f, 0x7d, 0x52, 0xe9, 0x3f, 0x29, 0xc8, - 0xd5, 0x1d, 0x9b, 0x0d, 0x2d, 0xe2, 0xd5, 0x0c, 0x83, 0x8a, 0x0d, 0x68, 0x7b, 0x8e, 0xeb, 0x30, - 0x6c, 0xa2, 0xf3, 0xb0, 0xc0, 0x29, 0x37, 0x49, 0x4e, 0x29, 0x2a, 0xe5, 0xb4, 0xea, 0x0f, 0x50, - 0x11, 0x32, 0x06, 0x61, 0xba, 0x47, 0x5d, 0x01, 0xce, 0xcd, 0x4b, 0x5e, 0x9c, 0x84, 0x36, 0x21, - 0xe5, 0x9f, 0x1a, 0x35, 0x72, 0x09, 0xc9, 0x5e, 0x92, 0xe3, 0x96, 0x81, 0xee, 0xc0, 0x2a, 0xb5, - 0x29, 0xa7, 0xd8, 0xd4, 0x06, 0x44, 0xec, 0x5d, 0x2e, 0x59, 0x54, 0xca, 0x99, 0xdd, 0xad, 0x0a, - 0xed, 0xe9, 0x15, 0xb1, 0xdd, 0x95, 0x60, 0x93, 0x47, 0x3b, 0x95, 0xbb, 0x12, 0x71, 0x2b, 0xf9, - 0xd5, 0x37, 0x85, 0x39, 0x75, 0x25, 0x90, 0xf3, 0x89, 0xe8, 0x12, 0x2c, 0xf7, 0x89, 0x4d, 0x18, - 0x65, 0xda, 0x00, 0xb3, 0x41, 0x6e, 0xa1, 0xa8, 0x94, 0x97, 0xd5, 0x4c, 0x40, 0xbb, 0x8b, 0xd9, - 0x00, 0x15, 0x20, 0xd3, 0xa3, 0x36, 0xf6, 0xc6, 0x3e, 0x62, 0x51, 0x22, 0xc0, 0x27, 0x49, 0x40, - 0x1d, 0x80, 0xb9, 0xf8, 0x99, 0xad, 0x09, 0xdf, 0xc8, 0x2d, 0x05, 0x86, 0xf8, 0x7e, 0x51, 0x09, - 0xfd, 0xa2, 0xd2, 0x0d, 0x1d, 0xe7, 0x56, 0x4a, 0x18, 0xf2, 0xf9, 0xb7, 0x05, 0x45, 0x4d, 0x4b, - 0x39, 0xc1, 0x41, 0x7b, 0x90, 0x1d, 0xda, 0x3d, 0xc7, 0x36, 0xa8, 0xdd, 0xd7, 0x5c, 0xe2, 0x51, - 0xc7, 0xc8, 0xa5, 0xa4, 0xaa, 0xcd, 0x63, 0xaa, 0x1a, 0x81, 0x8b, 0xf9, 0x9a, 0xbe, 0x10, 0x9a, - 0xd6, 0x22, 0xe1, 0xb6, 0x94, 0x45, 0x3f, 0x00, 0xa4, 0xeb, 0x23, 0x69, 0x92, 0x33, 0xe4, 0xa1, - 0xc6, 0xf4, 0xec, 0x1a, 0xb3, 0xba, 0x3e, 0xea, 0xfa, 0xd2, 0x81, 0xca, 0x1f, 0xc2, 0x05, 0xee, - 0x61, 0x9b, 0x1d, 0x10, 0xef, 0xa8, 0x5e, 0x98, 0x5d, 0xef, 0x7b, 0xa1, 0x8e, 0x69, 0xe5, 0x77, - 0xa1, 0xa8, 0x07, 0x0e, 0xa4, 0x79, 0xc4, 0xa0, 0x8c, 0x7b, 0xb4, 0x37, 0x14, 0xb2, 0xda, 0x81, - 0x87, 0x75, 0xe9, 0x23, 0x19, 0xe9, 0x04, 0xf9, 0x10, 0xa7, 0x4e, 0xc1, 0x6e, 0x07, 0x28, 0xf4, - 0x08, 0xfe, 0xaf, 0x67, 0x3a, 0xfa, 0x21, 0x13, 0xc6, 0x69, 0x53, 0x9a, 0xe4, 0xd4, 0x16, 0x65, - 0x4c, 0x68, 0x5b, 0x2e, 0x2a, 0xe5, 0x84, 0x7a, 0xc9, 0xc7, 0xb6, 0x89, 0xd7, 0x88, 0x21, 0xbb, - 0x31, 0x20, 0xba, 0x06, 0x68, 0x40, 0x19, 0x77, 0x3c, 0xaa, 0x63, 0x53, 0x23, 0x36, 0xf7, 0x28, - 0x61, 0xb9, 0x15, 0x29, 0xbe, 0x3e, 0xe1, 0x34, 0x7d, 0x06, 0xba, 0x07, 0x97, 0x4e, 0x9d, 0x54, - 0xd3, 0x07, 0xd8, 0xb6, 0x89, 0x99, 0x5b, 0x95, 0x4b, 0x29, 0x18, 0xa7, 0xcc, 0x59, 0xf7, 0x61, - 0xe8, 0x1c, 0x2c, 0x70, 0xc7, 0xd5, 0xf6, 0x72, 0x6b, 0x45, 0xa5, 0xbc, 0xa2, 0x26, 0xb9, 0xe3, - 0xee, 0xa1, 0x8f, 0xe0, 0xfc, 0x08, 0x9b, 0xd4, 0xc0, 0xdc, 0xf1, 0x98, 0xe6, 0x3a, 0xcf, 0x88, - 0xa7, 0xe9, 0xd8, 0xcd, 0x65, 0x25, 0x06, 0x4d, 0x78, 0x6d, 0xc1, 0xaa, 0x63, 0x17, 0x5d, 0x81, - 0xf5, 0x88, 0xaa, 0x31, 0xc2, 0x25, 0x7c, 0x5d, 0xc2, 0xd7, 0x22, 0x46, 0x87, 0x70, 0x81, 0xdd, - 0x86, 0x34, 0x36, 0x4d, 0xe7, 0x99, 0x49, 0x19, 0xcf, 0xa1, 0x62, 0xa2, 0x9c, 0x56, 0x27, 0x04, - 0xb4, 0x05, 0x29, 0x83, 0xd8, 0x63, 0xc9, 0x3c, 0x27, 0x99, 0xd1, 0x18, 0x5d, 0x84, 0xb4, 0x25, - 0x72, 0x2c, 0xc7, 0x87, 0x24, 0x77, 0xbe, 0xa8, 0x94, 0x93, 0x6a, 0xca, 0xa2, 0x76, 0x47, 0x8c, - 0x51, 0x05, 0xce, 0x49, 0x2d, 0x1a, 0xb5, 0xc5, 0x39, 0x8d, 0x88, 0x36, 0xc2, 0x26, 0xcb, 0xbd, - 0x57, 0x54, 0xca, 0x29, 0x75, 0x5d, 0xb2, 0x5a, 0x01, 0x67, 0x1f, 0x9b, 0xec, 0x46, 0xf9, 0xb3, - 0x2f, 0x0b, 0x73, 0x5f, 0x7c, 0x59, 0x98, 0xfb, 0xf3, 0xef, 0xaf, 0x6d, 0x05, 0xe9, 0xa7, 0xef, - 0x8c, 0x2a, 0x41, 0xaa, 0xaa, 0xd4, 0x1d, 0x9b, 0x13, 0x9b, 0xe7, 0x94, 0xd2, 0x5f, 0x15, 0xb8, - 0x50, 0x8f, 0x5c, 0xc2, 0x72, 0x46, 0xd8, 0x7c, 0x97, 0xa9, 0xa7, 0x06, 0x69, 0x26, 0xce, 0x44, - 0x06, 0x7b, 0xf2, 0x35, 0x82, 0x3d, 0x25, 0xc4, 0x04, 0xe3, 0x46, 0xf1, 0x95, 0x6b, 0xfa, 0xf7, - 0x3c, 0x6c, 0x87, 0x6b, 0x7a, 0xe8, 0x18, 0xf4, 0x80, 0xea, 0xf8, 0x5d, 0xe7, 0xd4, 0xc8, 0xd7, - 0x92, 0x33, 0xf8, 0xda, 0xc2, 0xeb, 0xf9, 0xda, 0xe2, 0x0c, 0xbe, 0xb6, 0x74, 0x96, 0xaf, 0xa5, - 0xce, 0xf2, 0xb5, 0xf4, 0x6c, 0xbe, 0x06, 0xa7, 0xf9, 0xda, 0x7c, 0x4e, 0x29, 0xfd, 0x4a, 0x81, - 0xf3, 0xcd, 0xa7, 0x43, 0x3a, 0x72, 0xde, 0xd2, 0x4e, 0xdf, 0x87, 0x15, 0x12, 0xd3, 0xc7, 0x72, - 0x89, 0x62, 0xa2, 0x9c, 0xd9, 0xbd, 0x5c, 0x09, 0x0e, 0x3e, 0xaa, 0xc7, 0xe1, 0xe9, 0xc7, 0x67, - 0x57, 0xa7, 0x65, 0xa5, 0x85, 0x7f, 0x54, 0x60, 0x4b, 0xe4, 0x85, 0x3e, 0x51, 0xc9, 0x33, 0xec, - 0x19, 0x0d, 0x62, 0x3b, 0x16, 0x7b, 0x63, 0x3b, 0x4b, 0xb0, 0x62, 0x48, 0x4d, 0x1a, 0x77, 0x34, - 0x6c, 0x18, 0xd2, 0x4e, 0x89, 0x11, 0xc4, 0xae, 0x53, 0x33, 0x0c, 0x54, 0x86, 0xec, 0x04, 0xe3, - 0x89, 0x18, 0x13, 0xae, 0x2f, 0x60, 0xab, 0x21, 0x4c, 0x46, 0x1e, 0xb9, 0x91, 0x3f, 0xdb, 0xb5, - 0x4b, 0xff, 0x54, 0x20, 0x7b, 0xc7, 0x74, 0x7a, 0xd8, 0xec, 0x98, 0x98, 0x0d, 0x44, 0xce, 0x1c, - 0x8b, 0x90, 0xf2, 0x48, 0x50, 0xac, 0xa4, 0xf9, 0x33, 0x87, 0x94, 0x10, 0x93, 0xe5, 0xf3, 0x26, - 0xac, 0x47, 0xe5, 0x23, 0x72, 0x70, 0xb9, 0xda, 0x5b, 0xe7, 0x5e, 0x7c, 0x53, 0x58, 0x0b, 0x83, - 0xa9, 0x2e, 0x9d, 0xbd, 0xa1, 0xae, 0xe9, 0x53, 0x04, 0x03, 0xe5, 0x21, 0x43, 0x7b, 0xba, 0xc6, - 0xc8, 0x53, 0xcd, 0x1e, 0x5a, 0x32, 0x36, 0x92, 0x6a, 0x9a, 0xf6, 0xf4, 0x0e, 0x79, 0xba, 0x37, - 0xb4, 0xd0, 0xc7, 0xb0, 0x11, 0x36, 0x95, 0xc2, 0x9b, 0x34, 0x21, 0x2f, 0xb6, 0xcb, 0x93, 0xe1, - 0xb2, 0xac, 0x9e, 0x0b, 0xb9, 0xfb, 0xd8, 0x14, 0x93, 0xd5, 0x0c, 0xc3, 0x2b, 0xfd, 0x6b, 0x01, - 0x16, 0xdb, 0xd8, 0xc3, 0x16, 0x43, 0x5d, 0x58, 0xe3, 0xc4, 0x72, 0x4d, 0xcc, 0x89, 0xe6, 0xb7, - 0x26, 0xc1, 0x4a, 0xaf, 0xca, 0x96, 0x25, 0xde, 0x00, 0x56, 0x62, 0x2d, 0xdf, 0x68, 0xa7, 0x52, - 0x97, 0xd4, 0x0e, 0xc7, 0x9c, 0xa8, 0xab, 0xa1, 0x0e, 0x9f, 0x88, 0xae, 0x43, 0x8e, 0x7b, 0x43, - 0xc6, 0x27, 0x4d, 0xc3, 0xa4, 0x5a, 0xfa, 0x67, 0xbd, 0x11, 0xf2, 0xfd, 0x3a, 0x1b, 0x55, 0xc9, - 0x93, 0xfb, 0x83, 0xc4, 0x9b, 0xf4, 0x07, 0x06, 0x6c, 0x33, 0x71, 0xa8, 0x9a, 0x45, 0xb8, 0xac, - 0xe2, 0xae, 0x49, 0x6c, 0xca, 0x06, 0xa1, 0xf2, 0xc5, 0xd9, 0x95, 0x6f, 0x4a, 0x45, 0x0f, 0x85, - 0x1e, 0x35, 0x54, 0x13, 0xcc, 0x52, 0x87, 0xfc, 0xc9, 0xb3, 0x44, 0x0b, 0x5f, 0x92, 0x0b, 0xbf, - 0x78, 0x82, 0x8a, 0x68, 0xf5, 0x0c, 0x3e, 0x8c, 0x75, 0x1b, 0x22, 0x9a, 0x34, 0xe9, 0xc8, 0x9a, - 0x47, 0xfa, 0xa2, 0x24, 0x63, 0xbf, 0xf1, 0x20, 0x24, 0xea, 0x98, 0x02, 0x9f, 0x16, 0xed, 0x72, - 0xcc, 0xa9, 0xa9, 0x1d, 0xb4, 0x95, 0xa5, 0x49, 0x53, 0x12, 0xc5, 0xa6, 0x1a, 0xd3, 0x75, 0x9b, - 0x10, 0x11, 0x45, 0xb1, 0xc6, 0x84, 0xb8, 0x8e, 0x3e, 0x90, 0x39, 0x29, 0xa1, 0xae, 0x46, 0x4d, - 0x48, 0x53, 0x50, 0xd1, 0x13, 0xb8, 0x6a, 0x0f, 0xad, 0x1e, 0xf1, 0x34, 0xe7, 0xc0, 0x07, 0xca, - 0xc8, 0x63, 0x1c, 0x7b, 0x5c, 0xf3, 0x88, 0x4e, 0xe8, 0x48, 0x9c, 0xb8, 0x6f, 0x39, 0x93, 0x7d, - 0x51, 0x42, 0xbd, 0xec, 0x8b, 0x3c, 0x3a, 0x90, 0x3a, 0x58, 0xd7, 0xe9, 0x08, 0xb8, 0x1a, 0xa2, - 0x7d, 0xc3, 0x18, 0x6a, 0xc1, 0x25, 0x0b, 0x3f, 0xd7, 0x22, 0x67, 0x16, 0x86, 0x13, 0x9b, 0x0d, - 0x99, 0x36, 0x49, 0xe6, 0x41, 0x6f, 0x94, 0xb7, 0xf0, 0xf3, 0x76, 0x80, 0xab, 0x87, 0xb0, 0xfd, - 0x08, 0x75, 0x2f, 0x99, 0x4a, 0x66, 0x17, 0xee, 0x25, 0x53, 0x0b, 0xd9, 0xc5, 0x7b, 0xc9, 0x54, - 0x2a, 0x9b, 0x2e, 0xfd, 0x3f, 0xa4, 0x65, 0x5c, 0xd7, 0xf4, 0x43, 0x26, 0xb3, 0xbb, 0x61, 0x78, - 0x84, 0x31, 0xc2, 0x72, 0x4a, 0x90, 0xdd, 0x43, 0x42, 0x89, 0xc3, 0xe6, 0x69, 0x37, 0x06, 0x86, - 0x3e, 0x85, 0x25, 0x97, 0xc8, 0x76, 0x56, 0x0a, 0x66, 0x76, 0x3f, 0xa9, 0xcc, 0x70, 0xd5, 0xab, - 0x9c, 0xa6, 0x50, 0x0d, 0xb5, 0x95, 0xbc, 0xc9, 0x3d, 0xe5, 0x48, 0xaf, 0xc0, 0xd0, 0xfe, 0xd1, - 0x49, 0xbf, 0xff, 0x5a, 0x93, 0x1e, 0xd1, 0x37, 0x99, 0xf3, 0x2a, 0x64, 0x6a, 0xfe, 0xb2, 0x1f, - 0x88, 0xd2, 0x75, 0x6c, 0x5b, 0x96, 0xe3, 0xdb, 0xb2, 0x07, 0xab, 0x41, 0xf3, 0xd7, 0x75, 0x64, - 0x6e, 0x42, 0xef, 0x03, 0x04, 0x5d, 0xa3, 0xc8, 0x69, 0x7e, 0x76, 0x4f, 0x07, 0x94, 0x96, 0x31, - 0x55, 0xd1, 0xe7, 0xa7, 0x2a, 0xba, 0xac, 0x1a, 0x0e, 0x6c, 0xee, 0xc7, 0xab, 0xae, 0x2c, 0x20, - 0x6d, 0xac, 0x1f, 0x12, 0xce, 0x90, 0x0a, 0x49, 0x59, 0x5d, 0xfd, 0xe5, 0x5e, 0x3f, 0x75, 0xb9, - 0xa3, 0x9d, 0xca, 0x69, 0x4a, 0x1a, 0x98, 0xe3, 0x20, 0x06, 0xa4, 0xae, 0xd2, 0xcf, 0x15, 0xc8, - 0xdd, 0x27, 0xe3, 0x1a, 0x63, 0xb4, 0x6f, 0x5b, 0xc4, 0xe6, 0x22, 0xfa, 0xb0, 0x4e, 0xc4, 0x27, - 0xfa, 0x00, 0x56, 0x22, 0xc7, 0x93, 0xc9, 0x53, 0x91, 0xc9, 0x73, 0x39, 0x24, 0x8a, 0x7d, 0x42, - 0x37, 0x00, 0x5c, 0x8f, 0x8c, 0x34, 0x5d, 0x3b, 0x24, 0x63, 0xb9, 0xa6, 0xcc, 0xee, 0x76, 0x3c, - 0x29, 0xfa, 0xb7, 0xde, 0x4a, 0x7b, 0xd8, 0x33, 0xa9, 0x7e, 0x9f, 0x8c, 0xd5, 0x94, 0xc0, 0xd7, - 0xef, 0x93, 0xb1, 0xa8, 0x82, 0xb2, 0x49, 0x91, 0x99, 0x2c, 0xa1, 0xfa, 0x83, 0xd2, 0x2f, 0x15, - 0xb8, 0x10, 0x2d, 0x20, 0x3c, 0xaf, 0xf6, 0xb0, 0x27, 0x24, 0xe2, 0xfb, 0xa7, 0x4c, 0x77, 0x44, - 0xc7, 0xac, 0x9d, 0x3f, 0xc1, 0xda, 0x9b, 0xb0, 0x1c, 0xa5, 0x12, 0x61, 0x6f, 0x62, 0x06, 0x7b, - 0x33, 0xa1, 0xc4, 0x7d, 0x32, 0x2e, 0xfd, 0x24, 0x66, 0xdb, 0xad, 0x71, 0xcc, 0x85, 0xbd, 0x57, - 0xd8, 0x16, 0x4d, 0x1b, 0xb7, 0x4d, 0x8f, 0xcb, 0x1f, 0x5b, 0x40, 0xe2, 0xf8, 0x02, 0x4a, 0x7f, - 0x51, 0x60, 0x23, 0x3e, 0x2b, 0xeb, 0x3a, 0x6d, 0x6f, 0x68, 0x93, 0xfd, 0xdd, 0xb3, 0xe6, 0xbf, - 0x09, 0x29, 0x57, 0xa0, 0x34, 0xce, 0x82, 0x23, 0x9a, 0xad, 0x64, 0x2f, 0x49, 0xa9, 0xae, 0x08, - 0xf1, 0xd5, 0xa9, 0x05, 0xb0, 0x60, 0xe7, 0x3e, 0x9a, 0x29, 0xe8, 0x62, 0x01, 0xa5, 0xae, 0xc4, - 0xd7, 0xcc, 0x4a, 0x7f, 0x50, 0x00, 0x1d, 0xcf, 0x56, 0xe8, 0x3b, 0x80, 0xa6, 0x72, 0x5e, 0xdc, - 0xff, 0xb2, 0x6e, 0x2c, 0xcb, 0xc9, 0x9d, 0x8b, 0xfc, 0x68, 0x3e, 0xe6, 0x47, 0xe8, 0x7b, 0x00, - 0xae, 0x3c, 0xc4, 0x99, 0x4f, 0x3a, 0xed, 0x86, 0x9f, 0xa8, 0x00, 0x99, 0x1f, 0x39, 0xd4, 0x8e, - 0x3f, 0x58, 0x24, 0x54, 0x10, 0x24, 0xff, 0x2d, 0xa2, 0xf4, 0x33, 0x65, 0x92, 0x12, 0x83, 0x6c, - 0x5d, 0x33, 0xcd, 0xa0, 0x07, 0x44, 0x2e, 0x2c, 0x85, 0xf9, 0xde, 0x0f, 0xd7, 0xed, 0x13, 0x6b, - 0x52, 0x83, 0xe8, 0xb2, 0x2c, 0x5d, 0x17, 0x3b, 0xfe, 0xdb, 0x6f, 0x0b, 0x57, 0xfb, 0x94, 0x0f, - 0x86, 0xbd, 0x8a, 0xee, 0x58, 0xc1, 0x2b, 0x4e, 0xf0, 0xef, 0x1a, 0x33, 0x0e, 0xab, 0x7c, 0xec, - 0x12, 0x16, 0xca, 0xb0, 0xdf, 0xfc, 0xe3, 0x77, 0x57, 0x14, 0x35, 0x9c, 0xa6, 0x64, 0x40, 0x36, - 0xba, 0x83, 0x10, 0x8e, 0x0d, 0xcc, 0x31, 0x42, 0x90, 0xb4, 0xb1, 0x15, 0x36, 0x99, 0xf2, 0x7b, - 0x86, 0x1e, 0x73, 0x0b, 0x52, 0x56, 0xa0, 0x21, 0xb8, 0x75, 0x44, 0xe3, 0xd2, 0x4f, 0x17, 0xa1, - 0x18, 0x4e, 0xd3, 0xf2, 0xdf, 0x66, 0xe8, 0x8f, 0xfd, 0x16, 0x5c, 0x74, 0x4e, 0xa2, 0x7e, 0xb3, - 0x13, 0xde, 0x7b, 0x94, 0xb7, 0xf3, 0xde, 0x33, 0xff, 0xca, 0xf7, 0x9e, 0xc4, 0x2b, 0xde, 0x7b, - 0x92, 0x6f, 0xef, 0xbd, 0x67, 0xe1, 0xad, 0xbf, 0xf7, 0x2c, 0xbe, 0xa3, 0xf7, 0x9e, 0xa5, 0xff, - 0xc9, 0x7b, 0x4f, 0xea, 0xad, 0xbe, 0xf7, 0xa4, 0xdf, 0xec, 0xbd, 0x07, 0xde, 0xe8, 0xbd, 0x27, - 0x33, 0xd3, 0x7b, 0x4f, 0xe9, 0x17, 0xf3, 0xb0, 0x21, 0x6f, 0xd2, 0x9d, 0x01, 0x76, 0xc5, 0xe1, - 0x4e, 0x42, 0x20, 0xba, 0x9e, 0x2b, 0x33, 0x5c, 0xcf, 0xe7, 0x5f, 0xef, 0x7a, 0x9e, 0x98, 0xe1, - 0x7a, 0x9e, 0x3c, 0xeb, 0x7a, 0xbe, 0x70, 0xd6, 0xf5, 0x7c, 0x71, 0xb6, 0xeb, 0xf9, 0xd2, 0x29, - 0xd7, 0xf3, 0x52, 0x01, 0x32, 0x51, 0x82, 0x30, 0x18, 0xca, 0x42, 0x82, 0x1a, 0x61, 0x43, 0x29, - 0x3e, 0x4b, 0x3b, 0x70, 0xa1, 0x16, 0x9a, 0x45, 0x8c, 0xf8, 0xed, 0x18, 0x6d, 0xc0, 0xa2, 0x7f, - 0x43, 0x0d, 0xf0, 0xc1, 0xe8, 0xca, 0x9f, 0x14, 0x58, 0x89, 0x1a, 0x81, 0x01, 0x66, 0x04, 0xe5, - 0x61, 0xab, 0xfe, 0x68, 0xaf, 0xf3, 0xf8, 0x61, 0x53, 0xd5, 0xda, 0x77, 0x6b, 0x9d, 0xa6, 0xf6, - 0x78, 0xaf, 0xd3, 0x6e, 0xd6, 0x5b, 0xb7, 0x5b, 0xcd, 0x46, 0x76, 0x0e, 0xbd, 0x0f, 0x9b, 0x47, - 0xf8, 0x6a, 0xf3, 0x4e, 0xab, 0xd3, 0x6d, 0xaa, 0xcd, 0x46, 0x56, 0x39, 0x41, 0xbc, 0xb5, 0xd7, - 0xea, 0xb6, 0x6a, 0x0f, 0x5a, 0x4f, 0x9a, 0x8d, 0xec, 0x3c, 0xba, 0x08, 0x17, 0x8e, 0xf0, 0x1f, - 0xd4, 0x1e, 0xef, 0xd5, 0xef, 0x36, 0x1b, 0xd9, 0x04, 0xda, 0x82, 0x8d, 0x23, 0xcc, 0x4e, 0xf7, - 0x51, 0xbb, 0xdd, 0x6c, 0x64, 0x93, 0x27, 0xf0, 0x1a, 0xcd, 0x07, 0xcd, 0x6e, 0xb3, 0x91, 0x5d, - 0xd8, 0x4a, 0x7e, 0xf6, 0xeb, 0xfc, 0xdc, 0xad, 0x4f, 0xbf, 0x7a, 0x91, 0x57, 0xbe, 0x7e, 0x91, - 0x57, 0xfe, 0xfe, 0x22, 0xaf, 0x7c, 0xfe, 0x32, 0x3f, 0xf7, 0xf5, 0xcb, 0xfc, 0xdc, 0xdf, 0x5e, - 0xe6, 0xe7, 0x9e, 0x7c, 0x72, 0x3c, 0xf9, 0x4f, 0x8a, 0xeb, 0xb5, 0xe8, 0xc7, 0x90, 0xd1, 0x77, - 0xab, 0xcf, 0xa7, 0x7f, 0x6a, 0x91, 0x75, 0xa1, 0xb7, 0x28, 0xe3, 0xfa, 0xe3, 0xff, 0x06, 0x00, - 0x00, 0xff, 0xff, 0x21, 0xa7, 0x53, 0x56, 0x9b, 0x19, 0x00, 0x00, + // 2280 bytes of a gzipped FileDescriptorProto + 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xbc, 0x59, 0xcd, 0x6f, 0x1b, 0xc7, + 0xd9, 0xd7, 0x8a, 0x94, 0x44, 0x0e, 0xf5, 0x41, 0x8d, 0x1d, 0x99, 0x92, 0x15, 0x92, 0xde, 0xbc, + 0x0e, 0xf8, 0xda, 0x35, 0x19, 0x29, 0x40, 0x61, 0xb8, 0x0d, 0x0c, 0x9a, 0xa4, 0x6d, 0xfa, 0x43, + 0x66, 0x97, 0xb4, 0x02, 0xb8, 0x87, 0xc5, 0x70, 0x77, 0x44, 0x4e, 0xb5, 0xbb, 0xb3, 0xde, 0x19, + 0xae, 0xcd, 0x1e, 0x7a, 0x0e, 0x0a, 0x14, 0x48, 0x6f, 0x41, 0x2f, 0x0d, 0xd0, 0x4b, 0xd1, 0x53, + 0x0f, 0x45, 0xfe, 0x80, 0x9e, 0xd2, 0x02, 0x05, 0xd2, 0x5b, 0x4f, 0x49, 0x61, 0x1f, 0x7a, 0x28, + 0xd0, 0x9e, 0x7b, 0x2b, 0x66, 0xf6, 0x83, 0x4b, 0x7d, 0x99, 0x86, 0xed, 0x5e, 0xa4, 0x9d, 0x79, + 0x7e, 0xcf, 0x33, 0xcf, 0x33, 0xf3, 0x7c, 0xcd, 0x10, 0xec, 0x12, 0x87, 0x63, 0xcf, 0x18, 0x22, + 0xe2, 0xe8, 0x0c, 0x1b, 0x23, 0x8f, 0xf0, 0x71, 0xcd, 0x30, 0xfc, 0x9a, 0xeb, 0x51, 0x9f, 0x98, + 0xd8, 0xab, 0xf9, 0x3b, 0xf1, 0x77, 0xd5, 0xf5, 0x28, 0xa7, 0xf0, 0x83, 0x13, 0x78, 0xaa, 0x86, + 0xe1, 0x57, 0x63, 0x9c, 0xbf, 0xb3, 0xb5, 0x8e, 0x6c, 0xe2, 0xd0, 0x9a, 0xfc, 0x1b, 0xf0, 0x6d, + 0x15, 0x0d, 0xca, 0x6c, 0xca, 0x6a, 0x7d, 0xc4, 0x70, 0xcd, 0xdf, 0xe9, 0x63, 0x8e, 0x76, 0x6a, + 0x06, 0x25, 0x4e, 0x48, 0xff, 0x30, 0xa4, 0x63, 0x21, 0xc4, 0x31, 0x26, 0x98, 0x68, 0x22, 0xc4, + 0x6d, 0x06, 0x38, 0x5d, 0x8e, 0x6a, 0xc1, 0x20, 0x24, 0x9d, 0x1f, 0xd0, 0x01, 0x0d, 0xe6, 0xc5, + 0x57, 0xb4, 0xf0, 0x80, 0xd2, 0x81, 0x85, 0x6b, 0x72, 0xd4, 0x1f, 0x1d, 0xd4, 0xcc, 0x91, 0x87, + 0x38, 0xa1, 0xd1, 0xc2, 0xa5, 0xa3, 0x74, 0x4e, 0x6c, 0xcc, 0x38, 0xb2, 0xdd, 0x08, 0x40, 0xfa, + 0x46, 0xcd, 0xa0, 0x1e, 0xae, 0x19, 0x16, 0xc1, 0x0e, 0x17, 0x9b, 0x12, 0x7c, 0x85, 0x80, 0x9a, + 0x00, 0x58, 0x64, 0x30, 0xe4, 0xc1, 0x34, 0xab, 0x71, 0xec, 0x98, 0xd8, 0xb3, 0x49, 0x00, 0x9e, + 0x8c, 0x42, 0x86, 0xcb, 0xa7, 0xed, 0xbb, 0xbf, 0x53, 0x7b, 0x46, 0xbc, 0xc8, 0xd4, 0xed, 0x84, + 0x18, 0xc3, 0x1b, 0xbb, 0x9c, 0xd6, 0x0e, 0xf1, 0x38, 0xb4, 0x56, 0xfd, 0x4f, 0x06, 0x14, 0x1a, + 0xd4, 0x61, 0x23, 0x1b, 0x7b, 0x75, 0xd3, 0x24, 0xc2, 0xa4, 0x8e, 0x47, 0x5d, 0xca, 0x90, 0x05, + 0xcf, 0x83, 0x05, 0x4e, 0xb8, 0x85, 0x0b, 0x4a, 0x59, 0xa9, 0x64, 0xb5, 0x60, 0x00, 0xcb, 0x20, + 0x67, 0x62, 0x66, 0x78, 0xc4, 0x15, 0xe0, 0xc2, 0xbc, 0xa4, 0x25, 0xa7, 0xe0, 0x26, 0xc8, 0x04, + 0x6a, 0x11, 0xb3, 0x90, 0x92, 0xe4, 0x25, 0x39, 0x6e, 0x9b, 0xf0, 0x0e, 0x58, 0x25, 0x0e, 0xe1, + 0x04, 0x59, 0xfa, 0x10, 0x0b, 0x63, 0x0b, 0xe9, 0xb2, 0x52, 0xc9, 0xed, 0x6e, 0x55, 0x49, 0xdf, + 0xa8, 0x8a, 0xfd, 0xa9, 0x86, 0xbb, 0xe2, 0xef, 0x54, 0xef, 0x4a, 0xc4, 0xad, 0xf4, 0xd7, 0xdf, + 0x96, 0xe6, 0xb4, 0x95, 0x90, 0x2f, 0x98, 0x84, 0x97, 0xc0, 0xf2, 0x00, 0x3b, 0x98, 0x11, 0xa6, + 0x0f, 0x11, 0x1b, 0x16, 0x16, 0xca, 0x4a, 0x65, 0x59, 0xcb, 0x85, 0x73, 0x77, 0x11, 0x1b, 0xc2, + 0x12, 0xc8, 0xf5, 0x89, 0x83, 0xbc, 0x71, 0x80, 0x58, 0x94, 0x08, 0x10, 0x4c, 0x49, 0x40, 0x03, + 0x00, 0xe6, 0xa2, 0x67, 0x8e, 0x2e, 0x0e, 0xab, 0xb0, 0x14, 0x2a, 0x12, 0x9c, 0x64, 0x35, 0x3a, + 0xc9, 0x6a, 0x2f, 0x3a, 0xc9, 0x5b, 0x19, 0xa1, 0xc8, 0xe7, 0xdf, 0x95, 0x14, 0x2d, 0x2b, 0xf9, + 0x04, 0x05, 0xee, 0x81, 0xfc, 0xc8, 0xe9, 0x53, 0xc7, 0x24, 0xce, 0x40, 0x77, 0xb1, 0x47, 0xa8, + 0x59, 0xc8, 0x48, 0x51, 0x9b, 0xc7, 0x44, 0x35, 0x43, 0xa7, 0x09, 0x24, 0x7d, 0x21, 0x24, 0xad, + 0xc5, 0xcc, 0x1d, 0xc9, 0x0b, 0x7f, 0x04, 0xa0, 0x61, 0xf8, 0x52, 0x25, 0x3a, 0xe2, 0x91, 0xc4, + 0xec, 0xec, 0x12, 0xf3, 0x86, 0xe1, 0xf7, 0x02, 0xee, 0x50, 0xe4, 0x8f, 0xc1, 0x05, 0xee, 0x21, + 0x87, 0x1d, 0x60, 0xef, 0xa8, 0x5c, 0x30, 0xbb, 0xdc, 0xf7, 0x22, 0x19, 0xd3, 0xc2, 0xef, 0x82, + 0xb2, 0x11, 0x3a, 0x90, 0xee, 0x61, 0x93, 0x30, 0xee, 0x91, 0xfe, 0x48, 0xf0, 0xea, 0x07, 0x1e, + 0x32, 0xa4, 0x8f, 0xe4, 0xa4, 0x13, 0x14, 0x23, 0x9c, 0x36, 0x05, 0xbb, 0x1d, 0xa2, 0xe0, 0x23, + 0xf0, 0x7f, 0x7d, 0x8b, 0x1a, 0x87, 0x4c, 0x28, 0xa7, 0x4f, 0x49, 0x92, 0x4b, 0xdb, 0x84, 0x31, + 0x21, 0x6d, 0xb9, 0xac, 0x54, 0x52, 0xda, 0xa5, 0x00, 0xdb, 0xc1, 0x5e, 0x33, 0x81, 0xec, 0x25, + 0x80, 0xf0, 0x1a, 0x80, 0x43, 0xc2, 0x38, 0xf5, 0x88, 0x81, 0x2c, 0x1d, 0x3b, 0xdc, 0x23, 0x98, + 0x15, 0x56, 0x24, 0xfb, 0xfa, 0x84, 0xd2, 0x0a, 0x08, 0xf0, 0x1e, 0xb8, 0x74, 0xea, 0xa2, 0xba, + 0x31, 0x44, 0x8e, 0x83, 0xad, 0xc2, 0xaa, 0x34, 0xa5, 0x64, 0x9e, 0xb2, 0x66, 0x23, 0x80, 0xc1, + 0x73, 0x60, 0x81, 0x53, 0x57, 0xdf, 0x2b, 0xac, 0x95, 0x95, 0xca, 0x8a, 0x96, 0xe6, 0xd4, 0xdd, + 0x83, 0x1f, 0x81, 0xf3, 0x3e, 0xb2, 0x88, 0x89, 0x38, 0xf5, 0x98, 0xee, 0xd2, 0x67, 0xd8, 0xd3, + 0x0d, 0xe4, 0x16, 0xf2, 0x12, 0x03, 0x27, 0xb4, 0x8e, 0x20, 0x35, 0x90, 0x0b, 0xaf, 0x80, 0xf5, + 0x78, 0x56, 0x67, 0x98, 0x4b, 0xf8, 0xba, 0x84, 0xaf, 0xc5, 0x84, 0x2e, 0xe6, 0x02, 0xbb, 0x0d, + 0xb2, 0xc8, 0xb2, 0xe8, 0x33, 0x8b, 0x30, 0x5e, 0x80, 0xe5, 0x54, 0x25, 0xab, 0x4d, 0x26, 0xe0, + 0x16, 0xc8, 0x98, 0xd8, 0x19, 0x4b, 0xe2, 0x39, 0x49, 0x8c, 0xc7, 0xf0, 0x22, 0xc8, 0xda, 0x22, + 0x89, 0x70, 0x74, 0x88, 0x0b, 0xe7, 0xcb, 0x4a, 0x25, 0xad, 0x65, 0x6c, 0xe2, 0x74, 0xc5, 0x18, + 0x56, 0xc1, 0x39, 0x29, 0x45, 0x27, 0x8e, 0x38, 0x27, 0x1f, 0xeb, 0x3e, 0xb2, 0x58, 0xe1, 0xbd, + 0xb2, 0x52, 0xc9, 0x68, 0xeb, 0x92, 0xd4, 0x0e, 0x29, 0xfb, 0xc8, 0x62, 0x37, 0x2a, 0x9f, 0x7d, + 0x59, 0x9a, 0xfb, 0xe2, 0xcb, 0xd2, 0xdc, 0x9f, 0xff, 0x70, 0x6d, 0x2b, 0xcc, 0xac, 0x03, 0xea, + 0x57, 0xc3, 0x4c, 0x5c, 0x6d, 0x50, 0x87, 0x63, 0x87, 0x17, 0x14, 0xf5, 0xaf, 0x0a, 0xb8, 0xd0, + 0x88, 0x5d, 0xc2, 0xa6, 0x3e, 0xb2, 0xde, 0x65, 0xea, 0xa9, 0x83, 0x2c, 0x13, 0x67, 0x22, 0x83, + 0x3d, 0xfd, 0x1a, 0xc1, 0x9e, 0x11, 0x6c, 0x82, 0x70, 0xa3, 0xfc, 0x4a, 0x9b, 0xfe, 0x3d, 0x0f, + 0xb6, 0x23, 0x9b, 0x1e, 0x52, 0x93, 0x1c, 0x10, 0x03, 0xbd, 0xeb, 0x9c, 0x1a, 0xfb, 0x5a, 0x7a, + 0x06, 0x5f, 0x5b, 0x78, 0x3d, 0x5f, 0x5b, 0x9c, 0xc1, 0xd7, 0x96, 0xce, 0xf2, 0xb5, 0xcc, 0x59, + 0xbe, 0x96, 0x9d, 0xcd, 0xd7, 0xc0, 0x69, 0xbe, 0x36, 0x5f, 0x50, 0xd4, 0x5f, 0x2b, 0xe0, 0x7c, + 0xeb, 0xe9, 0x88, 0xf8, 0xf4, 0x2d, 0xed, 0xf4, 0x7d, 0xb0, 0x82, 0x13, 0xf2, 0x58, 0x21, 0x55, + 0x4e, 0x55, 0x72, 0xbb, 0x97, 0xab, 0xe1, 0xc1, 0xc7, 0xad, 0x44, 0x74, 0xfa, 0xc9, 0xd5, 0xb5, + 0x69, 0x5e, 0xa9, 0xe1, 0x1f, 0x15, 0xb0, 0x25, 0xf2, 0xc2, 0x00, 0x6b, 0xf8, 0x19, 0xf2, 0xcc, + 0x26, 0x76, 0xa8, 0xcd, 0xde, 0x58, 0x4f, 0x15, 0xac, 0x98, 0x52, 0x92, 0xce, 0xa9, 0x8e, 0x4c, + 0x53, 0xea, 0x29, 0x31, 0x62, 0xb2, 0x47, 0xeb, 0xa6, 0x09, 0x2b, 0x20, 0x3f, 0xc1, 0x78, 0x22, + 0xc6, 0x84, 0xeb, 0x0b, 0xd8, 0x6a, 0x04, 0x93, 0x91, 0x87, 0x6f, 0x14, 0xcf, 0x76, 0x6d, 0xf5, + 0x9f, 0x0a, 0xc8, 0xdf, 0xb1, 0x68, 0x1f, 0x59, 0x5d, 0x0b, 0xb1, 0xa1, 0xc8, 0x99, 0x63, 0x11, + 0x52, 0x1e, 0x0e, 0x8b, 0x95, 0x54, 0x7f, 0xe6, 0x90, 0x12, 0x6c, 0xb2, 0x7c, 0xde, 0x04, 0xeb, + 0x71, 0xf9, 0x88, 0x1d, 0x5c, 0x5a, 0x7b, 0xeb, 0xdc, 0x8b, 0x6f, 0x4b, 0x6b, 0x51, 0x30, 0x35, + 0xa4, 0xb3, 0x37, 0xb5, 0x35, 0x63, 0x6a, 0xc2, 0x84, 0x45, 0x90, 0x23, 0x7d, 0x43, 0x67, 0xf8, + 0xa9, 0xee, 0x8c, 0x6c, 0x19, 0x1b, 0x69, 0x2d, 0x4b, 0xfa, 0x46, 0x17, 0x3f, 0xdd, 0x1b, 0xd9, + 0xf0, 0x63, 0xb0, 0x11, 0x35, 0x95, 0xc2, 0x9b, 0x74, 0xc1, 0x2f, 0xb6, 0xcb, 0x93, 0xe1, 0xb2, + 0xac, 0x9d, 0x8b, 0xa8, 0xfb, 0xc8, 0x12, 0x8b, 0xd5, 0x4d, 0xd3, 0x53, 0xff, 0xb5, 0x00, 0x16, + 0x3b, 0xc8, 0x43, 0x36, 0x83, 0x3d, 0xb0, 0xc6, 0xb1, 0xed, 0x5a, 0x88, 0x63, 0x3d, 0x68, 0x4d, + 0x42, 0x4b, 0xaf, 0xca, 0x96, 0x25, 0xd9, 0xb1, 0x55, 0x13, 0x3d, 0x9a, 0xbf, 0x53, 0x6d, 0xc8, + 0xd9, 0x2e, 0x47, 0x1c, 0x6b, 0xab, 0x91, 0x8c, 0x60, 0x12, 0x5e, 0x07, 0x05, 0xee, 0x8d, 0x18, + 0x9f, 0x34, 0x0d, 0x93, 0x6a, 0x19, 0x9c, 0xf5, 0x46, 0x44, 0x0f, 0xea, 0x6c, 0x5c, 0x25, 0x4f, + 0xee, 0x0f, 0x52, 0x6f, 0xd2, 0x1f, 0x98, 0x60, 0x9b, 0x89, 0x43, 0xd5, 0x6d, 0xcc, 0x65, 0x15, + 0x77, 0x2d, 0xec, 0x10, 0x36, 0x8c, 0x84, 0x2f, 0xce, 0x2e, 0x7c, 0x53, 0x0a, 0x7a, 0x28, 0xe4, + 0x68, 0x91, 0x98, 0x70, 0x95, 0x06, 0x28, 0x9e, 0xbc, 0x4a, 0x6c, 0xf8, 0x92, 0x34, 0xfc, 0xe2, + 0x09, 0x22, 0x62, 0xeb, 0x19, 0xf8, 0x30, 0xd1, 0x6d, 0x88, 0x68, 0xd2, 0xa5, 0x23, 0xeb, 0x1e, + 0x1e, 0x88, 0x92, 0x8c, 0x82, 0xc6, 0x03, 0xe3, 0xb8, 0x63, 0x0a, 0x7d, 0x5a, 0xdc, 0x18, 0x12, + 0x4e, 0x4d, 0x9c, 0xb0, 0xad, 0x54, 0x27, 0x4d, 0x49, 0x1c, 0x9b, 0x5a, 0x42, 0xd6, 0x6d, 0x8c, + 0x45, 0x14, 0x25, 0x1a, 0x13, 0xec, 0x52, 0x63, 0x28, 0x73, 0x52, 0x4a, 0x5b, 0x8d, 0x9b, 0x90, + 0x96, 0x98, 0x85, 0x4f, 0xc0, 0x55, 0x67, 0x64, 0xf7, 0xb1, 0xa7, 0xd3, 0x83, 0x00, 0x28, 0x23, + 0x8f, 0x71, 0xe4, 0x71, 0xdd, 0xc3, 0x06, 0x26, 0xbe, 0x38, 0xf1, 0x40, 0x73, 0x26, 0xfb, 0xa2, + 0x94, 0x76, 0x39, 0x60, 0x79, 0x74, 0x20, 0x65, 0xb0, 0x1e, 0xed, 0x0a, 0xb8, 0x16, 0xa1, 0x03, + 0xc5, 0x18, 0x6c, 0x83, 0x4b, 0x36, 0x7a, 0xae, 0xc7, 0xce, 0x2c, 0x14, 0xc7, 0x0e, 0x1b, 0x31, + 0x7d, 0x92, 0xcc, 0xc3, 0xde, 0xa8, 0x68, 0xa3, 0xe7, 0x9d, 0x10, 0xd7, 0x88, 0x60, 0xfb, 0x31, + 0xea, 0x5e, 0x3a, 0x93, 0xce, 0x2f, 0xdc, 0x4b, 0x67, 0x16, 0xf2, 0x8b, 0xf7, 0xd2, 0x99, 0x4c, + 0x3e, 0xab, 0xfe, 0x3f, 0xc8, 0xca, 0xb8, 0xae, 0x1b, 0x87, 0x4c, 0x66, 0x77, 0xd3, 0xf4, 0x30, + 0x63, 0x98, 0x15, 0x94, 0x30, 0xbb, 0x47, 0x13, 0x2a, 0x07, 0x9b, 0xa7, 0xdd, 0x18, 0x18, 0xfc, + 0x14, 0x2c, 0xb9, 0x58, 0xb6, 0xb3, 0x92, 0x31, 0xb7, 0xfb, 0x49, 0x75, 0x86, 0xab, 0x5e, 0xf5, + 0x34, 0x81, 0x5a, 0x24, 0x4d, 0xf5, 0x26, 0xf7, 0x94, 0x23, 0xbd, 0x02, 0x83, 0xfb, 0x47, 0x17, + 0xfd, 0xe1, 0x6b, 0x2d, 0x7a, 0x44, 0xde, 0x64, 0xcd, 0xab, 0x20, 0x57, 0x0f, 0xcc, 0x7e, 0x20, + 0x4a, 0xd7, 0xb1, 0x6d, 0x59, 0x4e, 0x6e, 0xcb, 0x1e, 0x58, 0x0d, 0x9b, 0xbf, 0x1e, 0x95, 0xb9, + 0x09, 0xbe, 0x0f, 0x40, 0xd8, 0x35, 0x8a, 0x9c, 0x16, 0x64, 0xf7, 0x6c, 0x38, 0xd3, 0x36, 0xa7, + 0x2a, 0xfa, 0xfc, 0x54, 0x45, 0x97, 0x55, 0x83, 0x82, 0xcd, 0xfd, 0x64, 0xd5, 0x95, 0x05, 0xa4, + 0x83, 0x8c, 0x43, 0xcc, 0x19, 0xd4, 0x40, 0x5a, 0x56, 0xd7, 0xc0, 0xdc, 0xeb, 0xa7, 0x9a, 0xeb, + 0xef, 0x54, 0x4f, 0x13, 0xd2, 0x44, 0x1c, 0x85, 0x31, 0x20, 0x65, 0xa9, 0xbf, 0x54, 0x40, 0xe1, + 0x3e, 0x1e, 0xd7, 0x19, 0x23, 0x03, 0xc7, 0xc6, 0x0e, 0x17, 0xd1, 0x87, 0x0c, 0x2c, 0x3e, 0xe1, + 0x07, 0x60, 0x25, 0x76, 0x3c, 0x99, 0x3c, 0x15, 0x99, 0x3c, 0x97, 0xa3, 0x49, 0xb1, 0x4f, 0xf0, + 0x06, 0x00, 0xae, 0x87, 0x7d, 0xdd, 0xd0, 0x0f, 0xf1, 0x58, 0xda, 0x94, 0xdb, 0xdd, 0x4e, 0x26, + 0xc5, 0xe0, 0xfe, 0x59, 0xed, 0x8c, 0xfa, 0x16, 0x31, 0xee, 0xe3, 0xb1, 0x96, 0x11, 0xf8, 0xc6, + 0x7d, 0x3c, 0x16, 0x55, 0x50, 0x36, 0x29, 0x32, 0x93, 0xa5, 0xb4, 0x60, 0xa0, 0xfe, 0x4a, 0x01, + 0x17, 0x62, 0x03, 0xa2, 0xf3, 0xea, 0x8c, 0xfa, 0x82, 0x23, 0xb9, 0x7f, 0xca, 0x74, 0x47, 0x74, + 0x4c, 0xdb, 0xf9, 0x13, 0xb4, 0xbd, 0x09, 0x96, 0xe3, 0x54, 0x22, 0xf4, 0x4d, 0xcd, 0xa0, 0x6f, + 0x2e, 0xe2, 0xb8, 0x8f, 0xc7, 0xea, 0xcf, 0x12, 0xba, 0xdd, 0x1a, 0x27, 0x5c, 0xd8, 0x7b, 0x85, + 0x6e, 0xf1, 0xb2, 0x49, 0xdd, 0x8c, 0x24, 0xff, 0x31, 0x03, 0x52, 0xc7, 0x0d, 0x50, 0xff, 0xa2, + 0x80, 0x8d, 0xe4, 0xaa, 0xac, 0x47, 0x3b, 0xde, 0xc8, 0xc1, 0xfb, 0xbb, 0x67, 0xad, 0x7f, 0x13, + 0x64, 0x5c, 0x81, 0xd2, 0x39, 0x0b, 0x8f, 0x68, 0xb6, 0x92, 0xbd, 0x24, 0xb9, 0x7a, 0x22, 0xc4, + 0x57, 0xa7, 0x0c, 0x60, 0xe1, 0xce, 0x7d, 0x34, 0x53, 0xd0, 0x25, 0x02, 0x4a, 0x5b, 0x49, 0xda, + 0xcc, 0xd4, 0xaf, 0x14, 0x00, 0x8f, 0x67, 0x2b, 0xf8, 0x3d, 0x00, 0xa7, 0x72, 0x5e, 0xd2, 0xff, + 0xf2, 0x6e, 0x22, 0xcb, 0xc9, 0x9d, 0x8b, 0xfd, 0x68, 0x3e, 0xe1, 0x47, 0xf0, 0x07, 0x00, 0xb8, + 0xf2, 0x10, 0x67, 0x3e, 0xe9, 0xac, 0x1b, 0x7d, 0xc2, 0x12, 0xc8, 0xfd, 0x84, 0x12, 0x27, 0xf9, + 0x60, 0x91, 0xd2, 0x80, 0x98, 0x0a, 0xde, 0x22, 0xd4, 0x5f, 0x28, 0x93, 0x94, 0x18, 0x66, 0xeb, + 0xba, 0x65, 0x85, 0x3d, 0x20, 0x74, 0xc1, 0x52, 0x94, 0xef, 0x83, 0x70, 0xdd, 0x3e, 0xb1, 0x26, + 0x35, 0xb1, 0x21, 0xcb, 0xd2, 0x75, 0xb1, 0xe3, 0xbf, 0xfb, 0xae, 0x74, 0x75, 0x40, 0xf8, 0x70, + 0xd4, 0xaf, 0x1a, 0xd4, 0x0e, 0x1f, 0xa8, 0xc2, 0x7f, 0xd7, 0x98, 0x79, 0x58, 0xe3, 0x63, 0x17, + 0xb3, 0x88, 0x87, 0xfd, 0xf6, 0x1f, 0xbf, 0xbf, 0xa2, 0x68, 0xd1, 0x32, 0xaa, 0x09, 0xf2, 0xf1, + 0x1d, 0x04, 0x73, 0x64, 0x22, 0x8e, 0x20, 0x04, 0x69, 0x07, 0xd9, 0x51, 0x93, 0x29, 0xbf, 0x67, + 0xe8, 0x31, 0xb7, 0x40, 0xc6, 0x0e, 0x25, 0x84, 0xb7, 0x8e, 0x78, 0xac, 0xfe, 0x7c, 0x11, 0x94, + 0xa3, 0x65, 0xda, 0xc1, 0xdb, 0x0c, 0xf9, 0x69, 0xd0, 0x82, 0x8b, 0xce, 0x49, 0xd4, 0x6f, 0x76, + 0xc2, 0x7b, 0x8f, 0xf2, 0x76, 0xde, 0x7b, 0xe6, 0x5f, 0xf9, 0xde, 0x93, 0x7a, 0xc5, 0x7b, 0x4f, + 0xfa, 0xed, 0xbd, 0xf7, 0x2c, 0xbc, 0xf5, 0xf7, 0x9e, 0xc5, 0x77, 0xf4, 0xde, 0xb3, 0xf4, 0x3f, + 0x79, 0xef, 0xc9, 0xbc, 0xd5, 0xf7, 0x9e, 0xec, 0x9b, 0xbd, 0xf7, 0x80, 0x37, 0x7a, 0xef, 0xc9, + 0xcd, 0xf4, 0xde, 0xa3, 0x7e, 0x35, 0x0f, 0x36, 0xe4, 0x4d, 0xba, 0x3b, 0x44, 0xae, 0x38, 0xdc, + 0x49, 0x08, 0xc4, 0xd7, 0x73, 0x65, 0x86, 0xeb, 0xf9, 0xfc, 0xeb, 0x5d, 0xcf, 0x53, 0x33, 0x5c, + 0xcf, 0xd3, 0x67, 0x5d, 0xcf, 0x17, 0xce, 0xba, 0x9e, 0x2f, 0xce, 0x76, 0x3d, 0x5f, 0x3a, 0xe5, + 0x7a, 0x0e, 0x55, 0xb0, 0xec, 0x7a, 0x84, 0x8a, 0x3a, 0x90, 0x78, 0x0b, 0x98, 0x9a, 0x53, 0x4b, + 0x20, 0x17, 0x27, 0x11, 0x93, 0xc1, 0x3c, 0x48, 0x11, 0x33, 0x6a, 0x3a, 0xc5, 0xa7, 0xba, 0x03, + 0x2e, 0xd4, 0x23, 0xd5, 0xb1, 0x99, 0xbc, 0x41, 0xc3, 0x0d, 0xb0, 0x18, 0xdc, 0x62, 0x43, 0x7c, + 0x38, 0xba, 0xf2, 0x27, 0x05, 0xac, 0xc4, 0xcd, 0xc2, 0x10, 0x31, 0x0c, 0x8b, 0x60, 0xab, 0xf1, + 0x68, 0xaf, 0xfb, 0xf8, 0x61, 0x4b, 0xd3, 0x3b, 0x77, 0xeb, 0xdd, 0x96, 0xfe, 0x78, 0xaf, 0xdb, + 0x69, 0x35, 0xda, 0xb7, 0xdb, 0xad, 0x66, 0x7e, 0x0e, 0xbe, 0x0f, 0x36, 0x8f, 0xd0, 0xb5, 0xd6, + 0x9d, 0x76, 0xb7, 0xd7, 0xd2, 0x5a, 0xcd, 0xbc, 0x72, 0x02, 0x7b, 0x7b, 0xaf, 0xdd, 0x6b, 0xd7, + 0x1f, 0xb4, 0x9f, 0xb4, 0x9a, 0xf9, 0x79, 0x78, 0x11, 0x5c, 0x38, 0x42, 0x7f, 0x50, 0x7f, 0xbc, + 0xd7, 0xb8, 0xdb, 0x6a, 0xe6, 0x53, 0x70, 0x0b, 0x6c, 0x1c, 0x21, 0x76, 0x7b, 0x8f, 0x3a, 0x9d, + 0x56, 0x33, 0x9f, 0x3e, 0x81, 0xd6, 0x6c, 0x3d, 0x68, 0xf5, 0x5a, 0xcd, 0xfc, 0xc2, 0x56, 0xfa, + 0xb3, 0xdf, 0x14, 0xe7, 0x6e, 0x7d, 0xfa, 0xf5, 0x8b, 0xa2, 0xf2, 0xcd, 0x8b, 0xa2, 0xf2, 0xf7, + 0x17, 0x45, 0xe5, 0xf3, 0x97, 0xc5, 0xb9, 0x6f, 0x5e, 0x16, 0xe7, 0xfe, 0xf6, 0xb2, 0x38, 0xf7, + 0xe4, 0x93, 0xe3, 0x05, 0x62, 0x52, 0x80, 0xaf, 0xc5, 0xbf, 0x08, 0xf8, 0xdf, 0xaf, 0x3d, 0x9f, + 0xfe, 0x39, 0x46, 0xd6, 0x8e, 0xfe, 0xa2, 0x8c, 0xfd, 0x8f, 0xff, 0x1b, 0x00, 0x00, 0xff, 0xff, + 0x15, 0xc3, 0x5a, 0xbf, 0xbf, 0x19, 0x00, 0x00, } func (m *ConsumerAdditionProposal) Marshal() (dAtA []byte, err error) { @@ -3284,6 +3297,15 @@ func (m *PowerShapingParameters) MarshalToSizedBuffer(dAtA []byte) (int, error) _ = i var l int _ = l + if len(m.Prioritylist) > 0 { + for iNdEx := len(m.Prioritylist) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Prioritylist[iNdEx]) + copy(dAtA[i:], m.Prioritylist[iNdEx]) + i = encodeVarintProvider(dAtA, i, uint64(len(m.Prioritylist[iNdEx]))) + i-- + dAtA[i] = 0x42 + } + } if m.AllowInactiveVals { i-- if m.AllowInactiveVals { @@ -3977,6 +3999,12 @@ func (m *PowerShapingParameters) Size() (n int) { if m.AllowInactiveVals { n += 2 } + if len(m.Prioritylist) > 0 { + for _, s := range m.Prioritylist { + l = len(s) + n += 1 + l + sovProvider(uint64(l)) + } + } return n } @@ -8026,6 +8054,38 @@ func (m *PowerShapingParameters) Unmarshal(dAtA []byte) error { } } m.AllowInactiveVals = bool(v != 0) + case 8: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Prioritylist", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowProvider + } + 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 ErrInvalidLengthProvider + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthProvider + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Prioritylist = append(m.Prioritylist, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipProvider(dAtA[iNdEx:]) diff --git a/x/ccv/provider/types/query.pb.go b/x/ccv/provider/types/query.pb.go index 578c12598e..f486a07b57 100644 --- a/x/ccv/provider/types/query.pb.go +++ b/x/ccv/provider/types/query.pb.go @@ -261,6 +261,11 @@ type Chain struct { ConsumerId string `protobuf:"bytes,13,opt,name=consumer_id,json=consumerId,proto3" json:"consumer_id,omitempty"` // the reward denoms allowlisted by this consumer chain AllowlistedRewardDenoms *AllowlistedRewardDenoms `protobuf:"bytes,14,opt,name=allowlisted_reward_denoms,json=allowlistedRewardDenoms,proto3" json:"allowlisted_reward_denoms,omitempty"` + // Corresponds to a list of provider consensus addresses of validators that should have PRIORITY to validate on the consumer chain, + // meaning as long as they are eligible/opted in to validate on the consumer chain, the validator set will be + // filled with these validators first, and other validators will be added to the validator set only if there are + // not enough eligible priority validators. + Prioritylist []string `protobuf:"bytes,15,rep,name=prioritylist,proto3" json:"prioritylist,omitempty"` } func (m *Chain) Reset() { *m = Chain{} } @@ -394,6 +399,13 @@ func (m *Chain) GetAllowlistedRewardDenoms() *AllowlistedRewardDenoms { return nil } +func (m *Chain) GetPrioritylist() []string { + if m != nil { + return m.Prioritylist + } + return nil +} + type QueryValidatorConsumerAddrRequest struct { // The consensus address of the validator on the provider chain ProviderAddress string `protobuf:"bytes,1,opt,name=provider_address,json=providerAddress,proto3" json:"provider_address,omitempty" yaml:"address"` @@ -1857,161 +1869,162 @@ func init() { } var fileDescriptor_422512d7b7586cd7 = []byte{ - // 2450 bytes of a gzipped FileDescriptorProto + // 2465 bytes of a gzipped FileDescriptorProto 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0xac, 0x5a, 0xcd, 0x6f, 0xdc, 0xc6, 0x15, 0x17, 0x57, 0x1f, 0x5e, 0x8d, 0x2c, 0x39, 0x1e, 0xcb, 0xd6, 0x7a, 0x65, 0x6b, 0x65, 0x3a, 0x6e, 0x15, 0x39, 0x5e, 0x4a, 0x2a, 0xf2, 0xe5, 0xc4, 0x1f, 0x5a, 0x59, 0xb2, 0x05, 0xc7, 0xb6, 0x42, 0x29, 0x0e, 0xe0, 0xd4, 0x65, 0x47, 0xe4, 0x64, 0x35, 0x15, 0x97, 0xa4, 0x39, 0xa3, 0xb5, - 0xb7, 0x86, 0x2f, 0x3d, 0xe5, 0xd0, 0x02, 0x09, 0x8a, 0x9e, 0x9b, 0x73, 0x0f, 0x45, 0x51, 0x04, - 0xfd, 0x07, 0x7a, 0xc9, 0xad, 0x69, 0x7a, 0x29, 0x5a, 0xd4, 0x6d, 0xed, 0x16, 0xe8, 0xa5, 0x28, - 0x9a, 0xf6, 0x0f, 0x08, 0x66, 0x38, 0xe4, 0x2e, 0x69, 0x4a, 0x4b, 0x6a, 0x75, 0x13, 0x67, 0xde, - 0xfb, 0xbd, 0x8f, 0x79, 0xf3, 0xe6, 0xbd, 0xb7, 0x02, 0x1a, 0x71, 0x18, 0xf6, 0xcd, 0x2d, 0x44, - 0x1c, 0x83, 0x62, 0x73, 0xc7, 0x27, 0xac, 0xa5, 0x99, 0x66, 0x53, 0xf3, 0x7c, 0xb7, 0x49, 0x2c, - 0xec, 0x6b, 0xcd, 0x79, 0xed, 0xc1, 0x0e, 0xf6, 0x5b, 0x55, 0xcf, 0x77, 0x99, 0x0b, 0xcf, 0xa6, - 0x30, 0x54, 0x4d, 0xb3, 0x59, 0x0d, 0x19, 0xaa, 0xcd, 0xf9, 0xf2, 0xa9, 0xba, 0xeb, 0xd6, 0x6d, - 0xac, 0x21, 0x8f, 0x68, 0xc8, 0x71, 0x5c, 0x86, 0x18, 0x71, 0x1d, 0x1a, 0x40, 0x94, 0xc7, 0xeb, - 0x6e, 0xdd, 0x15, 0x7f, 0x6a, 0xfc, 0x2f, 0xb9, 0x5a, 0x91, 0x3c, 0xe2, 0x6b, 0x73, 0xe7, 0x23, - 0x8d, 0x91, 0x06, 0xa6, 0x0c, 0x35, 0x3c, 0x49, 0xb0, 0x90, 0x45, 0xd5, 0x48, 0x8b, 0x80, 0x67, - 0x6e, 0x37, 0x9e, 0xe6, 0xbc, 0x46, 0xb7, 0x90, 0x8f, 0x2d, 0xc3, 0x74, 0x1d, 0xba, 0xd3, 0x88, - 0x38, 0xce, 0xed, 0xc1, 0xf1, 0x90, 0xf8, 0x58, 0x92, 0x9d, 0x62, 0xd8, 0xb1, 0xb0, 0xdf, 0x20, - 0x0e, 0xd3, 0x4c, 0xbf, 0xe5, 0x31, 0x57, 0xdb, 0xc6, 0xad, 0xd0, 0xc2, 0x93, 0xa6, 0x4b, 0x1b, - 0x2e, 0x35, 0x02, 0x23, 0x83, 0x0f, 0xb9, 0xf5, 0x72, 0xf0, 0xa5, 0x51, 0x86, 0xb6, 0x89, 0x53, - 0xd7, 0x9a, 0xf3, 0x9b, 0x98, 0xa1, 0xf9, 0xf0, 0x5b, 0x52, 0xcd, 0x4a, 0xaa, 0x4d, 0x44, 0x71, - 0xe0, 0xfe, 0x88, 0xd0, 0x43, 0x75, 0xe2, 0x08, 0x7f, 0x06, 0xb4, 0xea, 0x65, 0x30, 0xf9, 0x1e, - 0xa7, 0x58, 0x92, 0x86, 0x5c, 0xc7, 0x0e, 0xa6, 0x84, 0xea, 0xf8, 0xc1, 0x0e, 0xa6, 0x0c, 0x56, - 0xc0, 0x48, 0x68, 0xa2, 0x41, 0xac, 0x92, 0x32, 0xad, 0xcc, 0x0c, 0xeb, 0x20, 0x5c, 0x5a, 0xb5, - 0xd4, 0xc7, 0xe0, 0x54, 0x3a, 0x3f, 0xf5, 0x5c, 0x87, 0x62, 0xf8, 0x21, 0x18, 0xad, 0x07, 0x4b, - 0x06, 0x65, 0x88, 0x61, 0x01, 0x31, 0xb2, 0x30, 0x57, 0xdd, 0x2d, 0x12, 0x9a, 0xf3, 0xd5, 0x04, - 0xd6, 0x3a, 0xe7, 0xab, 0x0d, 0x7c, 0xf1, 0xb4, 0xd2, 0xa7, 0x1f, 0xae, 0x77, 0xac, 0xa9, 0xbf, - 0x54, 0x40, 0x39, 0x26, 0x7d, 0x89, 0xe3, 0x45, 0xca, 0xdf, 0x00, 0x83, 0xde, 0x16, 0xa2, 0x81, - 0xcc, 0xb1, 0x85, 0x85, 0x6a, 0x86, 0xe8, 0x8b, 0x84, 0xaf, 0x71, 0x4e, 0x3d, 0x00, 0x80, 0x2b, - 0x00, 0xb4, 0x3d, 0x57, 0x2a, 0x08, 0x13, 0xbe, 0x55, 0x95, 0x47, 0xc3, 0xdd, 0x5c, 0x0d, 0xa2, - 0x5c, 0xba, 0xb9, 0xba, 0x86, 0xea, 0x58, 0x6a, 0xa1, 0x77, 0x70, 0xaa, 0xbf, 0x50, 0x12, 0xee, - 0x0e, 0x15, 0x96, 0xde, 0xaa, 0x81, 0x21, 0xa1, 0x1e, 0x2d, 0x29, 0xd3, 0xfd, 0x33, 0x23, 0x0b, - 0xb3, 0xd9, 0x54, 0xe6, 0xdb, 0xba, 0xe4, 0x84, 0xd7, 0x53, 0x74, 0xfd, 0x76, 0x57, 0x5d, 0x03, - 0x05, 0x62, 0xca, 0xfe, 0x67, 0x00, 0x0c, 0x0a, 0x68, 0x78, 0x12, 0x14, 0x03, 0x15, 0xa2, 0x10, - 0x38, 0x24, 0xbe, 0x57, 0x2d, 0x38, 0x09, 0x86, 0x4d, 0x9b, 0x60, 0x87, 0xf1, 0xbd, 0x82, 0xd8, - 0x2b, 0x06, 0x0b, 0xab, 0x16, 0x3c, 0x06, 0x06, 0x99, 0xeb, 0x19, 0xb7, 0x4b, 0xfd, 0xd3, 0xca, - 0xcc, 0xa8, 0x3e, 0xc0, 0x5c, 0xef, 0x36, 0x9c, 0x05, 0xb0, 0x41, 0x1c, 0xc3, 0x73, 0x1f, 0xf2, - 0x98, 0x72, 0x8c, 0x80, 0x62, 0x60, 0x5a, 0x99, 0xe9, 0xd7, 0xc7, 0x1a, 0xc4, 0x59, 0xe3, 0x1b, - 0xab, 0xce, 0x06, 0xa7, 0x9d, 0x03, 0xe3, 0x4d, 0x64, 0x13, 0x0b, 0x31, 0xd7, 0xa7, 0x92, 0xc5, - 0x44, 0x5e, 0x69, 0x50, 0xe0, 0xc1, 0xf6, 0x9e, 0x60, 0x5a, 0x42, 0x1e, 0x9c, 0x05, 0x47, 0xa3, - 0x55, 0x83, 0x62, 0x26, 0xc8, 0x87, 0x04, 0xf9, 0x91, 0x68, 0x63, 0x1d, 0x33, 0x4e, 0x7b, 0x0a, - 0x0c, 0x23, 0xdb, 0x76, 0x1f, 0xda, 0x84, 0xb2, 0xd2, 0xa1, 0xe9, 0xfe, 0x99, 0x61, 0xbd, 0xbd, - 0x00, 0xcb, 0xa0, 0x68, 0x61, 0xa7, 0x25, 0x36, 0x8b, 0x62, 0x33, 0xfa, 0x86, 0xe3, 0x61, 0x64, - 0x0d, 0x0b, 0x8b, 0x65, 0x94, 0x7c, 0x00, 0x8a, 0x0d, 0xcc, 0x90, 0x85, 0x18, 0x2a, 0x01, 0xe1, - 0xf7, 0xd7, 0x72, 0x85, 0xdc, 0x2d, 0xc9, 0x2c, 0x63, 0x3d, 0x02, 0xe3, 0x4e, 0xe6, 0x2e, 0xe3, - 0xb7, 0x1c, 0x97, 0x46, 0xa6, 0x95, 0x99, 0x01, 0xbd, 0xd8, 0x20, 0xce, 0x3a, 0xff, 0x86, 0x55, - 0x70, 0x4c, 0x28, 0x6d, 0x10, 0x07, 0x99, 0x8c, 0x34, 0xb1, 0xd1, 0x44, 0x36, 0x2d, 0x1d, 0x9e, - 0x56, 0x66, 0x8a, 0xfa, 0x51, 0xb1, 0xb5, 0x2a, 0x77, 0xee, 0x22, 0x9b, 0x26, 0xaf, 0xf4, 0x68, - 0xf2, 0x4a, 0xc3, 0x47, 0xe0, 0x64, 0xe4, 0x05, 0x6c, 0x19, 0x3e, 0x7e, 0x88, 0x7c, 0xcb, 0xb0, - 0xb0, 0xe3, 0x36, 0x68, 0x69, 0x4c, 0xd8, 0xf5, 0x4e, 0x26, 0xbb, 0x16, 0xdb, 0x28, 0xba, 0x00, - 0xb9, 0x26, 0x30, 0xf4, 0x09, 0x94, 0xbe, 0xa1, 0xfe, 0x44, 0x01, 0x67, 0xc4, 0xf5, 0xb8, 0x1b, - 0x9e, 0x54, 0xe8, 0x9a, 0x45, 0xcb, 0xf2, 0xc3, 0x6b, 0x7d, 0x09, 0xbc, 0x14, 0x4a, 0x31, 0x90, - 0x65, 0xf9, 0x98, 0xd2, 0x20, 0x2a, 0x6b, 0xf0, 0xeb, 0xa7, 0x95, 0xb1, 0x16, 0x6a, 0xd8, 0x17, - 0x55, 0xb9, 0xa1, 0xea, 0x47, 0x42, 0xda, 0xc5, 0x60, 0x25, 0x69, 0x7f, 0x21, 0x69, 0xff, 0xc5, - 0xe2, 0xc7, 0x9f, 0x55, 0xfa, 0xfe, 0xf5, 0x59, 0xa5, 0x4f, 0xbd, 0x03, 0xd4, 0xbd, 0xd4, 0x91, - 0x97, 0xf6, 0x15, 0xf0, 0x52, 0x04, 0x18, 0xd3, 0x47, 0x3f, 0x62, 0x76, 0xd0, 0x73, 0x6d, 0x5e, - 0x34, 0x70, 0xad, 0x43, 0xbb, 0x0e, 0x03, 0xd3, 0x01, 0xd3, 0x0d, 0x4c, 0x08, 0xe9, 0xc9, 0xc0, - 0xb8, 0x3a, 0x6d, 0x03, 0xd3, 0x1d, 0xfe, 0x82, 0x73, 0xd5, 0x49, 0x70, 0x52, 0x00, 0x6e, 0x6c, - 0xf9, 0x2e, 0x63, 0x36, 0x16, 0x79, 0x5a, 0xda, 0xa5, 0xfe, 0x3e, 0x4c, 0xd7, 0x89, 0x5d, 0x29, - 0xa6, 0x02, 0x46, 0xa8, 0x8d, 0xe8, 0x96, 0xd1, 0xc0, 0x0c, 0xfb, 0x42, 0x42, 0xbf, 0x0e, 0xc4, - 0xd2, 0x2d, 0xbe, 0x02, 0x17, 0xc0, 0xf1, 0x0e, 0x02, 0x43, 0x44, 0x11, 0x72, 0x4c, 0x2c, 0x4c, - 0xec, 0xd7, 0x8f, 0xb5, 0x49, 0x17, 0xc3, 0x2d, 0xf8, 0x3d, 0x50, 0x72, 0xf0, 0x23, 0x66, 0xf8, - 0xd8, 0xb3, 0xb1, 0x43, 0xe8, 0x96, 0x61, 0x22, 0xc7, 0xe2, 0xc6, 0x62, 0x91, 0x95, 0x46, 0x16, - 0xca, 0xd5, 0xa0, 0x76, 0xa8, 0x86, 0xb5, 0x43, 0x75, 0x23, 0xac, 0x1d, 0x6a, 0x45, 0x7e, 0x11, - 0x3f, 0xf9, 0x6b, 0x45, 0xd1, 0x4f, 0x70, 0x14, 0x3d, 0x04, 0x59, 0x0a, 0x31, 0xd4, 0x57, 0xc1, - 0xac, 0x30, 0x49, 0xc7, 0x75, 0x1e, 0xcf, 0x3e, 0xb6, 0xc2, 0x18, 0x89, 0x85, 0xbc, 0xf4, 0xc0, - 0x32, 0x38, 0x9f, 0x89, 0x5a, 0x7a, 0xe4, 0x04, 0x18, 0x92, 0xd7, 0x4e, 0x11, 0x09, 0x48, 0x7e, - 0xa9, 0xef, 0x82, 0x57, 0x04, 0xcc, 0xa2, 0x6d, 0xaf, 0x21, 0xe2, 0xd3, 0xbb, 0xc8, 0xe6, 0x38, - 0xfc, 0x10, 0x6a, 0xad, 0x36, 0x62, 0xc6, 0x27, 0xfc, 0xe7, 0x8a, 0xb4, 0xa1, 0x0b, 0x9c, 0x54, - 0xea, 0x01, 0x38, 0xea, 0x21, 0xe2, 0xf3, 0x2c, 0xc3, 0xcb, 0x1f, 0x11, 0x11, 0xf2, 0xb9, 0x5a, - 0xc9, 0x94, 0x16, 0xb8, 0x8c, 0x40, 0x04, 0x97, 0x10, 0x45, 0x9c, 0xd3, 0xf6, 0xc5, 0x98, 0x17, - 0x23, 0x51, 0xff, 0xaf, 0x80, 0x33, 0x5d, 0xb9, 0xe0, 0xca, 0xae, 0x79, 0x61, 0xf2, 0xeb, 0xa7, - 0x95, 0x89, 0xe0, 0xda, 0x24, 0x29, 0x52, 0x12, 0xc4, 0x4a, 0xca, 0xf5, 0x2b, 0x24, 0x71, 0x92, - 0x14, 0x29, 0xf7, 0xf0, 0x0a, 0x38, 0x1c, 0x51, 0x6d, 0xe3, 0x96, 0x0c, 0xb7, 0x53, 0xd5, 0x76, - 0xf1, 0x57, 0x0d, 0x8a, 0xbf, 0xea, 0xda, 0xce, 0xa6, 0x4d, 0xcc, 0x9b, 0xb8, 0xa5, 0x47, 0x47, - 0x75, 0x13, 0xb7, 0xd4, 0x71, 0x00, 0xc5, 0xb9, 0xac, 0x21, 0x1f, 0xb5, 0x63, 0xe8, 0xfb, 0xe0, - 0x58, 0x6c, 0x55, 0x1e, 0xcb, 0x2a, 0x18, 0xf2, 0xc4, 0x8a, 0xac, 0xb0, 0xce, 0x67, 0x3c, 0x0b, - 0xce, 0x22, 0x1f, 0x1c, 0x09, 0xa0, 0xde, 0x92, 0xf1, 0x10, 0x2b, 0x52, 0xee, 0x78, 0x0c, 0x5b, - 0xab, 0x4e, 0x94, 0x29, 0xb2, 0x97, 0x88, 0x0f, 0x64, 0xd0, 0x77, 0x83, 0x8b, 0x6a, 0xa0, 0xd3, - 0x9d, 0x6f, 0x7e, 0xe2, 0xbc, 0x70, 0x78, 0x17, 0x26, 0x3b, 0x1e, 0xff, 0xf8, 0x01, 0x62, 0xaa, - 0x2e, 0x82, 0xa9, 0x98, 0xc8, 0x7d, 0x68, 0xfd, 0xe9, 0x21, 0x30, 0xbd, 0x0b, 0x46, 0xf4, 0x57, - 0xaf, 0x4f, 0x51, 0x32, 0x42, 0x0a, 0x39, 0x23, 0x04, 0x96, 0xc0, 0xa0, 0x28, 0x8a, 0x44, 0x6c, - 0xf5, 0xd7, 0x0a, 0x25, 0x45, 0x0f, 0x16, 0xe0, 0x5b, 0x60, 0xc0, 0xe7, 0x39, 0x6e, 0x40, 0x68, - 0x73, 0x8e, 0x9f, 0xef, 0x9f, 0x9e, 0x56, 0x26, 0x83, 0x32, 0x90, 0x5a, 0xdb, 0x55, 0xe2, 0x6a, - 0x0d, 0xc4, 0xb6, 0xaa, 0xef, 0xe2, 0x3a, 0x32, 0x5b, 0xd7, 0xb0, 0x59, 0x52, 0x74, 0xc1, 0x02, - 0xcf, 0x81, 0xb1, 0x48, 0xab, 0x00, 0x7d, 0x50, 0xe4, 0xd7, 0xd1, 0x70, 0x55, 0x14, 0x5b, 0xf0, - 0x3e, 0x28, 0x45, 0x64, 0xa6, 0xdb, 0x68, 0x10, 0x4a, 0x89, 0xeb, 0x18, 0x42, 0xea, 0x90, 0x90, - 0x7a, 0x36, 0x83, 0x54, 0xfd, 0x44, 0x08, 0xb2, 0x14, 0x61, 0xe8, 0x5c, 0x8b, 0xfb, 0xa0, 0x14, - 0xb9, 0x36, 0x09, 0x7f, 0x28, 0x07, 0x7c, 0x08, 0x92, 0x80, 0xbf, 0x09, 0x46, 0x2c, 0x4c, 0x4d, - 0x9f, 0x78, 0xa2, 0x4c, 0x2e, 0x0a, 0xcf, 0x9f, 0x0d, 0xcb, 0xe4, 0xb0, 0x9f, 0x0a, 0x6b, 0xe4, - 0x6b, 0x6d, 0x52, 0x79, 0x57, 0x3a, 0xb9, 0xe1, 0x7d, 0x70, 0x32, 0xd2, 0xd5, 0xf5, 0xb0, 0x2f, - 0x8a, 0xcf, 0x30, 0x1e, 0x44, 0x89, 0x58, 0x3b, 0xf3, 0xd5, 0xe7, 0x17, 0x4e, 0x4b, 0xf4, 0x28, - 0x7e, 0x64, 0x1c, 0xac, 0x33, 0x9f, 0x38, 0x75, 0x7d, 0x22, 0xc4, 0xb8, 0x23, 0x21, 0xc2, 0x30, - 0x39, 0x01, 0x86, 0x7e, 0x80, 0x88, 0x8d, 0x2d, 0x51, 0x55, 0x16, 0x75, 0xf9, 0x05, 0x2f, 0x82, - 0x21, 0xde, 0x53, 0xed, 0x50, 0x51, 0x13, 0x8e, 0x2d, 0xa8, 0xbb, 0xa9, 0x5f, 0x73, 0x1d, 0x6b, - 0x5d, 0x50, 0xea, 0x92, 0x03, 0x6e, 0x80, 0x28, 0x1a, 0x0d, 0xe6, 0x6e, 0x63, 0x27, 0xa8, 0x18, - 0x87, 0x6b, 0xe7, 0xa5, 0x57, 0x8f, 0xbf, 0xe8, 0xd5, 0x55, 0x87, 0x7d, 0xf5, 0xf9, 0x05, 0x20, - 0x85, 0xac, 0x3a, 0x4c, 0x1f, 0x0b, 0x31, 0x36, 0x04, 0x04, 0x0f, 0x9d, 0x08, 0x35, 0x08, 0x9d, - 0xd1, 0x20, 0x74, 0xc2, 0xd5, 0x20, 0x74, 0x5e, 0x07, 0x13, 0xf2, 0xf6, 0x62, 0x6a, 0x98, 0x3b, - 0xbe, 0xcf, 0xfb, 0x07, 0xec, 0xb9, 0xe6, 0x96, 0xa8, 0x2f, 0x8b, 0xfa, 0xf1, 0x68, 0x7b, 0x29, - 0xd8, 0x5d, 0xe6, 0x9b, 0xea, 0xc7, 0x0a, 0xa8, 0xec, 0x7a, 0xaf, 0x65, 0xfa, 0xc0, 0x00, 0xb4, - 0x33, 0x83, 0x7c, 0x97, 0x96, 0x33, 0xe5, 0xc2, 0x6e, 0xb7, 0x5d, 0xef, 0x00, 0x56, 0x1f, 0x80, - 0xb9, 0x94, 0x46, 0x2e, 0xa2, 0xbd, 0x81, 0xe8, 0x86, 0x2b, 0xbf, 0xf0, 0xc1, 0x14, 0xae, 0xea, - 0x5d, 0x30, 0x9f, 0x43, 0xa4, 0x74, 0xc7, 0x99, 0x8e, 0x14, 0x43, 0xac, 0x30, 0x79, 0x8e, 0xb4, - 0x13, 0x9d, 0x28, 0x4a, 0xcf, 0xa7, 0x97, 0xb9, 0xf1, 0x3b, 0x93, 0x35, 0x75, 0xa6, 0xda, 0x59, - 0xc8, 0x6e, 0x67, 0x1d, 0xbc, 0x9a, 0x4d, 0x1d, 0x69, 0xe2, 0x1b, 0x32, 0xd5, 0x29, 0xd9, 0xb3, - 0x82, 0x60, 0x50, 0x55, 0x99, 0xe1, 0x6b, 0xb6, 0x6b, 0x6e, 0xd3, 0xf7, 0x1d, 0x46, 0xec, 0xdb, - 0xf8, 0x51, 0x10, 0x6b, 0xe1, 0x6b, 0x7b, 0x4f, 0x16, 0xec, 0xe9, 0x34, 0x52, 0x83, 0xd7, 0xc0, - 0xc4, 0xa6, 0xd8, 0x37, 0x76, 0x38, 0x81, 0x21, 0x2a, 0xce, 0x20, 0x9e, 0x15, 0xd1, 0xad, 0x8d, - 0x6f, 0xa6, 0xb0, 0xab, 0x8b, 0xb2, 0xfa, 0x5e, 0x8a, 0x5c, 0xb7, 0xe2, 0xbb, 0x8d, 0x25, 0xd9, - 0x3d, 0x87, 0xee, 0x8e, 0x75, 0xd8, 0x4a, 0xbc, 0xc3, 0x56, 0x57, 0xc0, 0xd9, 0x3d, 0x21, 0xda, - 0xa5, 0xf5, 0xde, 0xaf, 0xdd, 0x3b, 0xb2, 0x6e, 0x8f, 0xc5, 0x56, 0xe6, 0xb7, 0xf2, 0xb7, 0xfd, - 0x69, 0x73, 0x98, 0xcc, 0xd2, 0x63, 0xf3, 0x85, 0x42, 0x7c, 0xbe, 0x70, 0x16, 0x8c, 0xba, 0x0f, - 0x9d, 0x8e, 0x40, 0xea, 0x17, 0xfb, 0x87, 0xc5, 0x62, 0x98, 0x20, 0xa3, 0x76, 0x7c, 0x60, 0xb7, - 0x76, 0x7c, 0xf0, 0x20, 0xdb, 0xf1, 0x8f, 0xc0, 0x08, 0x71, 0x08, 0x33, 0x64, 0xbd, 0x35, 0x24, - 0xb0, 0x97, 0x73, 0x61, 0xaf, 0x3a, 0x84, 0x11, 0x64, 0x93, 0x1f, 0x8a, 0x51, 0x8b, 0xa8, 0xc2, - 0x78, 0xdf, 0x42, 0x75, 0xc0, 0x91, 0x83, 0xaa, 0x0c, 0x36, 0xc0, 0x78, 0x30, 0xf2, 0xa0, 0x5b, - 0xc8, 0x23, 0x4e, 0x3d, 0x14, 0x78, 0x48, 0x08, 0x7c, 0x3b, 0x5b, 0x81, 0xc7, 0x01, 0xd6, 0x03, - 0xfe, 0x0e, 0x31, 0xd0, 0x4b, 0xae, 0xd3, 0x85, 0xbf, 0x9f, 0x06, 0x83, 0xe2, 0x14, 0xe1, 0x3f, - 0x15, 0x30, 0x9e, 0x36, 0xd5, 0x83, 0x57, 0xf3, 0x27, 0xd2, 0xf8, 0x40, 0xb1, 0xbc, 0xd8, 0x03, - 0x42, 0x10, 0x4e, 0xea, 0x8d, 0x1f, 0xfd, 0xe1, 0x1f, 0x3f, 0x2d, 0xd4, 0xe0, 0xd5, 0xee, 0xe3, - 0xe7, 0x28, 0xec, 0xe4, 0xd8, 0x50, 0x7b, 0xdc, 0x11, 0x88, 0x4f, 0xe0, 0x9f, 0x15, 0x59, 0x4b, - 0xc7, 0x53, 0x2a, 0xbc, 0x92, 0x5f, 0xc9, 0xd8, 0xe4, 0xb1, 0x7c, 0x75, 0xff, 0x00, 0xd2, 0xc8, - 0x45, 0x61, 0xe4, 0xdb, 0xf0, 0xad, 0x1c, 0x46, 0x06, 0x03, 0x40, 0xed, 0xb1, 0x08, 0xff, 0x27, - 0xf0, 0xd3, 0x82, 0xbc, 0x95, 0xa9, 0xe3, 0x0b, 0xb8, 0x92, 0x5d, 0xc7, 0xbd, 0xc6, 0x31, 0xe5, - 0xeb, 0x3d, 0xe3, 0x48, 0x93, 0x37, 0x85, 0xc9, 0xdf, 0x85, 0xf7, 0x32, 0xfc, 0xac, 0x10, 0x8d, - 0xf8, 0x62, 0x7d, 0x58, 0xfc, 0x78, 0xb5, 0xc7, 0xc9, 0x57, 0x28, 0xcd, 0x27, 0x9d, 0xcd, 0xc3, - 0xbe, 0x7c, 0x92, 0x32, 0xc1, 0xd9, 0x97, 0x4f, 0xd2, 0x46, 0x2f, 0xfb, 0xf3, 0x49, 0xcc, 0xec, - 0xa4, 0x4f, 0x92, 0x8d, 0xeb, 0x13, 0xf8, 0x3b, 0x45, 0xf6, 0x99, 0xb1, 0xb1, 0x0c, 0xbc, 0x9c, - 0xdd, 0x86, 0xb4, 0x69, 0x4f, 0xf9, 0xca, 0xbe, 0xf9, 0xa5, 0xed, 0x6f, 0x0a, 0xdb, 0x17, 0xe0, - 0x5c, 0x77, 0xdb, 0x99, 0x04, 0x08, 0x7e, 0x63, 0x80, 0x3f, 0x2b, 0xc8, 0x67, 0x71, 0xef, 0x39, - 0x0b, 0xbc, 0x93, 0x5d, 0xc5, 0x4c, 0xf3, 0x9d, 0xf2, 0xda, 0xc1, 0x01, 0x4a, 0x27, 0xdc, 0x14, - 0x4e, 0x58, 0x86, 0x4b, 0xdd, 0x9d, 0xe0, 0x47, 0x88, 0xed, 0x5b, 0x11, 0x1b, 0xde, 0xc2, 0x1f, - 0x17, 0x64, 0xc5, 0xb1, 0xe7, 0xa4, 0x07, 0xde, 0xce, 0x6e, 0x45, 0x96, 0x09, 0x54, 0xf9, 0xce, - 0x81, 0xe1, 0x49, 0xa7, 0x2c, 0x0b, 0xa7, 0x5c, 0x81, 0x97, 0xba, 0x3b, 0x45, 0x46, 0xb9, 0xe1, - 0x71, 0xd4, 0x44, 0xfa, 0xff, 0xb5, 0x02, 0x46, 0x3a, 0x46, 0x29, 0xf0, 0x8d, 0xec, 0x7a, 0xc6, - 0x46, 0x32, 0xe5, 0x37, 0xf3, 0x33, 0x4a, 0x4b, 0xe6, 0x84, 0x25, 0xb3, 0x70, 0xa6, 0xbb, 0x25, - 0xc1, 0xe3, 0xdf, 0x8e, 0xed, 0xbd, 0xc7, 0x29, 0x79, 0x62, 0x3b, 0xd3, 0x9c, 0x27, 0x4f, 0x6c, - 0x67, 0x9b, 0xf4, 0xe4, 0x89, 0x6d, 0x97, 0x83, 0x18, 0xc4, 0x31, 0xda, 0x2d, 0x58, 0xe2, 0x30, - 0x7f, 0x53, 0x90, 0x43, 0xd1, 0x2c, 0xed, 0x11, 0x7c, 0x7f, 0xbf, 0x0f, 0xf4, 0x9e, 0x1d, 0x5e, - 0xf9, 0xee, 0x41, 0xc3, 0x4a, 0x4f, 0xdd, 0x13, 0x9e, 0xda, 0x80, 0x7a, 0xee, 0x6a, 0xc0, 0xf0, - 0xb0, 0xdf, 0x76, 0x5a, 0xda, 0x93, 0xf8, 0xab, 0x02, 0x78, 0x39, 0x4b, 0xbf, 0x05, 0xd7, 0x7a, - 0x78, 0xe8, 0x53, 0x3b, 0xc9, 0xf2, 0x7b, 0x07, 0x88, 0x28, 0x3d, 0x65, 0x0a, 0x4f, 0xdd, 0x87, - 0x1f, 0xe6, 0xf1, 0x54, 0x7c, 0xbc, 0xd4, 0xbd, 0x8a, 0xf8, 0xaf, 0x02, 0x26, 0x76, 0x99, 0x16, - 0xc0, 0xa5, 0x5e, 0x66, 0x0d, 0xa1, 0x63, 0xae, 0xf5, 0x06, 0x92, 0xff, 0x7e, 0x45, 0x16, 0xef, - 0x7a, 0xbf, 0xfe, 0xad, 0xc8, 0x16, 0x31, 0xad, 0x13, 0x86, 0x39, 0x26, 0x2c, 0x7b, 0x74, 0xdb, - 0xe5, 0x95, 0x5e, 0x61, 0xf2, 0x57, 0xcf, 0xbb, 0x34, 0xee, 0xf0, 0x7f, 0xc9, 0x9f, 0xea, 0xe3, - 0xad, 0x35, 0xbc, 0x9e, 0xff, 0x88, 0x52, 0xfb, 0xfb, 0xf2, 0x8d, 0xde, 0x81, 0x7a, 0xe8, 0x19, - 0x88, 0xa5, 0x3d, 0x8e, 0xc6, 0x0b, 0x4f, 0xe0, 0x5f, 0xc2, 0x5a, 0x30, 0x96, 0x9e, 0xf2, 0xd4, - 0x82, 0x69, 0x13, 0x84, 0xf2, 0x95, 0x7d, 0xf3, 0x4b, 0xd3, 0x56, 0x84, 0x69, 0x57, 0xe1, 0xe5, - 0xbc, 0x09, 0x30, 0x1e, 0xc5, 0xb5, 0x0f, 0xbe, 0x78, 0x36, 0xa5, 0x7c, 0xf9, 0x6c, 0x4a, 0xf9, - 0xdb, 0xb3, 0x29, 0xe5, 0x93, 0xe7, 0x53, 0x7d, 0x5f, 0x3e, 0x9f, 0xea, 0xfb, 0xe3, 0xf3, 0xa9, - 0xbe, 0x7b, 0x97, 0xea, 0x84, 0x6d, 0xed, 0x6c, 0x56, 0x4d, 0xb7, 0x21, 0xff, 0xe7, 0xa6, 0x43, - 0xd4, 0x85, 0x48, 0x54, 0xf3, 0x75, 0xed, 0x51, 0xa2, 0xf6, 0x6c, 0x79, 0x98, 0x6e, 0x0e, 0x89, - 0x5f, 0x0f, 0xbf, 0xf3, 0x4d, 0x00, 0x00, 0x00, 0xff, 0xff, 0x98, 0xe8, 0xa5, 0x6b, 0x13, 0x25, - 0x00, 0x00, + 0xb7, 0x86, 0x2f, 0x3d, 0xe5, 0xd0, 0x02, 0x09, 0x82, 0x9e, 0x9b, 0x73, 0x0f, 0x45, 0x51, 0x04, + 0xfd, 0x07, 0x7a, 0xc9, 0xad, 0x69, 0x7a, 0x29, 0x5a, 0xd4, 0x6d, 0xed, 0x16, 0xe8, 0xa5, 0x87, + 0xa6, 0xfd, 0x03, 0x82, 0x19, 0x0e, 0xb9, 0x4b, 0x9a, 0xd2, 0x92, 0x5a, 0xdd, 0xc4, 0x99, 0xf7, + 0x7e, 0xf3, 0xde, 0x9b, 0xf7, 0xde, 0xbc, 0xf7, 0x56, 0x40, 0x23, 0x0e, 0xc3, 0xbe, 0xb9, 0x85, + 0x88, 0x63, 0x50, 0x6c, 0xee, 0xf8, 0x84, 0xb5, 0x34, 0xd3, 0x6c, 0x6a, 0x9e, 0xef, 0x36, 0x89, + 0x85, 0x7d, 0xad, 0x39, 0xaf, 0x3d, 0xd8, 0xc1, 0x7e, 0xab, 0xea, 0xf9, 0x2e, 0x73, 0xe1, 0xd9, + 0x14, 0x86, 0xaa, 0x69, 0x36, 0xab, 0x21, 0x43, 0xb5, 0x39, 0x5f, 0x3e, 0x55, 0x77, 0xdd, 0xba, + 0x8d, 0x35, 0xe4, 0x11, 0x0d, 0x39, 0x8e, 0xcb, 0x10, 0x23, 0xae, 0x43, 0x03, 0x88, 0xf2, 0x78, + 0xdd, 0xad, 0xbb, 0xe2, 0x4f, 0x8d, 0xff, 0x25, 0x57, 0x2b, 0x92, 0x47, 0x7c, 0x6d, 0xee, 0x7c, + 0xa4, 0x31, 0xd2, 0xc0, 0x94, 0xa1, 0x86, 0x27, 0x09, 0x16, 0xb2, 0x88, 0x1a, 0x49, 0x11, 0xf0, + 0xcc, 0xed, 0xc6, 0xd3, 0x9c, 0xd7, 0xe8, 0x16, 0xf2, 0xb1, 0x65, 0x98, 0xae, 0x43, 0x77, 0x1a, + 0x11, 0xc7, 0xb9, 0x3d, 0x38, 0x1e, 0x12, 0x1f, 0x4b, 0xb2, 0x53, 0x0c, 0x3b, 0x16, 0xf6, 0x1b, + 0xc4, 0x61, 0x9a, 0xe9, 0xb7, 0x3c, 0xe6, 0x6a, 0xdb, 0xb8, 0x15, 0x6a, 0x78, 0xd2, 0x74, 0x69, + 0xc3, 0xa5, 0x46, 0xa0, 0x64, 0xf0, 0x21, 0xb7, 0x5e, 0x0e, 0xbe, 0x34, 0xca, 0xd0, 0x36, 0x71, + 0xea, 0x5a, 0x73, 0x7e, 0x13, 0x33, 0x34, 0x1f, 0x7e, 0x4b, 0xaa, 0x59, 0x49, 0xb5, 0x89, 0x28, + 0x0e, 0xcc, 0x1f, 0x11, 0x7a, 0xa8, 0x4e, 0x1c, 0x61, 0xcf, 0x80, 0x56, 0xbd, 0x0c, 0x26, 0xdf, + 0xe3, 0x14, 0x4b, 0x52, 0x91, 0xeb, 0xd8, 0xc1, 0x94, 0x50, 0x1d, 0x3f, 0xd8, 0xc1, 0x94, 0xc1, + 0x0a, 0x18, 0x09, 0x55, 0x34, 0x88, 0x55, 0x52, 0xa6, 0x95, 0x99, 0x61, 0x1d, 0x84, 0x4b, 0xab, + 0x96, 0xfa, 0x18, 0x9c, 0x4a, 0xe7, 0xa7, 0x9e, 0xeb, 0x50, 0x0c, 0x3f, 0x04, 0xa3, 0xf5, 0x60, + 0xc9, 0xa0, 0x0c, 0x31, 0x2c, 0x20, 0x46, 0x16, 0xe6, 0xaa, 0xbb, 0x79, 0x42, 0x73, 0xbe, 0x9a, + 0xc0, 0x5a, 0xe7, 0x7c, 0xb5, 0x81, 0x2f, 0x9f, 0x56, 0xfa, 0xf4, 0xc3, 0xf5, 0x8e, 0x35, 0xf5, + 0x57, 0x0a, 0x28, 0xc7, 0x4e, 0x5f, 0xe2, 0x78, 0x91, 0xf0, 0x37, 0xc0, 0xa0, 0xb7, 0x85, 0x68, + 0x70, 0xe6, 0xd8, 0xc2, 0x42, 0x35, 0x83, 0xf7, 0x45, 0x87, 0xaf, 0x71, 0x4e, 0x3d, 0x00, 0x80, + 0x2b, 0x00, 0xb4, 0x2d, 0x57, 0x2a, 0x08, 0x15, 0xbe, 0x53, 0x95, 0x57, 0xc3, 0xcd, 0x5c, 0x0d, + 0xbc, 0x5c, 0x9a, 0xb9, 0xba, 0x86, 0xea, 0x58, 0x4a, 0xa1, 0x77, 0x70, 0xaa, 0xbf, 0x54, 0x12, + 0xe6, 0x0e, 0x05, 0x96, 0xd6, 0xaa, 0x81, 0x21, 0x21, 0x1e, 0x2d, 0x29, 0xd3, 0xfd, 0x33, 0x23, + 0x0b, 0xb3, 0xd9, 0x44, 0xe6, 0xdb, 0xba, 0xe4, 0x84, 0xd7, 0x53, 0x64, 0xfd, 0x6e, 0x57, 0x59, + 0x03, 0x01, 0x62, 0xc2, 0x7e, 0x36, 0x08, 0x06, 0x05, 0x34, 0x3c, 0x09, 0x8a, 0x81, 0x08, 0x91, + 0x0b, 0x1c, 0x12, 0xdf, 0xab, 0x16, 0x9c, 0x04, 0xc3, 0xa6, 0x4d, 0xb0, 0xc3, 0xf8, 0x5e, 0x41, + 0xec, 0x15, 0x83, 0x85, 0x55, 0x0b, 0x1e, 0x03, 0x83, 0xcc, 0xf5, 0x8c, 0xdb, 0xa5, 0xfe, 0x69, + 0x65, 0x66, 0x54, 0x1f, 0x60, 0xae, 0x77, 0x1b, 0xce, 0x02, 0xd8, 0x20, 0x8e, 0xe1, 0xb9, 0x0f, + 0xb9, 0x4f, 0x39, 0x46, 0x40, 0x31, 0x30, 0xad, 0xcc, 0xf4, 0xeb, 0x63, 0x0d, 0xe2, 0xac, 0xf1, + 0x8d, 0x55, 0x67, 0x83, 0xd3, 0xce, 0x81, 0xf1, 0x26, 0xb2, 0x89, 0x85, 0x98, 0xeb, 0x53, 0xc9, + 0x62, 0x22, 0xaf, 0x34, 0x28, 0xf0, 0x60, 0x7b, 0x4f, 0x30, 0x2d, 0x21, 0x0f, 0xce, 0x82, 0xa3, + 0xd1, 0xaa, 0x41, 0x31, 0x13, 0xe4, 0x43, 0x82, 0xfc, 0x48, 0xb4, 0xb1, 0x8e, 0x19, 0xa7, 0x3d, + 0x05, 0x86, 0x91, 0x6d, 0xbb, 0x0f, 0x6d, 0x42, 0x59, 0xe9, 0xd0, 0x74, 0xff, 0xcc, 0xb0, 0xde, + 0x5e, 0x80, 0x65, 0x50, 0xb4, 0xb0, 0xd3, 0x12, 0x9b, 0x45, 0xb1, 0x19, 0x7d, 0xc3, 0xf1, 0xd0, + 0xb3, 0x86, 0x85, 0xc6, 0xd2, 0x4b, 0x3e, 0x00, 0xc5, 0x06, 0x66, 0xc8, 0x42, 0x0c, 0x95, 0x80, + 0xb0, 0xfb, 0x6b, 0xb9, 0x5c, 0xee, 0x96, 0x64, 0x96, 0xbe, 0x1e, 0x81, 0x71, 0x23, 0x73, 0x93, + 0xf1, 0x28, 0xc7, 0xa5, 0x91, 0x69, 0x65, 0x66, 0x40, 0x2f, 0x36, 0x88, 0xb3, 0xce, 0xbf, 0x61, + 0x15, 0x1c, 0x13, 0x42, 0x1b, 0xc4, 0x41, 0x26, 0x23, 0x4d, 0x6c, 0x34, 0x91, 0x4d, 0x4b, 0x87, + 0xa7, 0x95, 0x99, 0xa2, 0x7e, 0x54, 0x6c, 0xad, 0xca, 0x9d, 0xbb, 0xc8, 0xa6, 0xc9, 0x90, 0x1e, + 0x4d, 0x86, 0x34, 0x7c, 0x04, 0x4e, 0x46, 0x56, 0xc0, 0x96, 0xe1, 0xe3, 0x87, 0xc8, 0xb7, 0x0c, + 0x0b, 0x3b, 0x6e, 0x83, 0x96, 0xc6, 0x84, 0x5e, 0xef, 0x64, 0xd2, 0x6b, 0xb1, 0x8d, 0xa2, 0x0b, + 0x90, 0x6b, 0x02, 0x43, 0x9f, 0x40, 0xe9, 0x1b, 0x50, 0x05, 0x87, 0x3d, 0x9f, 0xb8, 0x1c, 0x4c, + 0x98, 0xfd, 0x88, 0x30, 0x7b, 0x6c, 0x4d, 0xfd, 0x99, 0x02, 0xce, 0x88, 0x10, 0xba, 0x1b, 0xde, + 0x66, 0x68, 0xbe, 0x45, 0xcb, 0xf2, 0xc3, 0xd0, 0xbf, 0x04, 0x5e, 0x0a, 0x25, 0x31, 0x90, 0x65, + 0xf9, 0x98, 0xd2, 0xc0, 0x73, 0x6b, 0xf0, 0x9b, 0xa7, 0x95, 0xb1, 0x16, 0x6a, 0xd8, 0x17, 0x55, + 0xb9, 0xa1, 0xea, 0x47, 0x42, 0xda, 0xc5, 0x60, 0x25, 0x69, 0xa3, 0x42, 0xd2, 0x46, 0x17, 0x8b, + 0x1f, 0x7f, 0x5e, 0xe9, 0xfb, 0xf7, 0xe7, 0x95, 0x3e, 0xf5, 0x0e, 0x50, 0xf7, 0x12, 0x47, 0x06, + 0xf6, 0x2b, 0xe0, 0xa5, 0x08, 0x30, 0x26, 0x8f, 0x7e, 0xc4, 0xec, 0xa0, 0xe7, 0xd2, 0xbc, 0xa8, + 0xe0, 0x5a, 0x87, 0x74, 0x1d, 0x0a, 0xa6, 0x03, 0xa6, 0x2b, 0x98, 0x38, 0xa4, 0x27, 0x05, 0xe3, + 0xe2, 0xb4, 0x15, 0x4c, 0x37, 0xf8, 0x0b, 0xc6, 0x55, 0x27, 0xc1, 0x49, 0x01, 0xb8, 0xb1, 0xe5, + 0xbb, 0x8c, 0xd9, 0x58, 0xe4, 0x72, 0xa9, 0x97, 0xfa, 0x87, 0x30, 0xa5, 0x27, 0x76, 0xe5, 0x31, + 0x15, 0x30, 0x42, 0x6d, 0x44, 0xb7, 0x8c, 0x06, 0x66, 0xd8, 0x17, 0x27, 0xf4, 0xeb, 0x40, 0x2c, + 0xdd, 0xe2, 0x2b, 0x70, 0x01, 0x1c, 0xef, 0x20, 0x30, 0x84, 0xa7, 0x21, 0xc7, 0xc4, 0x42, 0xc5, + 0x7e, 0xfd, 0x58, 0x9b, 0x74, 0x31, 0xdc, 0x82, 0x3f, 0x00, 0x25, 0x07, 0x3f, 0x62, 0x86, 0x8f, + 0x3d, 0x1b, 0x3b, 0x84, 0x6e, 0x19, 0x26, 0x72, 0x2c, 0xae, 0x2c, 0x16, 0x99, 0x6b, 0x64, 0xa1, + 0x5c, 0x0d, 0xea, 0x8b, 0x6a, 0x58, 0x5f, 0x54, 0x37, 0xc2, 0xfa, 0xa2, 0x56, 0xe4, 0xc1, 0xfa, + 0xc9, 0xdf, 0x2a, 0x8a, 0x7e, 0x82, 0xa3, 0xe8, 0x21, 0xc8, 0x52, 0x88, 0xa1, 0xbe, 0x0a, 0x66, + 0x85, 0x4a, 0x3a, 0xae, 0x73, 0x9f, 0xf7, 0xb1, 0x15, 0xfa, 0x48, 0x2c, 0x2c, 0xa4, 0x05, 0x96, + 0xc1, 0xf9, 0x4c, 0xd4, 0xd2, 0x22, 0x27, 0xc0, 0x90, 0x0c, 0x4d, 0x45, 0x44, 0x8b, 0xfc, 0x52, + 0xdf, 0x05, 0xaf, 0x08, 0x98, 0x45, 0xdb, 0x5e, 0x43, 0xc4, 0xa7, 0x77, 0x91, 0xcd, 0x71, 0xf8, + 0x25, 0xd4, 0x5a, 0x6d, 0xc4, 0x8c, 0xcf, 0xfc, 0x2f, 0x14, 0xa9, 0x43, 0x17, 0x38, 0x29, 0xd4, + 0x03, 0x70, 0xd4, 0x43, 0xc4, 0xe7, 0x99, 0x88, 0x97, 0x48, 0xc2, 0x23, 0xe4, 0x93, 0xb6, 0x92, + 0x29, 0x75, 0xf0, 0x33, 0x82, 0x23, 0xf8, 0x09, 0x91, 0xc7, 0x39, 0x6d, 0x5b, 0x8c, 0x79, 0x31, + 0x12, 0xf5, 0xff, 0x0a, 0x38, 0xd3, 0x95, 0x0b, 0xae, 0xec, 0x9a, 0x17, 0x26, 0xbf, 0x79, 0x5a, + 0x99, 0x08, 0xc2, 0x26, 0x49, 0x91, 0x92, 0x20, 0x56, 0x52, 0xc2, 0xaf, 0x90, 0xc4, 0x49, 0x52, + 0xa4, 0xc4, 0xe1, 0x15, 0x70, 0x38, 0xa2, 0xda, 0xc6, 0x2d, 0xe9, 0x6e, 0xa7, 0xaa, 0xed, 0x02, + 0xb1, 0x1a, 0x14, 0x88, 0xd5, 0xb5, 0x9d, 0x4d, 0x9b, 0x98, 0x37, 0x71, 0x4b, 0x8f, 0xae, 0xea, + 0x26, 0x6e, 0xa9, 0xe3, 0x00, 0x8a, 0x7b, 0x59, 0x43, 0x3e, 0x6a, 0xfb, 0xd0, 0x0f, 0xc1, 0xb1, + 0xd8, 0xaa, 0xbc, 0x96, 0x55, 0x30, 0xe4, 0x89, 0x15, 0x59, 0x85, 0x9d, 0xcf, 0x78, 0x17, 0x9c, + 0x45, 0x3e, 0x4a, 0x12, 0x40, 0xbd, 0x25, 0xfd, 0x21, 0x56, 0xc8, 0xdc, 0xf1, 0x18, 0xb6, 0x56, + 0x9d, 0x28, 0x53, 0x64, 0x2f, 0x23, 0x1f, 0x48, 0xa7, 0xef, 0x06, 0x17, 0xd5, 0x49, 0xa7, 0x3b, + 0xeb, 0x82, 0xc4, 0x7d, 0xe1, 0x30, 0x16, 0x26, 0x3b, 0x0a, 0x84, 0xf8, 0x05, 0x62, 0xaa, 0x2e, + 0x82, 0xa9, 0xd8, 0x91, 0xfb, 0x90, 0xfa, 0xd3, 0x43, 0x60, 0x7a, 0x17, 0x8c, 0xe8, 0xaf, 0x5e, + 0x9f, 0xa2, 0xa4, 0x87, 0x14, 0x72, 0x7a, 0x08, 0x2c, 0x81, 0x41, 0x51, 0x38, 0x09, 0xdf, 0xea, + 0xaf, 0x15, 0x4a, 0x8a, 0x1e, 0x2c, 0xc0, 0xb7, 0xc0, 0x80, 0xcf, 0x73, 0xdc, 0x80, 0x90, 0xe6, + 0x1c, 0xbf, 0xdf, 0x3f, 0x3f, 0xad, 0x4c, 0x06, 0xa5, 0x22, 0xb5, 0xb6, 0xab, 0xc4, 0xd5, 0x1a, + 0x88, 0x6d, 0x55, 0xdf, 0xc5, 0x75, 0x64, 0xb6, 0xae, 0x61, 0xb3, 0xa4, 0xe8, 0x82, 0x05, 0x9e, + 0x03, 0x63, 0x91, 0x54, 0x01, 0xfa, 0xa0, 0xc8, 0xaf, 0xa3, 0xe1, 0xaa, 0x28, 0xc8, 0xe0, 0x7d, + 0x50, 0x8a, 0xc8, 0x4c, 0xb7, 0xd1, 0x20, 0x94, 0x12, 0xd7, 0x31, 0xc4, 0xa9, 0x43, 0xe2, 0xd4, + 0xb3, 0x19, 0x4e, 0xd5, 0x4f, 0x84, 0x20, 0x4b, 0x11, 0x86, 0xce, 0xa5, 0xb8, 0x0f, 0x4a, 0x91, + 0x69, 0x93, 0xf0, 0x87, 0x72, 0xc0, 0x87, 0x20, 0x09, 0xf8, 0x9b, 0x60, 0xc4, 0xc2, 0xd4, 0xf4, + 0x89, 0x27, 0x4a, 0xe9, 0xa2, 0xb0, 0xfc, 0xd9, 0xb0, 0x94, 0x0e, 0x7b, 0xae, 0xb0, 0x8e, 0xbe, + 0xd6, 0x26, 0x95, 0xb1, 0xd2, 0xc9, 0x0d, 0xef, 0x83, 0x93, 0x91, 0xac, 0xae, 0x87, 0x7d, 0x51, + 0xa0, 0x86, 0xfe, 0x20, 0xca, 0xc8, 0xda, 0x99, 0xaf, 0xbf, 0xb8, 0x70, 0x5a, 0xa2, 0x47, 0xfe, + 0x23, 0xfd, 0x60, 0x9d, 0xf9, 0xc4, 0xa9, 0xeb, 0x13, 0x21, 0xc6, 0x1d, 0x09, 0x11, 0xba, 0xc9, + 0x09, 0x30, 0xf4, 0x23, 0x44, 0x6c, 0x6c, 0x89, 0xca, 0xb3, 0xa8, 0xcb, 0x2f, 0x78, 0x11, 0x0c, + 0xf1, 0xbe, 0x6b, 0x87, 0x8a, 0xba, 0x71, 0x6c, 0x41, 0xdd, 0x4d, 0xfc, 0x9a, 0xeb, 0x58, 0xeb, + 0x82, 0x52, 0x97, 0x1c, 0x70, 0x03, 0x44, 0xde, 0x68, 0x30, 0x77, 0x1b, 0x3b, 0x41, 0x55, 0x39, + 0x5c, 0x3b, 0x2f, 0xad, 0x7a, 0xfc, 0x45, 0xab, 0xae, 0x3a, 0xec, 0xeb, 0x2f, 0x2e, 0x00, 0x79, + 0xc8, 0xaa, 0xc3, 0xf4, 0xb1, 0x10, 0x63, 0x43, 0x40, 0x70, 0xd7, 0x89, 0x50, 0x03, 0xd7, 0x19, + 0x0d, 0x5c, 0x27, 0x5c, 0x0d, 0x5c, 0xe7, 0x75, 0x30, 0x21, 0xa3, 0x17, 0x53, 0xc3, 0xdc, 0xf1, + 0x7d, 0xde, 0x63, 0x60, 0xcf, 0x35, 0xb7, 0x44, 0x0d, 0x5a, 0xd4, 0x8f, 0x47, 0xdb, 0x4b, 0xc1, + 0xee, 0x32, 0xdf, 0x54, 0x3f, 0x56, 0x40, 0x65, 0xd7, 0xb8, 0x96, 0xe9, 0x03, 0x03, 0xd0, 0xce, + 0x0c, 0xf2, 0x5d, 0x5a, 0xce, 0x94, 0x0b, 0xbb, 0x45, 0xbb, 0xde, 0x01, 0xac, 0x3e, 0x00, 0x73, + 0x29, 0xcd, 0x5e, 0x44, 0x7b, 0x03, 0xd1, 0x0d, 0x57, 0x7e, 0xe1, 0x83, 0x29, 0x5c, 0xd5, 0xbb, + 0x60, 0x3e, 0xc7, 0x91, 0xd2, 0x1c, 0x67, 0x3a, 0x52, 0x0c, 0xb1, 0xc2, 0xe4, 0x39, 0xd2, 0x4e, + 0x74, 0xa2, 0x28, 0x3d, 0x9f, 0x5e, 0xe6, 0xc6, 0x63, 0x26, 0x6b, 0xea, 0x4c, 0xd5, 0xb3, 0x90, + 0x5d, 0xcf, 0x3a, 0x78, 0x35, 0x9b, 0x38, 0x52, 0xc5, 0x37, 0x64, 0xaa, 0x53, 0xb2, 0x67, 0x05, + 0xc1, 0xa0, 0xaa, 0x32, 0xc3, 0xd7, 0x6c, 0xd7, 0xdc, 0xa6, 0xef, 0x3b, 0x8c, 0xd8, 0xb7, 0xf1, + 0xa3, 0xc0, 0xd7, 0xc2, 0xd7, 0xf6, 0x9e, 0x2c, 0xd8, 0xd3, 0x69, 0xa4, 0x04, 0xaf, 0x81, 0x89, + 0x4d, 0xb1, 0x6f, 0xec, 0x70, 0x02, 0x43, 0x54, 0x9c, 0x81, 0x3f, 0x2b, 0xa2, 0xa3, 0x1b, 0xdf, + 0x4c, 0x61, 0x57, 0x17, 0x65, 0xf5, 0xbd, 0x14, 0x99, 0x6e, 0xc5, 0x77, 0x1b, 0x4b, 0xb2, 0xc3, + 0x0e, 0xcd, 0x1d, 0xeb, 0xc2, 0x95, 0x78, 0x17, 0xae, 0xae, 0x80, 0xb3, 0x7b, 0x42, 0xb4, 0x4b, + 0xeb, 0xbd, 0x5f, 0xbb, 0x77, 0x64, 0xdd, 0x1e, 0xf3, 0xad, 0xcc, 0x6f, 0xe5, 0xef, 0xfa, 0xd3, + 0x66, 0x35, 0x99, 0x4f, 0x8f, 0xcd, 0x20, 0x0a, 0xf1, 0x19, 0xc4, 0x59, 0x30, 0xea, 0x3e, 0x74, + 0x3a, 0x1c, 0xa9, 0x5f, 0xec, 0x1f, 0x16, 0x8b, 0x61, 0x82, 0x8c, 0x5a, 0xf6, 0x81, 0xdd, 0x5a, + 0xf6, 0xc1, 0x83, 0x6c, 0xd9, 0x3f, 0x02, 0x23, 0xc4, 0x21, 0xcc, 0x90, 0xf5, 0xd6, 0x90, 0xc0, + 0x5e, 0xce, 0x85, 0xbd, 0xea, 0x10, 0x46, 0x90, 0x4d, 0x7e, 0x2c, 0xc6, 0x31, 0xa2, 0x0a, 0xe3, + 0x7d, 0x0b, 0xd5, 0x01, 0x47, 0x0e, 0xaa, 0x32, 0xd8, 0x00, 0xe3, 0xc1, 0x58, 0x84, 0x6e, 0x21, + 0x8f, 0x38, 0xf5, 0xf0, 0xc0, 0x43, 0xe2, 0xc0, 0xb7, 0xb3, 0x15, 0x78, 0x1c, 0x60, 0x3d, 0xe0, + 0xef, 0x38, 0x06, 0x7a, 0xc9, 0x75, 0xba, 0xf0, 0x8f, 0xd3, 0x60, 0x50, 0xdc, 0x22, 0xfc, 0x97, + 0x02, 0xc6, 0xd3, 0x26, 0x7f, 0xf0, 0x6a, 0xfe, 0x44, 0x1a, 0x1f, 0x3a, 0x96, 0x17, 0x7b, 0x40, + 0x08, 0xdc, 0x49, 0xbd, 0xf1, 0x93, 0x3f, 0xfe, 0xf3, 0xb3, 0x42, 0x0d, 0x5e, 0xed, 0x3e, 0xa2, + 0x8e, 0xdc, 0x4e, 0x8e, 0x16, 0xb5, 0xc7, 0x1d, 0x8e, 0xf8, 0x04, 0xfe, 0x45, 0x91, 0xb5, 0x74, + 0x3c, 0xa5, 0xc2, 0x2b, 0xf9, 0x85, 0x8c, 0x4d, 0x27, 0xcb, 0x57, 0xf7, 0x0f, 0x20, 0x95, 0x5c, + 0x14, 0x4a, 0xbe, 0x0d, 0xdf, 0xca, 0xa1, 0x64, 0x30, 0x24, 0xd4, 0x1e, 0x0b, 0xf7, 0x7f, 0x02, + 0x3f, 0x2d, 0xc8, 0xa8, 0x4c, 0x1d, 0x5f, 0xc0, 0x95, 0xec, 0x32, 0xee, 0x35, 0x8e, 0x29, 0x5f, + 0xef, 0x19, 0x47, 0xaa, 0xbc, 0x29, 0x54, 0xfe, 0x3e, 0xbc, 0x97, 0xe1, 0xa7, 0x87, 0x68, 0x0c, + 0x18, 0xeb, 0xc3, 0xe2, 0xd7, 0xab, 0x3d, 0x4e, 0xbe, 0x42, 0x69, 0x36, 0xe9, 0x6c, 0x1e, 0xf6, + 0x65, 0x93, 0x94, 0x09, 0xce, 0xbe, 0x6c, 0x92, 0x36, 0x7a, 0xd9, 0x9f, 0x4d, 0x62, 0x6a, 0x27, + 0x6d, 0x92, 0x6c, 0x5c, 0x9f, 0xc0, 0xdf, 0x2b, 0xb2, 0xcf, 0x8c, 0x8d, 0x65, 0xe0, 0xe5, 0xec, + 0x3a, 0xa4, 0x4d, 0x7b, 0xca, 0x57, 0xf6, 0xcd, 0x2f, 0x75, 0x7f, 0x53, 0xe8, 0xbe, 0x00, 0xe7, + 0xba, 0xeb, 0xce, 0x24, 0x40, 0xf0, 0x3b, 0x04, 0xfc, 0x79, 0x41, 0x3e, 0x8b, 0x7b, 0xcf, 0x59, + 0xe0, 0x9d, 0xec, 0x22, 0x66, 0x9a, 0xef, 0x94, 0xd7, 0x0e, 0x0e, 0x50, 0x1a, 0xe1, 0xa6, 0x30, + 0xc2, 0x32, 0x5c, 0xea, 0x6e, 0x04, 0x3f, 0x42, 0x6c, 0x47, 0x45, 0x6c, 0xc0, 0x0b, 0x7f, 0x5a, + 0x90, 0x15, 0xc7, 0x9e, 0x93, 0x1e, 0x78, 0x3b, 0xbb, 0x16, 0x59, 0x26, 0x50, 0xe5, 0x3b, 0x07, + 0x86, 0x27, 0x8d, 0xb2, 0x2c, 0x8c, 0x72, 0x05, 0x5e, 0xea, 0x6e, 0x14, 0xe9, 0xe5, 0x86, 0xc7, + 0x51, 0x13, 0xe9, 0xff, 0x37, 0x0a, 0x18, 0xe9, 0x18, 0xa5, 0xc0, 0x37, 0xb2, 0xcb, 0x19, 0x1b, + 0xc9, 0x94, 0xdf, 0xcc, 0xcf, 0x28, 0x35, 0x99, 0x13, 0x9a, 0xcc, 0xc2, 0x99, 0xee, 0x9a, 0x04, + 0x8f, 0x7f, 0xdb, 0xb7, 0xf7, 0x1e, 0xa7, 0xe4, 0xf1, 0xed, 0x4c, 0x73, 0x9e, 0x3c, 0xbe, 0x9d, + 0x6d, 0xd2, 0x93, 0xc7, 0xb7, 0x5d, 0x0e, 0x62, 0x10, 0xc7, 0x68, 0xb7, 0x60, 0x89, 0xcb, 0xfc, + 0x6d, 0x41, 0x0e, 0x45, 0xb3, 0xb4, 0x47, 0xf0, 0xfd, 0xfd, 0x3e, 0xd0, 0x7b, 0x76, 0x78, 0xe5, + 0xbb, 0x07, 0x0d, 0x2b, 0x2d, 0x75, 0x4f, 0x58, 0x6a, 0x03, 0xea, 0xb9, 0xab, 0x01, 0xc3, 0xc3, + 0x7e, 0xdb, 0x68, 0x69, 0x4f, 0xe2, 0xaf, 0x0b, 0xe0, 0xe5, 0x2c, 0xfd, 0x16, 0x5c, 0xeb, 0xe1, + 0xa1, 0x4f, 0xed, 0x24, 0xcb, 0xef, 0x1d, 0x20, 0xa2, 0xb4, 0x94, 0x29, 0x2c, 0x75, 0x1f, 0x7e, + 0x98, 0xc7, 0x52, 0xf1, 0xf1, 0x52, 0xf7, 0x2a, 0xe2, 0xbf, 0x0a, 0x98, 0xd8, 0x65, 0x5a, 0x00, + 0x97, 0x7a, 0x99, 0x35, 0x84, 0x86, 0xb9, 0xd6, 0x1b, 0x48, 0xfe, 0xf8, 0x8a, 0x34, 0xde, 0x35, + 0xbe, 0xfe, 0xa3, 0xc8, 0x16, 0x31, 0xad, 0x13, 0x86, 0x39, 0x26, 0x2c, 0x7b, 0x74, 0xdb, 0xe5, + 0x95, 0x5e, 0x61, 0xf2, 0x57, 0xcf, 0xbb, 0x34, 0xee, 0xf0, 0x7f, 0xc9, 0x9f, 0xf3, 0xe3, 0xad, + 0x35, 0xbc, 0x9e, 0xff, 0x8a, 0x52, 0xfb, 0xfb, 0xf2, 0x8d, 0xde, 0x81, 0x7a, 0xe8, 0x19, 0x88, + 0xa5, 0x3d, 0x8e, 0xc6, 0x0b, 0x4f, 0xe0, 0x5f, 0xc3, 0x5a, 0x30, 0x96, 0x9e, 0xf2, 0xd4, 0x82, + 0x69, 0x13, 0x84, 0xf2, 0x95, 0x7d, 0xf3, 0x4b, 0xd5, 0x56, 0x84, 0x6a, 0x57, 0xe1, 0xe5, 0xbc, + 0x09, 0x30, 0xee, 0xc5, 0xb5, 0x0f, 0xbe, 0x7c, 0x36, 0xa5, 0x7c, 0xf5, 0x6c, 0x4a, 0xf9, 0xfb, + 0xb3, 0x29, 0xe5, 0x93, 0xe7, 0x53, 0x7d, 0x5f, 0x3d, 0x9f, 0xea, 0xfb, 0xd3, 0xf3, 0xa9, 0xbe, + 0x7b, 0x97, 0xea, 0x84, 0x6d, 0xed, 0x6c, 0x56, 0x4d, 0xb7, 0x21, 0xff, 0x2f, 0xa7, 0xe3, 0xa8, + 0x0b, 0xd1, 0x51, 0xcd, 0xd7, 0xb5, 0x47, 0x89, 0xda, 0xb3, 0xe5, 0x61, 0xba, 0x39, 0x24, 0x7e, + 0x3d, 0xfc, 0xde, 0xb7, 0x01, 0x00, 0x00, 0xff, 0xff, 0x19, 0x33, 0x42, 0x36, 0x37, 0x25, 0x00, + 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2830,6 +2843,15 @@ func (m *Chain) MarshalToSizedBuffer(dAtA []byte) (int, error) { _ = i var l int _ = l + if len(m.Prioritylist) > 0 { + for iNdEx := len(m.Prioritylist) - 1; iNdEx >= 0; iNdEx-- { + i -= len(m.Prioritylist[iNdEx]) + copy(dAtA[i:], m.Prioritylist[iNdEx]) + i = encodeVarintQuery(dAtA, i, uint64(len(m.Prioritylist[iNdEx]))) + i-- + dAtA[i] = 0x7a + } + } if m.AllowlistedRewardDenoms != nil { { size, err := m.AllowlistedRewardDenoms.MarshalToSizedBuffer(dAtA[:i]) @@ -4115,6 +4137,12 @@ func (m *Chain) Size() (n int) { l = m.AllowlistedRewardDenoms.Size() n += 1 + l + sovQuery(uint64(l)) } + if len(m.Prioritylist) > 0 { + for _, s := range m.Prioritylist { + l = len(s) + n += 1 + l + sovQuery(uint64(l)) + } + } return n } @@ -5354,6 +5382,38 @@ func (m *Chain) Unmarshal(dAtA []byte) error { return err } iNdEx = postIndex + case 15: + if wireType != 2 { + return fmt.Errorf("proto: wrong wireType = %d for field Prioritylist", wireType) + } + var stringLen uint64 + for shift := uint(0); ; shift += 7 { + if shift >= 64 { + return ErrIntOverflowQuery + } + 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 ErrInvalidLengthQuery + } + postIndex := iNdEx + intStringLen + if postIndex < 0 { + return ErrInvalidLengthQuery + } + if postIndex > l { + return io.ErrUnexpectedEOF + } + m.Prioritylist = append(m.Prioritylist, string(dAtA[iNdEx:postIndex])) + iNdEx = postIndex default: iNdEx = preIndex skippy, err := skipQuery(dAtA[iNdEx:])