From da02ef346dc411b66d4f72fc9e487525fb147fb8 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Fri, 18 Oct 2024 13:28:04 +0200 Subject: [PATCH 01/12] docs: ADR for Customizable Slashing and Jailing (#2146) * turn off expensive tests * Proof of Reputation Consumer Chains ADR * Update docs/docs/adrs/adr-0XX-conditional-clients.md Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update docs/docs/adrs/adr-0XX-conditional-clients.md Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * address reviewing suggestions * Delete .github/dependabot.yml * change name of ADR * update filename * revert changes to main * update ADR -- wip * rename file * update ADR decision * suggestions from coderabbitai * Update docs/docs/adrs/adr-020-cutomizable_slashing_and_jailing.md Co-authored-by: insumity * Update docs/docs/adrs/adr-020-cutomizable_slashing_and_jailing.md Co-authored-by: insumity --------- Co-authored-by: MSalopek Co-authored-by: Bernd Mueller Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Co-authored-by: insumity --- ...dr-020-cutomizable_slashing_and_jailing.md | 185 ++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 docs/docs/adrs/adr-020-cutomizable_slashing_and_jailing.md diff --git a/docs/docs/adrs/adr-020-cutomizable_slashing_and_jailing.md b/docs/docs/adrs/adr-020-cutomizable_slashing_and_jailing.md new file mode 100644 index 0000000000..e83119eabf --- /dev/null +++ b/docs/docs/adrs/adr-020-cutomizable_slashing_and_jailing.md @@ -0,0 +1,185 @@ +--- +sidebar_position: 21 +title: Customizable Slashing and Jailing +--- +# ADR 020: Customizable Slashing and Jailing + +## Changelog +* 2024-07-19: Initial draft of ADR +* 2024-08-23: Generalize ADR to make slashing and jailing customizable + +## Status + +Proposed + +## Context + +Interchain Security (ICS) is a cross-chain staking protocol -- it uses the stake on the provider chain as collateral for the Proof of Stake (PoS) on the consumer chains. +This means that the voting power of validators validating (aka producing blocks) on the consumer chains is a function of their stake on the provider. +Moreover, if these validators misbehave on the consumer chains, they get punished on the provider chain. +ICS is currently differentiating between two types of infractions -- equivocation and downtime. +Depending on the infraction type, the misbehaving validators might be jailed (i.e., removed from the provider validator set) and / or slashed (i.e., a portion of their stake on the provider is being burned). +For example, validators double signing on consumer chains get slashed and are permanently jailed, +while validators not validating sufficient blocks are temporarily jailed. + +This means that ICS consumer chains get their economical security from the provider. +However, this might come at a high cost. + +### The Cost of PoS + +One of the cost of validating on the consumer chains is operational -- validators need to run and monitor full nodes of every consumer chain they opt in for. +Although this cost varies from validator team to validator team (depending on how efficiently they can run their infrastructure), it doesn't depend on the total stake (or voting power) of the validators, so we can think of it as constant. +The other cost of validating comes from the risk of getting slashed or jailed. + +Most chains in Cosmos (including the Cosmos Hub) use delegated PoS -- users delegate their tokens to validators, which stake them in return for voting power. +Therefore, validators act as representatives chosen by their delegators to represent their interests. +However, delegators share the risk of their validators getting slashed or jailed: + +* When validators get slashed, a portion of their stake is being burned, including a portion of the tokens delegated by users. + As validators don't need to have their own stake, it is possible that delegators take all the risk of validators misbehaving. +* When validators get jailed, they no longer receive block rewards (neither from the provider nor from the consumer chains). + This also applies to their delegators. + As a result, delegators might choose to restake their tokens with another validator. + The longer the validators are jailed, the more likely is that delegators will restake. + Thus, by getting jailed, validators risk damaging their reputation. + +Misbehaviors don't need to be malicious, e.g., most cases of double signing infractions are due to misconfiguration. +This means that, by opting in on multiple consumer chains, validators and their delegators incur a higher risk. +As a result, validators and their delegators want to be compensated for this additional risk, which makes the current design of ICS expensive. + +This ADR addresses the high cost of ICS by allowing consumer chains to customize the slashing and jailing conditions. +Basically, every consumer chain can decide the punishment for every type of infraction. +This enables consumer chains to tradeoff economical security against cost. + +## Decision + +To reduce the cost of ICS, consumer chains will be able to customize the slashing and jailing for every type of infraction. +As a result, consumer chains can decide on the amount of economic security they want and validators (and their delegators) can decide on the amount of additional risk they want to incur. + +For every consumer chain, we introduce the following slashing and jailing parameters: +```proto +message InfractionParameters { + SlashJailParameters double_sign = 1; + SlashJailParameters downtime = 2; +} + +message SlashJailParameters { + bytes slash_fraction = 1 [ + (cosmos_proto.scalar) = "cosmos.Dec", + (gogoproto.customtype) = "cosmossdk.io/math.LegacyDec", + (gogoproto.nullable) = false, + (amino.dont_omitempty) = true + ]; + // use time.Unix(253402300799, 0) for permanent jailing + google.protobuf.Duration jail_duration = 2; +} +``` +Currently, we consider only two infraction types -- double signing and downtime. + +By default, every consumer chain will have the following slashing and jailing parameters: +```go +double_sign.slash_fraction: 0.05 // same as on the provider +double_sign.jail_duration: time.Unix(253402300799, 0) // permanent jailing, same as on the provider +downtime.slash_fraction: 0 // no slashing for downtime on the consumer +downtime.jail_duration: 600s // same as on the provider +``` +These parameters can be updated by the consumer chain owner at any given time (via `MsgCreateConsumer` or `MsgUpdateConsumer`). +However, the changes will come into effect after a period equal to the staking module's unbonding period elapses. +This will allow validators that don't agree with the changes to opt out and not be affected by them. +Also, to avoid malicious chains attacking the provider validator set, these params will be bounded by the values on the provider chain: +```go +double_sign.slash_fraction <= 0.05 // 5% +downtime.slash_fraction <= 0.0001 // 0.1% +downtime.jail_duration <= 600s // 10 minutes +``` + +Although consumer chains can set any values to these parameters (within the allowed bounds), we recommend the following settings, depending on the type of consumer chain. + +* **Proof-of-Stake (PoS) Consumer Chains.** These are chains that have the full economical security of the provider validators that opted in. This means that all slashing and jailing parameters are the same as on the provider. + + ```go + double_sign.slash_fraction: 0.05 + double_sign.jail_duration: time.Unix(253402300799, 0) + downtime.slash_fraction: 0.0001 + downtime.jail_duration: 600s + ``` + +* **Proof-of-Reputation (PoR) Consumer Chains.** + + ```go + double_sign.slash_fraction: 0 // no slashing + double_sign.jail_duration: time.Unix(253402300799, 0) + downtime.slash_fraction: 0 // no slashing + downtime.jail_duration: 600s + ``` + + This means that when validators that opt in misbehave on PoR consumer chains, their stake on the provider is not being slashed, instead they are just jailed on the provider. + As a result, delegators incur (almost) no risk if their validators opt in on multiple PoR consumer chains. + If their validators are jailed, then the delegators can redelegate to other validators. + Note though that delegators cannot redelegate multiple times, which means that if the new validators also get permanently jailed, the delegators need to wait for the unbonding period to elapse. +* **Testnet Consumer Chains.** + + ```go + double_sign.slash_fraction: 0 // no slashing + double_sign.jail_duration: 0 // no jailing + downtime.slash_fraction: 0 // no slashing + downtime.jail_duration: 0 // no jailing + ``` + + This means that validators are not punished for infractions on consumer chains. + This setting is ideal for testing consumer chains before going in production, as neither validators nor their delegators incur any risk from the validators opting in on these consumer chains. + +This means that both PoR and testnet consumer chains need only to cover the operational costs of the validators that opt in. +For example, if we take `$600` as the cost of running a validator node, a budget of `$3000` will be sufficient to cover the cost of four validators running such a consumer chain and have `$150` profit per validator as incentive. +In practice, this can be implemented via the per-consumer-chain commission rate that allows validators to have different commission rates on different consumer chains. + +### Implementation + +The implementation of this feature involves the following steps: + +* Add the `InfractionParameters` to `MsgCreateConsumer`. +* On slashing events (for either downtime or double signing infractions), use the corresponding `slash_fraction` set by the consumer chain. +* On jailing events (for either downtime or double signing infractions), use the corresponding `jail_duration` set by the consumer chain. +* Cryptographic equivocation evidence received for PoR chains results in the misbehaving validators only being tombstoned and not slashed. +* (Optional) Add the `InfractionParameters` to `MsgUpdateConsumer`, i.e., allow consumer chains to update the slashing and jailing parameters, but the changes will come into effect after a period equal to the staking module's unbonding period elapses to allow for validators to opt out. + +## Consequences + +### Positive + +* Reduce the cost of ICS by removing the risk of slashing delegators. + +### Negative + +* Reduce the economical security of consumer chains with weaker slashing conditions. + +#### Economic Security Model without Slashing + +The economic security model of most Cosmos chains relies on the following properties: + +* validators are not anonymous, which means that they could be legally liable if they are malicious; +* the delegated PoS mechanism creates a reputation-based network of validators; +* most validators have most of their stake coming from delegations (i.e., nothing at stake, besides reputation); +* it is relatively difficult to enter the active validator set and even more so to climb the voting power ladder. + +These properties enable us to make the following assumption: + +* Being permanently removed from the provider validator set is strong enough of a deterrent to misbehaving on consumer chains. + +The additional economical security a consumer gets from slashing is limited: +Since most of the stake is delegated, slashing punishes delegators more than validators. + +One benefit of slashing is that it acts as a deterrent for someone buying a large amount of staking tokens in order to attack a consumer chain. +For example, an attacker could get `$15,000,000` worth of ATOM, which would give them around `1%` voting power on the Cosmos Hub (at the time of this writing). +On a consumer chain, this voting power could be amplified depending on the other validators that opt in. +However, by having the right [power shaping](https://cosmos.github.io/interchain-security/features/power-shaping) settings, the voting power of validators can be capped. +This means that even if the attacker manages to double sign without getting slashed, as long as they don't have 1/3+ of the voting power, they cannot benefit from the attack. +Moreover, the attacker might lose due to other factors, such as [token toxicity](https://forum.cosmos.network/t/enabling-opt-in-and-mesh-security-with-fraud-votes/10901). + +### Neutral + +NA + +## References + + From 31a1524177698ae9b07d36cc41f1b4dcf30495ff Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Fri, 18 Oct 2024 13:25:40 +0200 Subject: [PATCH 02/12] fix!: add check for zero rewards (#2363) * add check for zero rewards * add changelog entries --- .../unreleased/bug-fixes/2363-zero-rewards.md | 2 ++ .../state-breaking/2363-zero-rewards.md | 2 ++ x/ccv/provider/keeper/distribution.go | 34 +++++++++++-------- 3 files changed, 24 insertions(+), 14 deletions(-) create mode 100644 .changelog/unreleased/bug-fixes/2363-zero-rewards.md create mode 100644 .changelog/unreleased/state-breaking/2363-zero-rewards.md diff --git a/.changelog/unreleased/bug-fixes/2363-zero-rewards.md b/.changelog/unreleased/bug-fixes/2363-zero-rewards.md new file mode 100644 index 0000000000..819cfee817 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/2363-zero-rewards.md @@ -0,0 +1,2 @@ +- `[x/provider]` Add check for zero rewards to the rewards distribution logic. + ([\#2363](https://github.com/cosmos/interchain-security/pull/2363)) \ No newline at end of file diff --git a/.changelog/unreleased/state-breaking/2363-zero-rewards.md b/.changelog/unreleased/state-breaking/2363-zero-rewards.md new file mode 100644 index 0000000000..819cfee817 --- /dev/null +++ b/.changelog/unreleased/state-breaking/2363-zero-rewards.md @@ -0,0 +1,2 @@ +- `[x/provider]` Add check for zero rewards to the rewards distribution logic. + ([\#2363](https://github.com/cosmos/interchain-security/pull/2363)) \ No newline at end of file diff --git a/x/ccv/provider/keeper/distribution.go b/x/ccv/provider/keeper/distribution.go index 8b5a0571d7..c03ecafb1e 100644 --- a/x/ccv/provider/keeper/distribution.go +++ b/x/ccv/provider/keeper/distribution.go @@ -139,10 +139,6 @@ func (k Keeper) DeleteConsumerRewardsAllocationByDenom(ctx sdk.Context, consumer // AllocateConsumerRewards allocates the given rewards to provider consumer chain with the given consumer id func (k Keeper) AllocateConsumerRewards(ctx sdk.Context, consumerId string, alloc types.ConsumerRewardsAllocation) (types.ConsumerRewardsAllocation, error) { - if alloc.Rewards.IsZero() { - return types.ConsumerRewardsAllocation{}, nil - } - chainId, err := k.GetConsumerChainId(ctx, consumerId) if err != nil { k.Logger(ctx).Error( @@ -271,7 +267,6 @@ func (k Keeper) AllocateConsumerRewards(ctx sdk.Context, consumerId string, allo // AllocateTokens performs rewards distribution to the community pool and validators // based on the Partial Set Security distribution specification. func (k Keeper) AllocateTokens(ctx sdk.Context) { - // Iterate over all launched consumer chains. // To avoid large iterations over all the consumer IDs, iterate only over // chains with an IBC client created. @@ -302,7 +297,12 @@ func (k Keeper) AllocateTokens(ctx sdk.Context) { ) continue } - remainingRewardDec, err := k.AllocateConsumerRewards(cachedCtx, consumerId, consumerRewards) + if consumerRewards.Rewards.IsZero() { + // note that GetConsumerRewardsAllocationByDenom returns an empty ConsumerRewardsAllocation + // when there is no (consumerId, denom) key for consumer rewards allocations + continue + } + remainingRewardAllocation, err := k.AllocateConsumerRewards(cachedCtx, consumerId, consumerRewards) if err != nil { k.Logger(ctx).Error( "fail to allocate rewards for consumer chain", @@ -312,14 +312,20 @@ func (k Keeper) AllocateTokens(ctx sdk.Context) { continue } - err = k.SetConsumerRewardsAllocationByDenom(cachedCtx, consumerId, denom, remainingRewardDec) - if err != nil { - k.Logger(ctx).Error( - "fail to set rewards for consumer chain", - "consumer id", consumerId, - "error", err.Error(), - ) - continue + if remainingRewardAllocation.Rewards.IsZero() { + // if there is no remaining consumer rewards allocation, then just delete the (consumerId, denom) key + k.DeleteConsumerRewardsAllocationByDenom(cachedCtx, consumerId, denom) + } else { + // otherwise, update the consumer rewards allocation + err = k.SetConsumerRewardsAllocationByDenom(cachedCtx, consumerId, denom, remainingRewardAllocation) + if err != nil { + k.Logger(ctx).Error( + "fail to set rewards for consumer chain", + "consumer id", consumerId, + "error", err.Error(), + ) + continue + } } writeCache() From 31985a6244aa78c75c2876dd6f820a45049b6304 Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Fri, 18 Oct 2024 14:45:44 +0200 Subject: [PATCH 03/12] docs: update onboarding guidelines (#2365) * update revision height in docs * update onboarding guidelines --- docs/docs/build/modules/02-provider.md | 2 +- docs/docs/consumer-development/onboarding.md | 65 ++++++++++++++++---- x/ccv/provider/client/cli/tx.go | 4 +- 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/docs/docs/build/modules/02-provider.md b/docs/docs/build/modules/02-provider.md index 431d32e8b6..6bcf211485 100644 --- a/docs/docs/build/modules/02-provider.md +++ b/docs/docs/build/modules/02-provider.md @@ -1660,7 +1660,7 @@ where `update-consumer-msg.json` contains: "initialization_parameters":{ "initial_height":{ "revision_number": 1, - "revision_height": 0 + "revision_height": 1 }, "genesis_hash": "", "binary_hash": "", diff --git a/docs/docs/consumer-development/onboarding.md b/docs/docs/consumer-development/onboarding.md index 4350db2c14..1e48c7366f 100644 --- a/docs/docs/consumer-development/onboarding.md +++ b/docs/docs/consumer-development/onboarding.md @@ -4,14 +4,14 @@ title: Onboarding Checklist --- # Consumer Onboarding Checklist -The following checklists will aid in onboarding a new consumer chain to interchain security. +The following checklists will aid in onboarding a new consumer chain to Interchain Security. Additionally, you can check the [testnet repo](https://github.com/cosmos/testnets/blob/master/interchain-security/CONSUMER_LAUNCH_GUIDE.md) for a comprehensive guide on preparing and launching consumer chains. ## 1. Complete testing & integration - [ ] test integration with gaia -- [ ] test your protocol with supported relayer versions (minimum hermes 1.4.1) +- [ ] test your protocol with supported relayer versions (minimum hermes 1.10.2) - [ ] reach out to the ICS team if you are facing issues ## 2. Create an Onboarding Repository @@ -20,11 +20,10 @@ To help validators and other node runners onboard onto your chain, please prepar This should include (at minimum): -- [ ] genesis.json without CCV data (before the proposal passes) -- [ ] genesis.json with CCV data (after spawn time passes). Check if CCV data needs to be transformed (see [Transform Consumer Genesis](./consumer-genesis-transformation.md)) +- [ ] genesis.json without the consumer module genesis (before the spawn time passes). **Make sure the genesis time is within the trusting period (i.e., one day before launch time or shorter).** +- [ ] genesis.json with the consumer module genesis (after the spawn time passes). Check if the consumer module genesis needs to be transformed (see [Transform Consumer Genesis](./consumer-genesis-transformation.md)) - [ ] information about relevant seed/peer nodes you are running - [ ] relayer information (compatible versions) -- [ ] copy of your governance proposal (as JSON) - [ ] a script showing how to start your chain and connect to peers (optional) - [ ] take feedback from other developers, validators and community regarding your onboarding repo and make improvements where applicable @@ -35,8 +34,8 @@ Example of such a repository can be found [here](https://github.com/hyphacoop/ic Before you start your chain, you need to submit a `MsgCreateConsumer` message that generates and returns back the `consumerId` that should be used in any upcoming interactions by the consumer chain or the validators that interact with your chain. -Additionally, you need to decider whether your chain should be an Opt-In chain or a Top N chain (see [Partial Set Security](../features/partial-set-security.md)) -and act accordingly (see [Permissionless ICS](../features/permissionless.md). +Additionally, you need to decide whether your chain should be an Opt-In chain or a Top N chain (see [Partial Set Security](../features/partial-set-security.md)) +and act accordingly (see [Permissionless ICS](../features/permissionless.md)). If you create a Top N chain through, please consider allowing at least a day between your proposal passing and the chain spawn time. This will allow the validators, other node operators and the community to prepare for the chain launch. @@ -57,9 +56,9 @@ Example of initialization parameters: // ConsumerInitializationParameters provided in MsgCreateConsumer or MsgUpdateConsumer { // Initial height of new consumer chain. - // For a completely new chain, this will be {0,1}. + // For a completely new chain, this will be {1,1}. "initial_height" : { - "revision_height": 0, + "revision_height": 1, "revision_number": 1, }, // Hash of the consumer chain genesis state without the consumer CCV module genesis params. @@ -120,9 +119,9 @@ Example of power-shaping parameters: "validator_set_cap": 0, // Corresponds to a list of provider consensus addresses of validators that are the ONLY ones that can validate // the consumer chain. - "allowlist": ["cosmosvalcons1l9qq4m300z8c5ez86ak2mp8znftewkwgjlxh88"], + "allowlist": ["cosmosvalcons..."], // Corresponds to a list of provider consensus addresses of validators that CANNOT validate the consumer chain. - "denylist": [], + "denylist": ["cosmosvalcons..."], // 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. @@ -138,13 +137,53 @@ Example of allowlisted reward denoms: } ``` +:::caution +For opt-in consumer chains, make sure that at least one validator opts in before the spawn time elapses. +Otherwise the launch process will be aborted and the spawn time needs to be updated by submitting a `MsgUpdateConsumer` message. +::: + ## 4. Launch The consumer chain starts after at least 66.67% of its voting power comes online. Note that this means 66.67% of the voting power in the *consumer* validator set, which will be comprised of all validators that either opted in to the chain or are part of the top N% of the provider chain (and are thus automatically opted in). The consumer chain is considered interchain secured once the appropriate CCV channels are established and the first validator set update is propagated from the provider to the consumer -- [ ] provide a repo with onboarding instructions for validators (it should already be listed in the proposal) -- [ ] genesis.json with ccv data populated (MUST contain the initial validator set) +- [ ] provide a repo with onboarding instructions for validators +- [ ] genesis.json with the consumer module section populated (MUST contain the initial validator set) - [ ] maintenance & emergency contact info (relevant discord, telegram, slack or other communication channels) - [ ] have a block explorer in place to track chain activity & health + +### Establish CCV channel + +Once the consumer chain is launched, the CCV channel needs to be established. The following instructions are setting both the connection and channel using Hermes: + +```bash +#!/bin/bash + +# CONSUMER_CLIENT_ID is created on CONSUMER upon genesis +CONSUMER_CLIENT_ID="" +CONSUMER_CHAIN_ID="" + +# PROVIDER_CLIENT_ID is created on PROVIDER upon CONSUMER spawn time: gaiad q provider list-consumer-chains +PROVIDER_CLIENT_ID="" +PROVIDER_CHAIN_ID="" + +CONFIG=$1 +if [ -z "$CONFIG" ]; then + CONFIG=$HOME/.hermes/config.toml +fi +if [ ! -f "$CONFIG" ]; then + echo "no config file found at $CONFIG" + exit 1 +fi + +output=$(hermes --json --config $CONFIG create connection --a-chain $CONSUMER_CHAIN_ID --a-client $CONSUMER_CLIENT_ID --b-client $PROVIDER_CLIENT_ID | tee /dev/tty) +json_output=$(echo "$output" | grep 'result') +a_side_connection_id=$(echo "$json_output" | jq -r '.result.a_side.connection_id') +output=$(hermes --json --config $CONFIG create channel --a-chain $CONSUMER_CHAIN_ID --a-port consumer --b-port provider --order ordered --a-connection $a_side_connection_id --channel-version 1 | tee /dev/tty) +json_output=$(echo "$output" | grep 'result') +echo "---- DONE ----" +echo "$json_output" | jq + +# hermes start +``` diff --git a/x/ccv/provider/client/cli/tx.go b/x/ccv/provider/client/cli/tx.go index d1caeb1d6f..ec694fd49e 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -234,7 +234,7 @@ where create_consumer.json has the following structure: "initialization_parameters": { "initial_height": { "revision_number": 1, - "revision_height": 0 + "revision_height": 1 }, "genesis_hash": "", "binary_hash": "", @@ -332,7 +332,7 @@ where update_consumer.json has the following structure: "initialization_parameters": { "initial_height": { "revision_number": 1, - "revision_height": 0 + "revision_height": 1 }, "genesis_hash": "", "binary_hash": "", From 61cdfaaab5e9537af6594ce53799ff504b15183c Mon Sep 17 00:00:00 2001 From: Marius Poke Date: Fri, 18 Oct 2024 15:57:32 +0200 Subject: [PATCH 04/12] chore: update mergify and dependabot (#2369) update mergify and dependabot --- .github/dependabot.yml | 10 ++++++++++ .mergify.yml | 10 +++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 3f46ed095d..12d4d9d017 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -77,3 +77,13 @@ updates: open-pull-requests-limit: 0 labels: - dependencies + + - package-ecosystem: gomod + directory: "/" + schedule: + interval: daily + target-branch: "release/v6.3.x" + # Only allow automated security-related dependency updates on release branches. + open-pull-requests-limit: 0 + labels: + - dependencies diff --git a/.mergify.yml b/.mergify.yml index 60db329871..038ba5cf54 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -57,4 +57,12 @@ pull_request_rules: actions: backport: branches: - - release/v6.2.x \ No newline at end of file + - release/v6.2.x + - name: Backport patches to the release/v6.3.x branch + conditions: + - base=main + - label=A:backport/v6.3.x + actions: + backport: + branches: + - release/v6.3.x \ No newline at end of file From 0d6f75f6d1252291903951af827e6dfbf081e069 Mon Sep 17 00:00:00 2001 From: rusttech Date: Fri, 25 Oct 2024 20:53:15 +0800 Subject: [PATCH 05/12] fix: fix slice init length (#2345) --- x/ccv/provider/keeper/consumer_equivocation.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x/ccv/provider/keeper/consumer_equivocation.go b/x/ccv/provider/keeper/consumer_equivocation.go index 0fc95f639b..a7c3d2025e 100644 --- a/x/ccv/provider/keeper/consumer_equivocation.go +++ b/x/ccv/provider/keeper/consumer_equivocation.go @@ -184,7 +184,7 @@ func (k Keeper) HandleConsumerMisbehaviour(ctx sdk.Context, consumerId string, m return err } - provAddrs := make([]types.ProviderConsAddress, len(byzantineValidators)) + provAddrs := make([]types.ProviderConsAddress, 0, len(byzantineValidators)) // slash, jail, and tombstone the Byzantine validators for _, v := range byzantineValidators { From dd0929472d70da812537609f6383cb9d1ff3ca99 Mon Sep 17 00:00:00 2001 From: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> Date: Fri, 25 Oct 2024 18:50:48 +0200 Subject: [PATCH 06/12] feat!: Add support for priority validators (#2101) * Start adding priority validators * Add new priority_validator field * Added priority list to the PowerShapingParameters * Add documentation for priority list * Add priority list in local-testnet.sh * Update .changelog/unreleased/features/provider/xxxx-priority-validators.md Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update x/ccv/provider/keeper/power_shaping.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update x/ccv/provider/keeper/power_shaping_test.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update x/ccv/provider/keeper/power_shaping_test.go Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Update .changelog/unreleased/api-breaking/provider/xxxx-priority-validators.md Co-authored-by: Philip Offtermatt <57488781+p-offtermatt@users.noreply.github.com> * Fix typo in provider.proto * Remove unnecessary priority list from test in steps_permissionless_ics.go * Remove comment from grpc_query.go * Add e2e test for priority list * Improved e2e test * Fixed some issues * Refactored code logic * Refactored code logic * Renamed files * Removed priority list from migrations.go * Fixed bug for priority list * Added priority list to e2e nightly tests * Update tx.go * Refactored TestCapValidatorSet * Small fixes * Small fixes * Fix PartitionBasedOnPriorityList function * Update contrib/local-testnet.sh Co-authored-by: Marius Poke * Moved 2101-introduce-priority-validators.md into state-breaking * Fixed TestGetConsumerChain * Added test case in TestCapValidatorSet * Revert changes made by the merge * Removed changes from ADRs that were already implemented * Added a comment in CapValidatorSet function * Removed unnecessary imports --------- Co-authored-by: kirdatatjana Co-authored-by: kirdatatjana <116630536+kirdatatjana@users.noreply.github.com> Co-authored-by: Marius Poke --- .../2101-introduce-priority-validators.md | 2 + .../2101-introduce-priority-validators.md | 2 + .github/workflows/nightly-e2e.yml | 17 + contrib/local-testnet.sh | 3 +- docs/docs/build/modules/02-provider.md | 13 +- docs/docs/consumer-development/onboarding.md | 4 +- docs/docs/features/power-shaping.md | 4 + .../ccv/provider/v1/provider.proto | 152 +++++--- .../ccv/provider/v1/query.proto | 5 + tests/e2e/actions.go | 9 + tests/e2e/main.go | 7 + tests/e2e/steps_partial_set_security.go | 184 +++++++++ testutil/keeper/unit_test_helpers.go | 1 + x/ccv/provider/client/cli/tx.go | 6 +- x/ccv/provider/client/legacy_proposals.go | 2 + x/ccv/provider/keeper/consumer_lifecycle.go | 1 + .../keeper/consumer_lifecycle_test.go | 5 + x/ccv/provider/keeper/grpc_query.go | 7 + x/ccv/provider/keeper/grpc_query_test.go | 17 +- x/ccv/provider/keeper/power_shaping.go | 116 +++++- x/ccv/provider/keeper/power_shaping_test.go | 237 +++++++++--- x/ccv/provider/keeper/validator_set_update.go | 4 +- x/ccv/provider/types/keys.go | 16 + x/ccv/provider/types/keys_test.go | 3 + x/ccv/provider/types/msg.go | 3 + x/ccv/provider/types/msg_test.go | 4 + x/ccv/provider/types/provider.pb.go | 346 ++++++++++------- x/ccv/provider/types/query.pb.go | 362 ++++++++++-------- 28 files changed, 1106 insertions(+), 426 deletions(-) create mode 100644 .changelog/unreleased/features/provider/2101-introduce-priority-validators.md create mode 100644 .changelog/unreleased/state-breaking/2101-introduce-priority-validators.md diff --git a/.changelog/unreleased/features/provider/2101-introduce-priority-validators.md b/.changelog/unreleased/features/provider/2101-introduce-priority-validators.md new file mode 100644 index 0000000000..a90e0a6e26 --- /dev/null +++ b/.changelog/unreleased/features/provider/2101-introduce-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/state-breaking/2101-introduce-priority-validators.md b/.changelog/unreleased/state-breaking/2101-introduce-priority-validators.md new file mode 100644 index 0000000000..a90e0a6e26 --- /dev/null +++ b/.changelog/unreleased/state-breaking/2101-introduce-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/.github/workflows/nightly-e2e.yml b/.github/workflows/nightly-e2e.yml index efac898687..2751aa598f 100644 --- a/.github/workflows/nightly-e2e.yml +++ b/.github/workflows/nightly-e2e.yml @@ -277,6 +277,22 @@ jobs: go-version: "1.22" # The Go version to download (if necessary) and use. - name: E2E partial set security denylist run: go run ./tests/e2e/... --tc partial-set-security-validators-denylisted + partial-set-security-validators-prioritylisted-test: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/setup-go@v5 + with: + go-version: "1.22" + - uses: actions/checkout@v4 + - name: Checkout LFS objects + run: git lfs checkout + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: "1.22" # The Go version to download (if necessary) and use. + - name: E2E partial set security prioritylist + run: go run ./tests/e2e/... --tc partial-set-security-validators-prioritylisted partial-set-security-modification-proposal: runs-on: ubuntu-latest timeout-minutes: 20 @@ -376,6 +392,7 @@ jobs: - partial-set-security-validators-power-cap-test - partial-set-security-validators-allowlisted-test - partial-set-security-validators-denylisted-test + - partial-set-security-validators-prioritylisted-test - partial-set-security-modification-proposal - active-set-changes-test - permissionless-basic-test diff --git a/contrib/local-testnet.sh b/contrib/local-testnet.sh index 3aebbbe262..a321bfe7f1 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 1e48c7366f..1613a2f268 100644 --- a/docs/docs/consumer-development/onboarding.md +++ b/docs/docs/consumer-development/onboarding.md @@ -125,7 +125,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 06bc94c6af..f43bf0bc5e 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 929ce7be30..b6038025ed 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 ec694fd49e..52a53f3ebe 100644 --- a/x/ccv/provider/client/cli/tx.go +++ b/x/ccv/provider/client/cli/tx.go @@ -254,7 +254,8 @@ where create_consumer.json has the following structure: "allowlist": ["cosmosvalcons..."], "denylist": ["cosmosvalcons..."], "min_stake": 0, - "allow_inactive_vals": false + "allow_inactive_vals": false, + "prioritylist": ["cosmosvalcons..."] }, "allowlisted_reward_denoms": { "denoms": ["ibc/...", "ibc/..."] @@ -352,7 +353,8 @@ where update_consumer.json has the following structure: "allowlist": ["cosmosvalcons..."], "denylist": ["cosmosvalcons..."], "min_stake": 0, - "allow_inactive_vals": false + "allow_inactive_vals": false, + "prioritylist": ["cosmosvalcons..."] }, "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 200c2b949f..f90c359e4c 100644 --- a/x/ccv/provider/keeper/consumer_lifecycle_test.go +++ b/x/ccv/provider/keeper/consumer_lifecycle_test.go @@ -226,6 +226,7 @@ func TestBeginBlockLaunchConsumers(t *testing.T) { ValidatorSetCap: 0, Allowlist: []string{}, Denylist: []string{}, + Prioritylist: []string{}, }, { Top_N: 50, @@ -233,6 +234,7 @@ func TestBeginBlockLaunchConsumers(t *testing.T) { ValidatorSetCap: 0, Allowlist: []string{}, Denylist: []string{}, + Prioritylist: []string{}, }, { Top_N: 50, @@ -240,6 +242,7 @@ func TestBeginBlockLaunchConsumers(t *testing.T) { ValidatorSetCap: 0, Allowlist: []string{}, Denylist: []string{}, + Prioritylist: []string{}, }, { Top_N: 0, @@ -247,6 +250,7 @@ func TestBeginBlockLaunchConsumers(t *testing.T) { ValidatorSetCap: 0, Allowlist: []string{}, Denylist: []string{}, + Prioritylist: []string{}, }, { Top_N: 0, @@ -254,6 +258,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 a8fe617f53..5f664a331a 100644 --- a/x/ccv/provider/keeper/grpc_query_test.go +++ b/x/ccv/provider/keeper/grpc_query_test.go @@ -451,7 +451,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{ @@ -490,6 +495,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() @@ -500,6 +508,11 @@ func TestGetConsumerChain(t *testing.T) { strDenylist[j] = addr.String() } + strPrioritylist := make([]string, len(prioritylists[i])) + for j, addr := range prioritylists[i] { + strPrioritylist[j] = addr.String() + } + metadataLists = append(metadataLists, types.ConsumerMetadata{Name: chainIDs[i]}) pk.SetConsumerMetadata(ctx, consumerID, metadataLists[i]) @@ -524,6 +537,7 @@ func TestGetConsumerChain(t *testing.T) { MinStake: minStakes[i].Uint64(), ConsumerId: consumerIDs[i], AllowlistedRewardDenoms: allowlistedRewardDenoms[i], + Prioritylist: strPrioritylist, }) } @@ -674,6 +688,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..1c789ce30f 100644 --- a/x/ccv/provider/keeper/power_shaping.go +++ b/x/ccv/provider/keeper/power_shaping.go @@ -88,7 +88,7 @@ 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. +// If cap is `k`, `CapValidatorSet` returns the first `k` validators from `validators`. func (k Keeper) CapValidatorSet( ctx sdk.Context, powerShapingParameters types.PowerShapingParameters, @@ -101,10 +101,7 @@ func (k Keeper) CapValidatorSet( 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 - }) - + // validators are already sorted by priority and power return validators[:int(validatorSetCap)] } else { return validators @@ -337,13 +334,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 prioritylist 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 +551,107 @@ 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) + return store.Get(types.PrioritylistKey(consumerId, providerAddr)) != 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)) + } +} + +// PartitionBasedOnPriorityList 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) PartitionBasedOnPriorityList(ctx sdk.Context, consumerId string, nextValidators []types.ConsensusValidator) ([]types.ConsensusValidator, []types.ConsensusValidator) { + + priorityValidators := make([]types.ConsensusValidator, 0) + nonPriorityValidators := make([]types.ConsensusValidator, 0) + + // Form priorityValidators + for _, validator := range nextValidators { + addr := types.NewProviderConsAddress(validator.ProviderConsAddr) + if k.IsPrioritylisted(ctx, consumerId, addr) { + priorityValidators = append(priorityValidators, validator) + } else { + // Add remaining validators to nonPriorityValidators + 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..20358db3f4 100644 --- a/x/ccv/provider/keeper/power_shaping_test.go +++ b/x/ccv/provider/keeper/power_shaping_test.go @@ -250,74 +250,134 @@ 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{}, - } - validators := []providertypes.ConsensusValidator{validatorA, validatorB, validatorC} + valAddrA := "cosmosvalcons1ezyrq65s3gshhx5585w6mpusq3xsj3ayzf4uv6" + valAddrB := "cosmosvalcons1nx7n5uh0ztxsynn4sje6eyq2ud6rc6klc96w39" + valAddrC := "cosmosvalcons1qmq08eruchr5sf5s3rwz7djpr5a25f7xw4mceq" + valAddrD := "cosmosvalcons1kswr5sq599365kcjmhgufevfps9njf43e4lwdk" + + validatorA := providertypes.ConsensusValidator{ProviderConsAddr: consAddressFromBech32(valAddrA), Power: 1, PublicKey: &crypto.PublicKey{}} + validatorB := providertypes.ConsensusValidator{ProviderConsAddr: consAddressFromBech32(valAddrB), Power: 2, PublicKey: &crypto.PublicKey{}} + validatorC := providertypes.ConsensusValidator{ProviderConsAddr: consAddressFromBech32(valAddrC), Power: 3, PublicKey: &crypto.PublicKey{}} + validatorD := providertypes.ConsensusValidator{ProviderConsAddr: consAddressFromBech32(valAddrD), Power: 4, PublicKey: &crypto.PublicKey{}} + validators := []providertypes.ConsensusValidator{validatorA, validatorB, validatorC, validatorD} + // Initial error check powerShapingParameters, err := providerKeeper.GetConsumerPowerShapingParameters(ctx, CONSUMER_ID) require.Error(t, err) - consumerValidators := providerKeeper.CapValidatorSet(ctx, powerShapingParameters, 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) + priorityValidators, nonPriorityValidators := providerKeeper.PartitionBasedOnPriorityList(ctx, CONSUMER_ID, validators) + consumerValidators := providerKeeper.CapValidatorSet(ctx, powerShapingParameters, append(priorityValidators, nonPriorityValidators...)) + require.Equal(t, []providertypes.ConsensusValidator{validatorD, validatorC, validatorB, validatorA}, 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 + expectedValidators []providertypes.ConsensusValidator + expectError bool + }{ + { + name: "ValidatorSetCap = 0 (no capping)", + powerShapingParameters: providertypes.PowerShapingParameters{ValidatorSetCap: 0}, + expectedValidators: []providertypes.ConsensusValidator{validatorD, validatorC, validatorB, validatorA}, + }, + { + name: "ValidatorSetCap = 0, with priority list", + powerShapingParameters: providertypes.PowerShapingParameters{ + ValidatorSetCap: 0, + Prioritylist: []string{ + valAddrA, + valAddrB, + }, + }, + expectedValidators: []providertypes.ConsensusValidator{validatorB, validatorA, validatorD, validatorC}, + }, + { + 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{ + valAddrA, + valAddrB, + }, + }, + expectedValidators: []providertypes.ConsensusValidator{validatorB, validatorA}, + }, + { + name: "ValidatorSetCap = 3, with partial priority list", + powerShapingParameters: providertypes.PowerShapingParameters{ + ValidatorSetCap: 3, + Prioritylist: []string{valAddrA}, + }, + expectedValidators: []providertypes.ConsensusValidator{validatorA, validatorD, validatorC}, + }, + { + name: "All validators in priority list", + powerShapingParameters: providertypes.PowerShapingParameters{ + ValidatorSetCap: 4, + Prioritylist: []string{ + valAddrC, + valAddrA, + valAddrD, + valAddrB, + }, + }, + expectedValidators: []providertypes.ConsensusValidator{validatorD, validatorC, validatorB, validatorA}, + }, + { + name: "ValidatorSetCap = 1 (capping to highest power, with priority list)", + powerShapingParameters: providertypes.PowerShapingParameters{ + ValidatorSetCap: 1, + Prioritylist: []string{valAddrA}, + }, + expectedValidators: []providertypes.ConsensusValidator{validatorA}, + }, + } - 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) + if tc.expectError { + require.Error(t, err) + } else { + require.NoError(t, err) + require.Equal(t, tc.powerShapingParameters, powerShapingParameters) + } + priorityValidators, nonPriorityValidators := providerKeeper.PartitionBasedOnPriorityList(ctx, CONSUMER_ID, validators) + consumerValidators := providerKeeper.CapValidatorSet(ctx, powerShapingParameters, append(priorityValidators, nonPriorityValidators...)) + require.Equal(t, tc.expectedValidators, consumerValidators) + }) + } +} - 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) +// Helper function to handle address conversion +func consAddressFromBech32(addr string) sdk.ConsAddress { + consAddr, err := sdk.ConsAddressFromBech32(addr) + if err != nil { + panic(fmt.Sprintf("invalid consensus address: %s", addr)) + } + return consAddr } func TestCapValidatorsPower(t *testing.T) { @@ -745,11 +805,14 @@ 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) expectedDenylist := []providertypes.ProviderConsAddress{providerConsAddr[2], providerConsAddr[3]} sortProviderConsAddr(expectedDenylist) + expectedPrioritylist := []providertypes.ProviderConsAddress{providerConsAddr[1]} + sortProviderConsAddr(expectedPrioritylist) err = providerKeeper.SetConsumerPowerShapingParameters(ctx, consumerId, expectedPowerShapingParameters) require.NoError(t, err) actualPowerShapingParameters, err := providerKeeper.GetConsumerPowerShapingParameters(ctx, consumerId) @@ -757,6 +820,7 @@ func TestConsumerPowerShapingParameters(t *testing.T) { require.Equal(t, expectedPowerShapingParameters, actualPowerShapingParameters) require.Equal(t, expectedAllowlist, providerKeeper.GetAllowList(ctx, consumerId)) require.Equal(t, expectedDenylist, providerKeeper.GetDenyList(ctx, consumerId)) + require.Equal(t, expectedPrioritylist, providerKeeper.GetPriorityList(ctx, consumerId)) // assert that overwriting the current initialization record works expectedPowerShapingParameters = providertypes.PowerShapingParameters{ @@ -767,11 +831,14 @@ 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) expectedDenylist = []providertypes.ProviderConsAddress{providerConsAddr[2], providerConsAddr[3]} sortProviderConsAddr(expectedDenylist) + expectedPrioritylist = []providertypes.ProviderConsAddress{providerConsAddr[4], providerConsAddr[5]} + sortProviderConsAddr(expectedAllowlist) err = providerKeeper.SetConsumerPowerShapingParameters(ctx, consumerId, expectedPowerShapingParameters) require.NoError(t, err) actualPowerShapingParameters, err = providerKeeper.GetConsumerPowerShapingParameters(ctx, consumerId) @@ -779,6 +846,7 @@ func TestConsumerPowerShapingParameters(t *testing.T) { require.Equal(t, expectedPowerShapingParameters, actualPowerShapingParameters) require.Equal(t, expectedAllowlist, providerKeeper.GetAllowList(ctx, consumerId)) require.Equal(t, expectedDenylist, providerKeeper.GetDenyList(ctx, consumerId)) + require.Equal(t, expectedPrioritylist, providerKeeper.GetPriorityList(ctx, consumerId)) } // TestAllowlist tests the `SetAllowlist`, `IsAllowlisted`, `DeleteAllowlist`, and `IsAllowlistEmpty` methods @@ -1006,3 +1074,50 @@ 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)) +} diff --git a/x/ccv/provider/keeper/validator_set_update.go b/x/ccv/provider/keeper/validator_set_update.go index d375d42d8f..265911d5d2 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.PartitionBasedOnPriorityList(ctx, consumerId, nextValidators) + + nextValidators = k.CapValidatorSet(ctx, powerShapingParameters, append(priorityValidators, nonPriorityValidators...)) nextValidators = k.CapValidatorsPower(ctx, powerShapingParameters.ValidatorsPowerCap, nextValidators) 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 acfdf1bd8b..91a5282c4f 100644 --- a/x/ccv/provider/types/msg.go +++ b/x/ccv/provider/types/msg.go @@ -529,6 +529,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 b0f0f11102..f1eaa3124a 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:]) From 3c3db71c5cab78a18ad82746b94fcb78afc5a19c Mon Sep 17 00:00:00 2001 From: Jehan Date: Mon, 28 Oct 2024 07:44:48 -0700 Subject: [PATCH 07/12] docs: add spawn page to docs (#2338) * add spawn page * add .md extension to doc; change links * update dead link to new one --------- Co-authored-by: MSalopek --- .../consumer-development/app-integration.md | 3 +- .../changeover-procedure.md | 2 +- .../consumer-chain-governance.md | 2 +- .../consumer-genesis-transformation.md | 2 +- .../consumer-development/create-with-spawn.md | 107 ++++++++++++++++++ docs/docs/consumer-development/offboarding.md | 2 +- docs/docs/consumer-development/onboarding.md | 5 +- 7 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 docs/docs/consumer-development/create-with-spawn.md diff --git a/docs/docs/consumer-development/app-integration.md b/docs/docs/consumer-development/app-integration.md index 0671db05a7..57ec14fc48 100644 --- a/docs/docs/consumer-development/app-integration.md +++ b/docs/docs/consumer-development/app-integration.md @@ -1,5 +1,5 @@ --- -sidebar_position: 1 +sidebar_position: 2 --- # Developing an ICS consumer chain @@ -31,4 +31,3 @@ With these modules enabled, the consumer chain can mint its own governance token ## Standalone chain to consumer chain changeover See the [standalone chain to consumer chain changeover guide](./changeover-procedure.md) for more information on how to transition your standalone chain to a consumer chain. - diff --git a/docs/docs/consumer-development/changeover-procedure.md b/docs/docs/consumer-development/changeover-procedure.md index 240925fc0d..17b8faa713 100644 --- a/docs/docs/consumer-development/changeover-procedure.md +++ b/docs/docs/consumer-development/changeover-procedure.md @@ -1,5 +1,5 @@ --- -sidebar_position: 5 +sidebar_position: 6 --- # Changeover Procedure diff --git a/docs/docs/consumer-development/consumer-chain-governance.md b/docs/docs/consumer-development/consumer-chain-governance.md index c8586efe3a..86b56f8418 100644 --- a/docs/docs/consumer-development/consumer-chain-governance.md +++ b/docs/docs/consumer-development/consumer-chain-governance.md @@ -1,5 +1,5 @@ --- -sidebar_position: 2 +sidebar_position: 3 --- # Consumer Chain Governance diff --git a/docs/docs/consumer-development/consumer-genesis-transformation.md b/docs/docs/consumer-development/consumer-genesis-transformation.md index d77e8ec559..360332aa25 100644 --- a/docs/docs/consumer-development/consumer-genesis-transformation.md +++ b/docs/docs/consumer-development/consumer-genesis-transformation.md @@ -1,5 +1,5 @@ --- -sidebar_position: 6 +sidebar_position: 7 --- # Consumer Genesis Transformation diff --git a/docs/docs/consumer-development/create-with-spawn.md b/docs/docs/consumer-development/create-with-spawn.md new file mode 100644 index 0000000000..07e202b041 --- /dev/null +++ b/docs/docs/consumer-development/create-with-spawn.md @@ -0,0 +1,107 @@ +--- +sidebar_position: 1 +--- + +# Create an ICS chain with Spawn + +## Requirements + +- [`go 1.22+`](https://go.dev/doc/install) +- [`Docker`](https://docs.docker.com/get-docker/) + +[MacOS + Ubuntu Setup](https://github.com/rollchains/spawn/blob/release/v0.50/docs/versioned_docs/version-v0.50.x/01-setup/01-system-setup.md) + +## Getting Started + +**Note:** This tutorial focuses on using the Spawn CLI to create an ICS consumer chain. For more complete documentation on Spawn, see the [Spawn documentation](https://rollchains.github.io/spawn/v0.50/). + +In this tutorial, we'll create and interact with a new Interchain security enabled blockchain called "consumer", with the token denomination "uconsu". + +1. Clone this repo and install + +```shell +git clone https://github.com/rollchains/spawn.git +cd spawn +git checkout v0.50.4 +make install +``` + +2. Create your chain using the `spawn` command and customize it to your needs! + +```shell +GITHUB_USERNAME= + +spawn new consumer \ +--consensus=interchain-security \ +--bech32=consu `# the prefix for addresses` \ +--denom=uconsu `# the coin denomination to create` \ +--bin=consumerd `# the name of the binary` \ +--disabled=tokenfactory,globalfee,ibc-packetforward,ibc-ratelimit,cosmwasm,wasm-light-client,optimistic-execution,ignite-cli `# disable features. [tokenfactory,globalfee,ibc-packetforward,ibc-ratelimit,cosmwasm,wasm-light-client,ignite-cli]` \ +--org=${GITHUB_USERNAME} `# the github username or organization to use for the module imports, optional` +``` + +> _NOTE:_ `spawn` creates a ready to use repository complete with `git` and GitHub CI. It can be quickly pushed to a new repository getting you and your team up and running quickly. + +3. Spin up a local testnet for your chain + +```shell +cd consumer + +# Starts 2 networks for the IBC testnet at http://127.0.0.1:8080. +# - Builds the docker image of your chain +# - Launches a testnet with IBC automatically connected and relayed +# +# Note: you can run a single node, non IBC testnet, with `make sh-testnet`. +make testnet +``` + +4. Open a new terminal window and send a transaction on your new chain + +```shell +# list the keys that have been provisioned with funds in genesis +consumerd keys list + +# send a transaction from one account to another +consumerd tx bank send acc0 $(consumerd keys show acc1 -a) 1337uconsu --chain-id=localchain-1 + +# enter "y" to confirm the transaction +# then query your balances tfor proof the transaction executed successfully +consumerd q bank balances $(consumerd keys show acc1 -a) +``` + +5. (optional) Send an IBC transaction + +```shell +# submit a cross chain transfer from acc0 to the other address +consumerd tx ibc-transfer transfer transfer channel-0 cosmos1hj5fveer5cjtn4wd6wstzugjfdxzl0xpxvjjvr 7uconsu --from=acc0 --chain-id=localchain-1 --yes + +# Query the other side to confirm it went through +sleep 10 + +# Interact with the other chain without having to install the cosmos binary +# - Endpoints found at: GET http://127.0.0.1:8080/info +local-ic interact localcosmos-1 query 'bank balances cosmos1hj5fveer5cjtn4wd6wstzugjfdxzl0xpxvjjvr' --api-endpoint=http://127.0.0.1:8080 +``` + +6. Push your new chain to a github repository + +```shell +# Create a new repository on GitHub from the gh cli +gh repo create ics-consumer --source=. --remote=origin --push +``` + +> You can also push it the old fashioned way with https://github.com/new and `git push origin main`. + +In this tutorial, we configured a new custom chain, launched a testnet for it, tested a simple token transfer, and confirmed it was successful. +This tutorial demonstrates just how easy it is to create a brand new custom Cosmos-SDK blockchain from scratch, saving developers time. + +## Modify your chain + +New module code is usually added in the `x/` directory of your repository. +Check out the [Cosmos SDK documentation](https://docs.cosmos.network/v0.50/build/building-modules/intro) for more information on how to add modules to your chain. + +Once you're ready you can preview your chain using the section below. + +## List your chain + +You can [list your chain on Forge](https://forge.cosmos.network/list-your-chain), even if it's not finished, in the **pre-launch** stage. diff --git a/docs/docs/consumer-development/offboarding.md b/docs/docs/consumer-development/offboarding.md index ff252ad550..0567566ed2 100644 --- a/docs/docs/consumer-development/offboarding.md +++ b/docs/docs/consumer-development/offboarding.md @@ -1,5 +1,5 @@ --- -sidebar_position: 4 +sidebar_position: 5 title: Offboarding Checklist --- # Consumer Offboarding diff --git a/docs/docs/consumer-development/onboarding.md b/docs/docs/consumer-development/onboarding.md index 1613a2f268..5d6f42ef20 100644 --- a/docs/docs/consumer-development/onboarding.md +++ b/docs/docs/consumer-development/onboarding.md @@ -1,7 +1,8 @@ --- -sidebar_position: 3 +sidebar_position: 4 title: Onboarding Checklist --- + # Consumer Onboarding Checklist The following checklists will aid in onboarding a new consumer chain to Interchain Security. @@ -52,6 +53,7 @@ gather community support and accept feedback from the community, validators and - [ ] if desired, decide on power-shaping parameters (see [Power Shaping](../features/power-shaping.md)) Example of initialization parameters: + ```js // ConsumerInitializationParameters provided in MsgCreateConsumer or MsgUpdateConsumer { @@ -100,6 +102,7 @@ Example of initialization parameters: ``` Example of power-shaping parameters: + ```js // PowerShaping parameters provided in MsgCreateConsumer or MsgUpdateConsumer { From 956aede8d6ca93c88a7113c8fa6118fb7bc517c3 Mon Sep 17 00:00:00 2001 From: Jehan Date: Tue, 29 Oct 2024 12:35:05 -0700 Subject: [PATCH 08/12] docs: update spawn install instructions (#2379) update spawn install instructions --- .../consumer-development/create-with-spawn.md | 57 ++++++++++++++++--- 1 file changed, 48 insertions(+), 9 deletions(-) diff --git a/docs/docs/consumer-development/create-with-spawn.md b/docs/docs/consumer-development/create-with-spawn.md index 07e202b041..752b784113 100644 --- a/docs/docs/consumer-development/create-with-spawn.md +++ b/docs/docs/consumer-development/create-with-spawn.md @@ -17,27 +17,66 @@ sidebar_position: 1 In this tutorial, we'll create and interact with a new Interchain security enabled blockchain called "consumer", with the token denomination "uconsu". -1. Clone this repo and install +1. Install Spawn ```shell -git clone https://github.com/rollchains/spawn.git +# Install from latest source +git clone https://github.com/rollchains/spawn.git --depth 1 --branch v0.50.10 + +# Change to this directory cd spawn -git checkout v0.50.4 + +# Clear Go modules cache for a fresh install +go clean -modcache + +# Install Spawn make install + +# Install Local Interchain (testnet runner) +make get-localic + +# Install docker container builder +make get-heighliner + +# Verify installations were successful +spawn + +local-ic + +heighliner + +# If you get "command 'spawn' not found", run the following +# Linux / Windows / Some MacOS +echo 'export PATH=$PATH:$(go env GOPATH)/bin' >> ~/.bashrc +source ~/.bashrc + +# MacOS +echo 'export PATH=$PATH:$(go env GOPATH)/bin' >> ~/.zshrc +source ~/.zshrc + +# Legacy MacOS Go +echo 'export PATH=$PATH:$HOME/go/bin' >> ~/.zshrc +source ~/.zshrc + +# Sometimes it can be good to also clear your cache +# especially WSL users +go clean -cache + + ``` 2. Create your chain using the `spawn` command and customize it to your needs! ```shell -GITHUB_USERNAME= +GITHUB_USERNAME= spawn new consumer \ --consensus=interchain-security \ ---bech32=consu `# the prefix for addresses` \ ---denom=uconsu `# the coin denomination to create` \ ---bin=consumerd `# the name of the binary` \ ---disabled=tokenfactory,globalfee,ibc-packetforward,ibc-ratelimit,cosmwasm,wasm-light-client,optimistic-execution,ignite-cli `# disable features. [tokenfactory,globalfee,ibc-packetforward,ibc-ratelimit,cosmwasm,wasm-light-client,ignite-cli]` \ ---org=${GITHUB_USERNAME} `# the github username or organization to use for the module imports, optional` +--bech32=consu \ +--denom=uconsu \ +--bin=consumerd \ +--disabled=tokenfactory,ibc-packetforward,ibc-ratelimit,cosmwasm,wasm-light-client \ +--org=${GITHUB_USERNAME} ``` > _NOTE:_ `spawn` creates a ready to use repository complete with `git` and GitHub CI. It can be quickly pushed to a new repository getting you and your team up and running quickly. From 399c833a515ce3be176f4e1cf7e7d2d2ecb66703 Mon Sep 17 00:00:00 2001 From: Sergey <83376337+freak12techno@users.noreply.github.com> Date: Thu, 31 Oct 2024 12:49:15 +0300 Subject: [PATCH 09/12] fix: fix consumer chains list pagination (#2377) * chore: fix consumer chains list pagination * chore: added CHANGELOG entry * chore: review fixes --- .../2377-fix-list-consumer-chains-pagination.md | 2 ++ x/ccv/provider/keeper/grpc_query.go | 15 +++++++++------ x/ccv/provider/keeper/grpc_query_test.go | 13 ++++++++++++- 3 files changed, 23 insertions(+), 7 deletions(-) create mode 100644 .changelog/unreleased/bug-fixes/2377-fix-list-consumer-chains-pagination.md diff --git a/.changelog/unreleased/bug-fixes/2377-fix-list-consumer-chains-pagination.md b/.changelog/unreleased/bug-fixes/2377-fix-list-consumer-chains-pagination.md new file mode 100644 index 0000000000..28623ee3e2 --- /dev/null +++ b/.changelog/unreleased/bug-fixes/2377-fix-list-consumer-chains-pagination.md @@ -0,0 +1,2 @@ +- `[x/provider]` Fixed pagination in the list consumer chains query. + ([\#2377](https://github.com/cosmos/interchain-security/pull/2377)) \ No newline at end of file diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index dfc6b06501..2d0c1e1d10 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -56,23 +56,26 @@ func (k Keeper) QueryConsumerChains(goCtx context.Context, req *types.QueryConsu store := ctx.KVStore(k.storeKey) storePrefix := types.ConsumerIdToPhaseKeyPrefix() consumerPhaseStore := prefix.NewStore(store, []byte{storePrefix}) - pageRes, err := query.Paginate(consumerPhaseStore, req.Pagination, func(key, value []byte) error { + pageRes, err := query.FilteredPaginate(consumerPhaseStore, req.Pagination, func(key, value []byte, accumulate bool) (bool, error) { consumerId, err := types.ParseStringIdWithLenKey(storePrefix, append([]byte{storePrefix}, key...)) if err != nil { - return status.Error(codes.Internal, err.Error()) + return false, status.Error(codes.Internal, err.Error()) } phase := types.ConsumerPhase(binary.BigEndian.Uint32(value)) if req.Phase != types.CONSUMER_PHASE_UNSPECIFIED && req.Phase != phase { - return nil + return false, nil } c, err := k.GetConsumerChain(ctx, consumerId) if err != nil { - return status.Error(codes.Internal, err.Error()) + return false, status.Error(codes.Internal, err.Error()) } - chains = append(chains, &c) - return nil + + if accumulate { + chains = append(chains, &c) + } + return true, nil }) if err != nil { diff --git a/x/ccv/provider/keeper/grpc_query_test.go b/x/ccv/provider/keeper/grpc_query_test.go index 5f664a331a..fc9eebe43f 100644 --- a/x/ccv/provider/keeper/grpc_query_test.go +++ b/x/ccv/provider/keeper/grpc_query_test.go @@ -699,18 +699,21 @@ func TestQueryConsumerChains(t *testing.T) { setup func(ctx sdk.Context, pk keeper.Keeper) phase_filter types.ConsumerPhase limit uint64 + total uint64 expConsumers []*types.Chain }{ { name: "expect all consumers when phase filter isn't set", setup: func(ctx sdk.Context, pk keeper.Keeper) {}, expConsumers: consumers, + total: 4, }, { name: "expect an amount of consumer equal to the limit", setup: func(ctx sdk.Context, pk keeper.Keeper) {}, expConsumers: consumers[:3], limit: 3, + total: 4, }, { name: "expect registered consumers when phase filter is set to Registered", @@ -720,6 +723,7 @@ func TestQueryConsumerChains(t *testing.T) { }, phase_filter: types.CONSUMER_PHASE_REGISTERED, expConsumers: consumers[0:1], + total: 1, }, { name: "expect initialized consumers when phase is set to Initialized", @@ -729,6 +733,7 @@ func TestQueryConsumerChains(t *testing.T) { }, phase_filter: types.CONSUMER_PHASE_INITIALIZED, expConsumers: consumers[1:2], + total: 1, }, { name: "expect launched consumers when phase is set to Launched", @@ -738,6 +743,7 @@ func TestQueryConsumerChains(t *testing.T) { }, phase_filter: types.CONSUMER_PHASE_LAUNCHED, expConsumers: consumers[2:3], + total: 1, }, { name: "expect stopped consumers when phase is set to Stopped", @@ -747,6 +753,7 @@ func TestQueryConsumerChains(t *testing.T) { }, phase_filter: types.CONSUMER_PHASE_STOPPED, expConsumers: consumers[3:], + total: 1, }, } @@ -756,7 +763,8 @@ func TestQueryConsumerChains(t *testing.T) { req := types.QueryConsumerChainsRequest{ Phase: tc.phase_filter, Pagination: &sdkquery.PageRequest{ - Limit: tc.limit, + Limit: tc.limit, + CountTotal: true, }, } expectedResponse := types.QueryConsumerChainsResponse{ @@ -768,6 +776,9 @@ func TestQueryConsumerChains(t *testing.T) { if tc.limit != 0 { require.Len(t, res.GetChains(), int(tc.limit), tc.name) } + if tc.total != 0 { + require.Equal(t, res.Pagination.Total, tc.total, tc.name) + } }) } } From 802ed49d17bcbcec89324840298510c2c5dfa6df Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:24:11 +0100 Subject: [PATCH 10/12] build(deps): bump actions/cache from 4.1.0 to 4.1.2 (#2376) Bumps [actions/cache](https://github.com/actions/cache) from 4.1.0 to 4.1.2. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v4.1.0...v4.1.2) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 69d2448c8e..16ce734996 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -39,7 +39,7 @@ jobs: **/go.sum **/Makefile Makefile - - uses: actions/cache@v4.1.0 + - uses: actions/cache@v4.1.2 with: path: | ~/.cache/go-build From 6532a8818d0c3e287f04ae0cf3405a19b32e4090 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:24:29 +0100 Subject: [PATCH 11/12] build(deps): bump bufbuild/buf-setup-action from 1.45.0 to 1.46.0 (#2384) Bumps [bufbuild/buf-setup-action](https://github.com/bufbuild/buf-setup-action) from 1.45.0 to 1.46.0. - [Release notes](https://github.com/bufbuild/buf-setup-action/releases) - [Commits](https://github.com/bufbuild/buf-setup-action/compare/v1.45.0...v1.46.0) --- updated-dependencies: - dependency-name: bufbuild/buf-setup-action dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- .github/workflows/proto-registry.yml | 2 +- .github/workflows/proto.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/proto-registry.yml b/.github/workflows/proto-registry.yml index 6850af4db0..d4714b611f 100644 --- a/.github/workflows/proto-registry.yml +++ b/.github/workflows/proto-registry.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: bufbuild/buf-setup-action@v1.45.0 + - uses: bufbuild/buf-setup-action@v1.46.0 - uses: bufbuild/buf-push-action@v1 with: input: "proto" diff --git a/.github/workflows/proto.yml b/.github/workflows/proto.yml index d7af43f29c..b1f3d2b2e7 100644 --- a/.github/workflows/proto.yml +++ b/.github/workflows/proto.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - uses: bufbuild/buf-setup-action@v1.45.0 + - uses: bufbuild/buf-setup-action@v1.46.0 - uses: bufbuild/buf-breaking-action@v1 with: input: "proto" From b3a2781457d20861578959ea39823465dbf01cc5 Mon Sep 17 00:00:00 2001 From: Simon Noetzlin Date: Tue, 5 Nov 2024 15:16:25 +0100 Subject: [PATCH 12/12] test: fix key assignment in testing (#2344) fix key assignment in testing --- tests/integration/setup.go | 41 ----------------------- testutil/ibc_testing/generic_setup.go | 47 +++++++++++++++++++++++++-- 2 files changed, 44 insertions(+), 44 deletions(-) diff --git a/tests/integration/setup.go b/tests/integration/setup.go index f1f4faebbd..ca9adec496 100644 --- a/tests/integration/setup.go +++ b/tests/integration/setup.go @@ -9,20 +9,15 @@ import ( channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" ibctmtypes "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v8/testing" - "github.com/cosmos/ibc-go/v8/testing/mock" "github.com/stretchr/testify/suite" store "cosmossdk.io/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/cometbft/cometbft/abci/types" - tmencoding "github.com/cometbft/cometbft/crypto/encoding" icstestingutils "github.com/cosmos/interchain-security/v6/testutil/ibc_testing" testutil "github.com/cosmos/interchain-security/v6/testutil/integration" consumertypes "github.com/cosmos/interchain-security/v6/x/ccv/consumer/types" - providertypes "github.com/cosmos/interchain-security/v6/x/ccv/provider/types" ccv "github.com/cosmos/interchain-security/v6/x/ccv/types" ) @@ -145,14 +140,6 @@ func (suite *CCVTestSuite) SetupTest() { params.BlocksPerEpoch = 10 providerKeeper.SetParams(suite.providerCtx(), params) - // re-assign all validator keys for the first consumer chain - // this has to be done before: - // 1. the consumer chain is added to the coordinator - // 2. MakeGenesis is called on the provider chain - // 3. ibc/testing sets the tendermint header for the consumer chain app - providerKeeper.SetConsumerPhase(suite.providerCtx(), icstestingutils.FirstConsumerID, providertypes.CONSUMER_PHASE_INITIALIZED) - preProposalKeyAssignment(suite, icstestingutils.FirstConsumerID) - // start consumer chains suite.consumerBundles = make(map[string]*icstestingutils.ConsumerBundle) for i := 0; i < icstestingutils.NumConsumers; i++ { @@ -416,34 +403,6 @@ func (s *CCVTestSuite) validateEndpointsClientConfig(consumerBundle icstestingut ) } -// preProposalKeyAssignment assigns keys to all provider validators for -// the consumer with consumerId before the chain is registered, i.e., -// before a client to the consumer is created -func preProposalKeyAssignment(s *CCVTestSuite, consumerId string) { - providerKeeper := s.providerApp.GetProviderKeeper() - - for _, val := range s.providerChain.Vals.Validators { - // get SDK validator - valAddr, err := sdk.ValAddressFromHex(val.Address.String()) - s.Require().NoError(err) - validator := s.getVal(s.providerCtx(), valAddr) - - // generate new PrivValidator - privVal := mock.NewPV() - tmPubKey, err := privVal.GetPubKey() - s.Require().NoError(err) - consumerKey, err := tmencoding.PubKeyToProto(tmPubKey) - s.Require().NoError(err) - - // add Signer to the provider chain as there is no consumer chain to add it; - // as a result, NewTestChainWithValSet in AddConsumer uses providerChain.Signers - s.providerChain.Signers[tmPubKey.Address().String()] = privVal - - err = providerKeeper.AssignConsumerKey(s.providerCtx(), consumerId, validator, consumerKey) - s.Require().NoError(err) - } -} - // packetSniffer implements the StreamingService interface. // Implements ListenEndBlock to record packets from events. type packetSniffer struct { diff --git a/testutil/ibc_testing/generic_setup.go b/testutil/ibc_testing/generic_setup.go index 680dc842b5..e208b5b29a 100644 --- a/testutil/ibc_testing/generic_setup.go +++ b/testutil/ibc_testing/generic_setup.go @@ -7,6 +7,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/ibc-go/v8/testing/mock" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -19,6 +20,7 @@ import ( testutil "github.com/cosmos/interchain-security/v6/testutil/integration" testkeeper "github.com/cosmos/interchain-security/v6/testutil/keeper" consumerkeeper "github.com/cosmos/interchain-security/v6/x/ccv/consumer/keeper" + providerkeeper "github.com/cosmos/interchain-security/v6/x/ccv/provider/keeper" providertypes "github.com/cosmos/interchain-security/v6/x/ccv/provider/types" ) @@ -155,9 +157,6 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp]( powerShapingParameters.Top_N = consumerTopNParams[index] // isn't used in CreateConsumerClient consumerId := providerKeeper.FetchAndIncrementConsumerId(providerChain.GetContext()) - if chainID == firstConsumerChainID { - FirstConsumerID = consumerId - } providerKeeper.SetConsumerChainId(providerChain.GetContext(), consumerId, chainID) err := providerKeeper.SetConsumerMetadata(providerChain.GetContext(), consumerId, consumerMetadata) s.Require().NoError(err) @@ -166,6 +165,15 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp]( err = providerKeeper.SetConsumerPowerShapingParameters(providerChain.GetContext(), consumerId, powerShapingParameters) s.Require().NoError(err) providerKeeper.SetConsumerPhase(providerChain.GetContext(), consumerId, providertypes.CONSUMER_PHASE_INITIALIZED) + if chainID == firstConsumerChainID { + FirstConsumerID = consumerId + // re-assign all validator keys for the first consumer chain + // this has to be done before: + // 1. the consumer chain is added to the coordinator + // 2. MakeGenesis is called on the provider chain + // 3. ibc/testing sets the tendermint header for the consumer chain app + preProposalKeyAssignment(s, *providerChain, providerKeeper, providerApp, FirstConsumerID) + } err = providerKeeper.AppendConsumerToBeLaunched(providerChain.GetContext(), consumerId, coordinator.CurrentTime) s.Require().NoError(err) @@ -228,3 +236,36 @@ func AddConsumer[Tp testutil.ProviderApp, Tc testutil.ConsumerApp]( TopN: powerShapingParameters.Top_N, } } + +// preProposalKeyAssignment assigns keys to all provider validators for +// the consumer with consumerId before the chain is registered, i.e., +// before a client to the consumer is created +func preProposalKeyAssignment( + s *suite.Suite, + providerChain ibctesting.TestChain, + providerKeeper providerkeeper.Keeper, + providerApp testutil.ProviderApp, + consumerId string, +) { + for _, val := range providerChain.Vals.Validators { + // get SDK validator + valAddr, err := sdk.ValAddressFromHex(val.Address.String()) + s.Require().NoError(err) + validator, err := providerApp.GetTestStakingKeeper().GetValidator(providerChain.GetContext(), valAddr) + s.Require().NoError(err) + + // generate new PrivValidator + privVal := mock.NewPV() + tmPubKey, err := privVal.GetPubKey() + s.Require().NoError(err) + consumerKey, err := tmencoding.PubKeyToProto(tmPubKey) + s.Require().NoError(err) + + // add Signer to the provider chain as there is no consumer chain to add it; + // as a result, NewTestChainWithValSet in AddConsumer uses providerChain.Signers + providerChain.Signers[tmPubKey.Address().String()] = privVal + + err = providerKeeper.AssignConsumerKey(providerChain.GetContext(), consumerId, validator, consumerKey) + s.Require().NoError(err) + } +}