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/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/.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/.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/.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/.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/.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" 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 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 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: [] ``` @@ -1683,7 +1691,7 @@ where `update-consumer-msg.json` contains: "initialization_parameters":{ "initial_height":{ "revision_number": 1, - "revision_height": 0 + "revision_height": 1 }, "genesis_hash": "", "binary_hash": "", @@ -1702,8 +1710,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/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..752b784113 --- /dev/null +++ b/docs/docs/consumer-development/create-with-spawn.md @@ -0,0 +1,146 @@ +--- +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. Install Spawn + +```shell +# Install from latest source +git clone https://github.com/rollchains/spawn.git --depth 1 --branch v0.50.10 + +# Change to this directory +cd spawn + +# 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= + +spawn new consumer \ +--consensus=interchain-security \ +--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. + +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 4350db2c14..5d6f42ef20 100644 --- a/docs/docs/consumer-development/onboarding.md +++ b/docs/docs/consumer-development/onboarding.md @@ -1,17 +1,18 @@ --- -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. +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 +21,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 +35,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. @@ -53,13 +53,14 @@ 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 { // 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. @@ -101,6 +102,7 @@ Example of initialization parameters: ``` Example of power-shaping parameters: + ```js // PowerShaping parameters provided in MsgCreateConsumer or MsgUpdateConsumer { @@ -120,13 +122,15 @@ 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. - "allow_inactive_vals": false + "allow_inactive_vals": false, + // Corresponds to a list of provider consensus addresses of validators that have priority + "prioritylist": [], } ``` @@ -138,13 +142,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/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 98f7ca0ca6..e659b3cda6 100644 --- a/proto/interchain_security/ccv/provider/v1/query.proto +++ b/proto/interchain_security/ccv/provider/v1/query.proto @@ -204,6 +204,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/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) + } +} 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 d1caeb1d6f..52a53f3ebe 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": "", @@ -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/..."] @@ -332,7 +333,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": "", @@ -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_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 { 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/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() diff --git a/x/ccv/provider/keeper/grpc_query.go b/x/ccv/provider/keeper/grpc_query.go index 775572b851..d98f7e9b3e 100644 --- a/x/ccv/provider/keeper/grpc_query.go +++ b/x/ccv/provider/keeper/grpc_query.go @@ -57,23 +57,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 { @@ -115,6 +118,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()) @@ -140,6 +149,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 73deaff360..73f1f94ffb 100644 --- a/x/ccv/provider/keeper/grpc_query_test.go +++ b/x/ccv/provider/keeper/grpc_query_test.go @@ -454,7 +454,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{ @@ -493,6 +498,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() @@ -503,6 +511,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]) @@ -527,6 +540,7 @@ func TestGetConsumerChain(t *testing.T) { MinStake: minStakes[i].Uint64(), ConsumerId: consumerIDs[i], AllowlistedRewardDenoms: allowlistedRewardDenoms[i], + Prioritylist: strPrioritylist, }) } @@ -677,6 +691,7 @@ func TestQueryConsumerChains(t *testing.T) { Metadata: metadata, ConsumerId: consumerId, AllowlistedRewardDenoms: &types.AllowlistedRewardDenoms{Denoms: []string{}}, + Prioritylist: []string{}, } consumerIds[i] = consumerId consumers[i] = &c @@ -687,18 +702,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", @@ -708,6 +726,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", @@ -717,6 +736,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", @@ -726,6 +746,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", @@ -735,6 +756,7 @@ func TestQueryConsumerChains(t *testing.T) { }, phase_filter: types.CONSUMER_PHASE_STOPPED, expConsumers: consumers[3:], + total: 1, }, } @@ -744,7 +766,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{ @@ -756,6 +779,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) + } }) } } 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 309c7c5079..1fd93e436c 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"` @@ -1947,165 +1959,166 @@ func init() { } var fileDescriptor_422512d7b7586cd7 = []byte{ - // 2517 bytes of a gzipped FileDescriptorProto + // 2532 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, 0xcd, 0x5a, 0x4a, 0x3c, 0x96, 0xad, 0xf5, 0xca, 0xd1, 0xca, 0x74, + 0x15, 0x17, 0x57, 0x1f, 0x5e, 0xcd, 0x5a, 0x72, 0x32, 0x96, 0xad, 0xf5, 0xca, 0xd1, 0xca, 0x74, 0xdc, 0x2a, 0x72, 0xbc, 0x2b, 0xa9, 0xc8, 0x97, 0x13, 0x7f, 0x68, 0x65, 0x49, 0x16, 0x1c, 0xdb, 0x0a, 0xa5, 0x38, 0x80, 0x53, 0x97, 0x1d, 0x91, 0x93, 0xd5, 0x54, 0x5c, 0x92, 0xe6, 0x8c, 0xd6, - 0xde, 0x1a, 0xbe, 0xf4, 0x94, 0x43, 0x0b, 0x24, 0x28, 0x7a, 0x6e, 0xce, 0x3d, 0x14, 0x45, 0x11, - 0xf4, 0x1f, 0xe8, 0x25, 0xb7, 0xa6, 0xe9, 0xa5, 0x48, 0x51, 0xb7, 0xb0, 0x5b, 0xa0, 0x97, 0xa2, - 0x68, 0x5a, 0xf4, 0x5c, 0xcc, 0x70, 0xc8, 0x5d, 0xd2, 0x5c, 0x2d, 0xa9, 0xd5, 0x6d, 0x39, 0xf3, - 0xde, 0xef, 0x7d, 0xcc, 0x9b, 0x37, 0xef, 0x3d, 0x09, 0x54, 0x89, 0xcd, 0xb0, 0x67, 0xec, 0x20, - 0x62, 0xeb, 0x14, 0x1b, 0x7b, 0x1e, 0x61, 0xad, 0xaa, 0x61, 0x34, 0xab, 0xae, 0xe7, 0x34, 0x89, - 0x89, 0xbd, 0x6a, 0x73, 0xa1, 0x7a, 0x7f, 0x0f, 0x7b, 0xad, 0x8a, 0xeb, 0x39, 0xcc, 0x81, 0x67, - 0x13, 0x18, 0x2a, 0x86, 0xd1, 0xac, 0x04, 0x0c, 0x95, 0xe6, 0x42, 0xe9, 0x74, 0xdd, 0x71, 0xea, - 0x16, 0xae, 0x22, 0x97, 0x54, 0x91, 0x6d, 0x3b, 0x0c, 0x31, 0xe2, 0xd8, 0xd4, 0x87, 0x28, 0x4d, - 0xd4, 0x9d, 0xba, 0x23, 0x7e, 0x56, 0xf9, 0x2f, 0xb9, 0x5a, 0x96, 0x3c, 0xe2, 0x6b, 0x7b, 0xef, - 0xa3, 0x2a, 0x23, 0x0d, 0x4c, 0x19, 0x6a, 0xb8, 0x92, 0x60, 0x31, 0x8d, 0xaa, 0xa1, 0x16, 0x3e, - 0xcf, 0x7c, 0x37, 0x9e, 0xe6, 0x42, 0x95, 0xee, 0x20, 0x0f, 0x9b, 0xba, 0xe1, 0xd8, 0x74, 0xaf, - 0x11, 0x72, 0x9c, 0xdb, 0x87, 0xe3, 0x01, 0xf1, 0xb0, 0x24, 0x3b, 0xcd, 0xb0, 0x6d, 0x62, 0xaf, - 0x41, 0x6c, 0x56, 0x35, 0xbc, 0x96, 0xcb, 0x9c, 0xea, 0x2e, 0x6e, 0x05, 0x16, 0x9e, 0x32, 0x1c, - 0xda, 0x70, 0xa8, 0xee, 0x1b, 0xe9, 0x7f, 0xc8, 0xad, 0x97, 0xfd, 0xaf, 0x2a, 0x65, 0x68, 0x97, - 0xd8, 0xf5, 0x6a, 0x73, 0x61, 0x1b, 0x33, 0xb4, 0x10, 0x7c, 0x4b, 0xaa, 0x39, 0x49, 0xb5, 0x8d, - 0x28, 0xf6, 0xdd, 0x1f, 0x12, 0xba, 0xa8, 0x4e, 0x6c, 0xe1, 0x4f, 0x9f, 0x56, 0xbd, 0x0c, 0xa6, - 0xde, 0xe3, 0x14, 0xcb, 0xd2, 0x90, 0x35, 0x6c, 0x63, 0x4a, 0xa8, 0x86, 0xef, 0xef, 0x61, 0xca, - 0x60, 0x19, 0x14, 0x02, 0x13, 0x75, 0x62, 0x16, 0x95, 0x19, 0x65, 0x76, 0x54, 0x03, 0xc1, 0xd2, - 0xba, 0xa9, 0x3e, 0x02, 0xa7, 0x93, 0xf9, 0xa9, 0xeb, 0xd8, 0x14, 0xc3, 0x0f, 0xc1, 0x58, 0xdd, - 0x5f, 0xd2, 0x29, 0x43, 0x0c, 0x0b, 0x88, 0xc2, 0xe2, 0x7c, 0xa5, 0x5b, 0x24, 0x34, 0x17, 0x2a, - 0x31, 0xac, 0x4d, 0xce, 0x57, 0x1b, 0xfa, 0xe2, 0x49, 0x79, 0x40, 0x3b, 0x5a, 0xef, 0x58, 0x53, - 0x7f, 0xa9, 0x80, 0x52, 0x44, 0xfa, 0x32, 0xc7, 0x0b, 0x95, 0xbf, 0x0e, 0x86, 0xdd, 0x1d, 0x44, - 0x7d, 0x99, 0xe3, 0x8b, 0x8b, 0x95, 0x14, 0xd1, 0x17, 0x0a, 0xdf, 0xe0, 0x9c, 0x9a, 0x0f, 0x00, - 0x57, 0x01, 0x68, 0x7b, 0xae, 0x98, 0x13, 0x26, 0x7c, 0xab, 0x22, 0x8f, 0x86, 0xbb, 0xb9, 0xe2, - 0x47, 0xb9, 0x74, 0x73, 0x65, 0x03, 0xd5, 0xb1, 0xd4, 0x42, 0xeb, 0xe0, 0x54, 0x7f, 0xa1, 0xc4, - 0xdc, 0x1d, 0x28, 0x2c, 0xbd, 0x55, 0x03, 0x23, 0x42, 0x3d, 0x5a, 0x54, 0x66, 0x06, 0x67, 0x0b, - 0x8b, 0x73, 0xe9, 0x54, 0xe6, 0xdb, 0x9a, 0xe4, 0x84, 0x6b, 0x09, 0xba, 0x7e, 0xbb, 0xa7, 0xae, - 0xbe, 0x02, 0x11, 0x65, 0xff, 0x35, 0x04, 0x86, 0x05, 0x34, 0x3c, 0x05, 0xf2, 0xbe, 0x0a, 0x61, - 0x08, 0x1c, 0x11, 0xdf, 0xeb, 0x26, 0x9c, 0x02, 0xa3, 0x86, 0x45, 0xb0, 0xcd, 0xf8, 0x5e, 0x4e, - 0xec, 0xe5, 0xfd, 0x85, 0x75, 0x13, 0x1e, 0x07, 0xc3, 0xcc, 0x71, 0xf5, 0x5b, 0xc5, 0xc1, 0x19, - 0x65, 0x76, 0x4c, 0x1b, 0x62, 0x8e, 0x7b, 0x0b, 0xce, 0x01, 0xd8, 0x20, 0xb6, 0xee, 0x3a, 0x0f, - 0x78, 0x4c, 0xd9, 0xba, 0x4f, 0x31, 0x34, 0xa3, 0xcc, 0x0e, 0x6a, 0xe3, 0x0d, 0x62, 0x6f, 0xf0, - 0x8d, 0x75, 0x7b, 0x8b, 0xd3, 0xce, 0x83, 0x89, 0x26, 0xb2, 0x88, 0x89, 0x98, 0xe3, 0x51, 0xc9, - 0x62, 0x20, 0xb7, 0x38, 0x2c, 0xf0, 0x60, 0x7b, 0x4f, 0x30, 0x2d, 0x23, 0x17, 0xce, 0x81, 0x63, - 0xe1, 0xaa, 0x4e, 0x31, 0x13, 0xe4, 0x23, 0x82, 0xfc, 0x85, 0x70, 0x63, 0x13, 0x33, 0x4e, 0x7b, - 0x1a, 0x8c, 0x22, 0xcb, 0x72, 0x1e, 0x58, 0x84, 0xb2, 0xe2, 0x91, 0x99, 0xc1, 0xd9, 0x51, 0xad, - 0xbd, 0x00, 0x4b, 0x20, 0x6f, 0x62, 0xbb, 0x25, 0x36, 0xf3, 0x62, 0x33, 0xfc, 0x86, 0x13, 0x41, - 0x64, 0x8d, 0x0a, 0x8b, 0x65, 0x94, 0x7c, 0x00, 0xf2, 0x0d, 0xcc, 0x90, 0x89, 0x18, 0x2a, 0x02, - 0xe1, 0xf7, 0xd7, 0x32, 0x85, 0xdc, 0x4d, 0xc9, 0x2c, 0x63, 0x3d, 0x04, 0xe3, 0x4e, 0xe6, 0x2e, - 0xe3, 0xb7, 0x1c, 0x17, 0x0b, 0x33, 0xca, 0xec, 0x90, 0x96, 0x6f, 0x10, 0x7b, 0x93, 0x7f, 0xc3, - 0x0a, 0x38, 0x2e, 0x94, 0xd6, 0x89, 0x8d, 0x0c, 0x46, 0x9a, 0x58, 0x6f, 0x22, 0x8b, 0x16, 0x8f, - 0xce, 0x28, 0xb3, 0x79, 0xed, 0x98, 0xd8, 0x5a, 0x97, 0x3b, 0x77, 0x90, 0x45, 0xe3, 0x57, 0x7a, - 0x2c, 0x7e, 0xa5, 0xe1, 0x43, 0x70, 0x2a, 0xf4, 0x02, 0x36, 0x75, 0x0f, 0x3f, 0x40, 0x9e, 0xa9, - 0x9b, 0xd8, 0x76, 0x1a, 0xb4, 0x38, 0x2e, 0xec, 0x7a, 0x27, 0x95, 0x5d, 0x4b, 0x6d, 0x14, 0x4d, - 0x80, 0x5c, 0x13, 0x18, 0xda, 0x24, 0x4a, 0xde, 0x50, 0x7f, 0xa2, 0x80, 0x33, 0xe2, 0x7a, 0xdc, - 0x09, 0x4e, 0x2a, 0x70, 0xcd, 0x92, 0x69, 0x7a, 0xc1, 0xb5, 0xbe, 0x04, 0x5e, 0x0c, 0xa4, 0xe8, - 0xc8, 0x34, 0x3d, 0x4c, 0xa9, 0x1f, 0x95, 0x35, 0xf8, 0xcd, 0x93, 0xf2, 0x78, 0x0b, 0x35, 0xac, - 0x8b, 0xaa, 0xdc, 0x50, 0xb5, 0x17, 0x02, 0xda, 0x25, 0x7f, 0x25, 0x6e, 0x7f, 0x2e, 0x6e, 0xff, - 0xc5, 0xfc, 0xc7, 0x9f, 0x95, 0x07, 0xfe, 0xf1, 0x59, 0x79, 0x40, 0xbd, 0x0d, 0xd4, 0xfd, 0xd4, - 0x91, 0x97, 0xf6, 0x15, 0xf0, 0x62, 0x08, 0x18, 0xd1, 0x47, 0x7b, 0xc1, 0xe8, 0xa0, 0xe7, 0xda, - 0x3c, 0x6f, 0xe0, 0x46, 0x87, 0x76, 0x1d, 0x06, 0x26, 0x03, 0x26, 0x1b, 0x18, 0x13, 0xd2, 0x97, - 0x81, 0x51, 0x75, 0xda, 0x06, 0x26, 0x3b, 0xfc, 0x39, 0xe7, 0xaa, 0x53, 0xe0, 0x94, 0x00, 0xdc, - 0xda, 0xf1, 0x1c, 0xc6, 0x2c, 0x2c, 0xf2, 0xb4, 0xb4, 0x4b, 0xfd, 0x7d, 0x90, 0xae, 0x63, 0xbb, - 0x52, 0x4c, 0x19, 0x14, 0xa8, 0x85, 0xe8, 0x8e, 0xde, 0xc0, 0x0c, 0x7b, 0x42, 0xc2, 0xa0, 0x06, - 0xc4, 0xd2, 0x4d, 0xbe, 0x02, 0x17, 0xc1, 0x89, 0x0e, 0x02, 0x5d, 0x44, 0x11, 0xb2, 0x0d, 0x2c, - 0x4c, 0x1c, 0xd4, 0x8e, 0xb7, 0x49, 0x97, 0x82, 0x2d, 0xf8, 0x3d, 0x50, 0xb4, 0xf1, 0x43, 0xa6, - 0x7b, 0xd8, 0xb5, 0xb0, 0x4d, 0xe8, 0x8e, 0x6e, 0x20, 0xdb, 0xe4, 0xc6, 0x62, 0x91, 0x95, 0x0a, - 0x8b, 0xa5, 0x8a, 0x5f, 0x3b, 0x54, 0x82, 0xda, 0xa1, 0xb2, 0x15, 0xd4, 0x0e, 0xb5, 0x3c, 0xbf, - 0x88, 0x9f, 0xfc, 0xa5, 0xac, 0x68, 0x27, 0x39, 0x8a, 0x16, 0x80, 0x2c, 0x07, 0x18, 0xea, 0xab, - 0x60, 0x4e, 0x98, 0xa4, 0xe1, 0x3a, 0x8f, 0x67, 0x0f, 0x9b, 0x41, 0x8c, 0x44, 0x42, 0x5e, 0x7a, - 0x60, 0x05, 0x9c, 0x4f, 0x45, 0x2d, 0x3d, 0x72, 0x12, 0x8c, 0xc8, 0x6b, 0xa7, 0x88, 0x04, 0x24, - 0xbf, 0xd4, 0x77, 0xc1, 0x2b, 0x02, 0x66, 0xc9, 0xb2, 0x36, 0x10, 0xf1, 0xe8, 0x1d, 0x64, 0x71, - 0x1c, 0x7e, 0x08, 0xb5, 0x56, 0x1b, 0x31, 0xe5, 0x13, 0xfe, 0x73, 0x45, 0xda, 0xd0, 0x03, 0x4e, - 0x2a, 0x75, 0x1f, 0x1c, 0x73, 0x11, 0xf1, 0x78, 0x96, 0xe1, 0xe5, 0x8f, 0x88, 0x08, 0xf9, 0x5c, - 0xad, 0xa6, 0x4a, 0x0b, 0x5c, 0x86, 0x2f, 0x82, 0x4b, 0x08, 0x23, 0xce, 0x6e, 0xfb, 0x62, 0xdc, - 0x8d, 0x90, 0xa8, 0xff, 0x55, 0xc0, 0x99, 0x9e, 0x5c, 0x70, 0xb5, 0x6b, 0x5e, 0x98, 0xfa, 0xe6, - 0x49, 0x79, 0xd2, 0xbf, 0x36, 0x71, 0x8a, 0x84, 0x04, 0xb1, 0x9a, 0x70, 0xfd, 0x72, 0x71, 0x9c, - 0x38, 0x45, 0xc2, 0x3d, 0xbc, 0x02, 0x8e, 0x86, 0x54, 0xbb, 0xb8, 0x25, 0xc3, 0xed, 0x74, 0xa5, - 0x5d, 0xfc, 0x55, 0xfc, 0xe2, 0xaf, 0xb2, 0xb1, 0xb7, 0x6d, 0x11, 0xe3, 0x06, 0x6e, 0x69, 0xe1, - 0x51, 0xdd, 0xc0, 0x2d, 0x75, 0x02, 0x40, 0x71, 0x2e, 0x1b, 0xc8, 0x43, 0xed, 0x18, 0xfa, 0x3e, - 0x38, 0x1e, 0x59, 0x95, 0xc7, 0xb2, 0x0e, 0x46, 0x5c, 0xb1, 0x22, 0x2b, 0xac, 0xf3, 0x29, 0xcf, - 0x82, 0xb3, 0xc8, 0x07, 0x47, 0x02, 0xa8, 0x37, 0x65, 0x3c, 0x44, 0x8a, 0x94, 0xdb, 0x2e, 0xc3, - 0xe6, 0xba, 0x1d, 0x66, 0x8a, 0xf4, 0x25, 0xe2, 0x7d, 0x19, 0xf4, 0xbd, 0xe0, 0xc2, 0x1a, 0xe8, - 0xa5, 0xce, 0x37, 0x3f, 0x76, 0x5e, 0x38, 0xb8, 0x0b, 0x53, 0x1d, 0x8f, 0x7f, 0xf4, 0x00, 0x31, - 0x55, 0x97, 0xc0, 0x74, 0x44, 0xe4, 0x01, 0xb4, 0xfe, 0xf4, 0x08, 0x98, 0xe9, 0x82, 0x11, 0xfe, - 0xea, 0xf7, 0x29, 0x8a, 0x47, 0x48, 0x2e, 0x63, 0x84, 0xc0, 0x22, 0x18, 0x16, 0x45, 0x91, 0x88, - 0xad, 0xc1, 0x5a, 0xae, 0xa8, 0x68, 0xfe, 0x02, 0x7c, 0x0b, 0x0c, 0x79, 0x3c, 0xc7, 0x0d, 0x09, - 0x6d, 0xce, 0xf1, 0xf3, 0xfd, 0xfa, 0x49, 0x79, 0xca, 0x2f, 0x03, 0xa9, 0xb9, 0x5b, 0x21, 0x4e, - 0xb5, 0x81, 0xd8, 0x4e, 0xe5, 0x5d, 0x5c, 0x47, 0x46, 0xeb, 0x1a, 0x36, 0x8a, 0x8a, 0x26, 0x58, - 0xe0, 0x39, 0x30, 0x1e, 0x6a, 0xe5, 0xa3, 0x0f, 0x8b, 0xfc, 0x3a, 0x16, 0xac, 0x8a, 0x62, 0x0b, - 0xde, 0x03, 0xc5, 0x90, 0xcc, 0x70, 0x1a, 0x0d, 0x42, 0x29, 0x71, 0x6c, 0x5d, 0x48, 0x1d, 0x11, - 0x52, 0xcf, 0xa6, 0x90, 0xaa, 0x9d, 0x0c, 0x40, 0x96, 0x43, 0x0c, 0x8d, 0x6b, 0x71, 0x0f, 0x14, - 0x43, 0xd7, 0xc6, 0xe1, 0x8f, 0x64, 0x80, 0x0f, 0x40, 0x62, 0xf0, 0x37, 0x40, 0xc1, 0xc4, 0xd4, - 0xf0, 0x88, 0x2b, 0xca, 0xe4, 0xbc, 0xf0, 0xfc, 0xd9, 0xa0, 0x4c, 0x0e, 0xfa, 0xa9, 0xa0, 0x46, - 0xbe, 0xd6, 0x26, 0x95, 0x77, 0xa5, 0x93, 0x1b, 0xde, 0x03, 0xa7, 0x42, 0x5d, 0x1d, 0x17, 0x7b, - 0xa2, 0xf8, 0x0c, 0xe2, 0x41, 0x94, 0x88, 0xb5, 0x33, 0x5f, 0x7d, 0x7e, 0xe1, 0x25, 0x89, 0x1e, - 0xc6, 0x8f, 0x8c, 0x83, 0x4d, 0xe6, 0x11, 0xbb, 0xae, 0x4d, 0x06, 0x18, 0xb7, 0x25, 0x44, 0x10, - 0x26, 0x27, 0xc1, 0xc8, 0x0f, 0x10, 0xb1, 0xb0, 0x29, 0xaa, 0xca, 0xbc, 0x26, 0xbf, 0xe0, 0x45, - 0x30, 0xc2, 0x7b, 0xaa, 0x3d, 0x2a, 0x6a, 0xc2, 0xf1, 0x45, 0xb5, 0x9b, 0xfa, 0x35, 0xc7, 0x36, - 0x37, 0x05, 0xa5, 0x26, 0x39, 0xe0, 0x16, 0x08, 0xa3, 0x51, 0x67, 0xce, 0x2e, 0xb6, 0xfd, 0x8a, - 0x71, 0xb4, 0x76, 0x5e, 0x7a, 0xf5, 0xc4, 0xf3, 0x5e, 0x5d, 0xb7, 0xd9, 0x57, 0x9f, 0x5f, 0x00, - 0x52, 0xc8, 0xba, 0xcd, 0xb4, 0xf1, 0x00, 0x63, 0x4b, 0x40, 0xf0, 0xd0, 0x09, 0x51, 0xfd, 0xd0, - 0x19, 0xf3, 0x43, 0x27, 0x58, 0xf5, 0x43, 0xe7, 0x75, 0x30, 0x29, 0x6f, 0x2f, 0xa6, 0xba, 0xb1, - 0xe7, 0x79, 0xbc, 0x7f, 0xc0, 0xae, 0x63, 0xec, 0x88, 0xfa, 0x32, 0xaf, 0x9d, 0x08, 0xb7, 0x97, - 0xfd, 0xdd, 0x15, 0xbe, 0xa9, 0x7e, 0xac, 0x80, 0x72, 0xd7, 0x7b, 0x2d, 0xd3, 0x07, 0x06, 0xa0, - 0x9d, 0x19, 0xe4, 0xbb, 0xb4, 0x92, 0x2a, 0x17, 0xf6, 0xba, 0xed, 0x5a, 0x07, 0xb0, 0x7a, 0x1f, - 0xcc, 0x27, 0x34, 0x72, 0x21, 0xed, 0x75, 0x44, 0xb7, 0x1c, 0xf9, 0x85, 0x0f, 0xa7, 0x70, 0x55, - 0xef, 0x80, 0x85, 0x0c, 0x22, 0xa5, 0x3b, 0xce, 0x74, 0xa4, 0x18, 0x62, 0x06, 0xc9, 0xb3, 0xd0, - 0x4e, 0x74, 0xa2, 0x28, 0x3d, 0x9f, 0x5c, 0xe6, 0x46, 0xef, 0x4c, 0xda, 0xd4, 0x99, 0x68, 0x67, - 0x2e, 0xbd, 0x9d, 0x75, 0xf0, 0x6a, 0x3a, 0x75, 0xa4, 0x89, 0x6f, 0xc8, 0x54, 0xa7, 0xa4, 0xcf, - 0x0a, 0x82, 0x41, 0x55, 0x65, 0x86, 0xaf, 0x59, 0x8e, 0xb1, 0x4b, 0xdf, 0xb7, 0x19, 0xb1, 0x6e, - 0xe1, 0x87, 0x7e, 0xac, 0x05, 0xaf, 0xed, 0x5d, 0x59, 0xb0, 0x27, 0xd3, 0x48, 0x0d, 0x5e, 0x03, - 0x93, 0xdb, 0x62, 0x5f, 0xdf, 0xe3, 0x04, 0xba, 0xa8, 0x38, 0xfd, 0x78, 0x56, 0x44, 0xb7, 0x36, - 0xb1, 0x9d, 0xc0, 0xae, 0x2e, 0xc9, 0xea, 0x7b, 0x39, 0x74, 0xdd, 0xaa, 0xe7, 0x34, 0x96, 0x65, - 0xf7, 0x1c, 0xb8, 0x3b, 0xd2, 0x61, 0x2b, 0xd1, 0x0e, 0x5b, 0x5d, 0x05, 0x67, 0xf7, 0x85, 0x68, - 0x97, 0xd6, 0xfb, 0xbf, 0x76, 0xef, 0xc8, 0xba, 0x3d, 0x12, 0x5b, 0xa9, 0xdf, 0xca, 0xdf, 0x0e, - 0x26, 0xcd, 0x61, 0x52, 0x4b, 0x8f, 0xcc, 0x17, 0x72, 0xd1, 0xf9, 0xc2, 0x59, 0x30, 0xe6, 0x3c, - 0xb0, 0x3b, 0x02, 0x69, 0x50, 0xec, 0x1f, 0x15, 0x8b, 0x41, 0x82, 0x0c, 0xdb, 0xf1, 0xa1, 0x6e, - 0xed, 0xf8, 0xf0, 0x61, 0xb6, 0xe3, 0x1f, 0x81, 0x02, 0xb1, 0x09, 0xd3, 0x65, 0xbd, 0x35, 0x22, - 0xb0, 0x57, 0x32, 0x61, 0xaf, 0xdb, 0x84, 0x11, 0x64, 0x91, 0x1f, 0x8a, 0x51, 0x8b, 0xa8, 0xc2, - 0x78, 0xdf, 0x42, 0x35, 0xc0, 0x91, 0xfd, 0xaa, 0x0c, 0x36, 0xc0, 0x84, 0x3f, 0xf2, 0xa0, 0x3b, - 0xc8, 0x25, 0x76, 0x3d, 0x10, 0x78, 0x44, 0x08, 0x7c, 0x3b, 0x5d, 0x81, 0xc7, 0x01, 0x36, 0x7d, - 0xfe, 0x0e, 0x31, 0xd0, 0x8d, 0xaf, 0x53, 0xb5, 0x16, 0x4b, 0xae, 0x72, 0xfc, 0xc6, 0xbb, 0xa1, - 0xd4, 0x91, 0xb0, 0x1b, 0x2b, 0x9a, 0x22, 0x18, 0x32, 0x1c, 0xd6, 0x40, 0x30, 0xc5, 0xd3, 0x19, - 0x69, 0x04, 0x13, 0xc1, 0x74, 0x6d, 0x58, 0xa1, 0xde, 0x06, 0x5c, 0xfc, 0xba, 0x0c, 0x86, 0x85, - 0x34, 0xf8, 0x77, 0x05, 0x4c, 0x24, 0xc9, 0x85, 0x57, 0xb3, 0x67, 0xfe, 0xe8, 0x04, 0xb4, 0xb4, - 0xd4, 0x07, 0x82, 0x6f, 0xb0, 0x7a, 0xfd, 0x47, 0x7f, 0xf8, 0xdb, 0x4f, 0x73, 0x35, 0x78, 0xb5, - 0xf7, 0xbc, 0x3c, 0xf4, 0xae, 0xb4, 0xb3, 0xfa, 0xa8, 0xc3, 0xdf, 0x8f, 0xe1, 0x9f, 0x14, 0x59, - 0xfc, 0x47, 0xdf, 0x00, 0x78, 0x25, 0xbb, 0x92, 0x91, 0x51, 0x69, 0xe9, 0xea, 0xc1, 0x01, 0xa4, - 0x91, 0x4b, 0xc2, 0xc8, 0xb7, 0xe1, 0x5b, 0x19, 0x8c, 0xf4, 0x27, 0x96, 0xd5, 0x47, 0xe2, 0xbe, - 0x3e, 0x86, 0x9f, 0xe6, 0x64, 0x1a, 0x49, 0x9c, 0xb7, 0xc0, 0xd5, 0xf4, 0x3a, 0xee, 0x37, 0x3f, - 0x2a, 0xad, 0xf5, 0x8d, 0x23, 0x4d, 0xde, 0x16, 0x26, 0x7f, 0x17, 0xde, 0x4d, 0xf1, 0x77, 0x90, - 0x70, 0x26, 0x19, 0x69, 0x1c, 0xa3, 0xc7, 0x5b, 0x7d, 0x14, 0x7f, 0x36, 0x93, 0x7c, 0xd2, 0xd9, - 0xed, 0x1c, 0xc8, 0x27, 0x09, 0x23, 0xa7, 0x03, 0xf9, 0x24, 0x69, 0x56, 0x74, 0x30, 0x9f, 0x44, - 0xcc, 0x8e, 0xfb, 0x24, 0xde, 0x69, 0x3f, 0x86, 0xbf, 0x53, 0x64, 0x63, 0x1c, 0x99, 0x23, 0xc1, - 0xcb, 0xe9, 0x6d, 0x48, 0x1a, 0x4f, 0x95, 0xae, 0x1c, 0x98, 0x5f, 0xda, 0xfe, 0xa6, 0xb0, 0x7d, - 0x11, 0xce, 0xf7, 0xb6, 0x9d, 0x49, 0x00, 0xff, 0x8f, 0x22, 0xf0, 0x67, 0x39, 0xf9, 0x8e, 0xef, - 0x3f, 0x18, 0x82, 0xb7, 0xd3, 0xab, 0x98, 0x6a, 0x20, 0x55, 0xda, 0x38, 0x3c, 0x40, 0xe9, 0x84, - 0x1b, 0xc2, 0x09, 0x2b, 0x70, 0xb9, 0xb7, 0x13, 0xbc, 0x10, 0xb1, 0x7d, 0x2b, 0x22, 0xd3, 0x66, - 0xf8, 0xe3, 0x9c, 0x2c, 0x91, 0xf6, 0x1d, 0x4d, 0xc1, 0x5b, 0xe9, 0xad, 0x48, 0x33, 0x32, 0x2b, - 0xdd, 0x3e, 0x34, 0x3c, 0xe9, 0x94, 0x15, 0xe1, 0x94, 0x2b, 0xf0, 0x52, 0x6f, 0xa7, 0xc8, 0x28, - 0xd7, 0x5d, 0x8e, 0x1a, 0x4b, 0xff, 0xbf, 0x56, 0x40, 0xa1, 0x63, 0xf6, 0x03, 0xdf, 0x48, 0xaf, - 0x67, 0x64, 0x86, 0x54, 0x7a, 0x33, 0x3b, 0xa3, 0xb4, 0x64, 0x5e, 0x58, 0x32, 0x07, 0x67, 0x7b, - 0x5b, 0xe2, 0x57, 0x2b, 0xed, 0xd8, 0xde, 0x7f, 0xfe, 0x93, 0x25, 0xb6, 0x53, 0x0d, 0xa6, 0xb2, - 0xc4, 0x76, 0xba, 0xd1, 0x54, 0x96, 0xd8, 0x76, 0x38, 0x88, 0x4e, 0x6c, 0xbd, 0xdd, 0x33, 0xc6, - 0x0e, 0xf3, 0x37, 0x39, 0x39, 0xc5, 0x4d, 0xd3, 0xcf, 0xc1, 0xf7, 0x0f, 0xfa, 0x40, 0xef, 0xdb, - 0x92, 0x96, 0xee, 0x1c, 0x36, 0xac, 0xf4, 0xd4, 0x5d, 0xe1, 0xa9, 0x2d, 0xa8, 0x65, 0xae, 0x06, - 0x74, 0x17, 0x7b, 0x6d, 0xa7, 0x25, 0x3d, 0x89, 0xbf, 0xca, 0x81, 0x97, 0xd3, 0x34, 0x88, 0x70, - 0xa3, 0x8f, 0x87, 0x3e, 0xb1, 0xf5, 0x2d, 0xbd, 0x77, 0x88, 0x88, 0xd2, 0x53, 0x86, 0xf0, 0xd4, - 0x3d, 0xf8, 0x61, 0x16, 0x4f, 0x45, 0xe7, 0x61, 0xbd, 0xab, 0x88, 0x7f, 0x2b, 0x60, 0xb2, 0xcb, - 0x78, 0x03, 0x2e, 0xf7, 0x33, 0x1c, 0x09, 0x1c, 0x73, 0xad, 0x3f, 0x90, 0xec, 0xf7, 0x2b, 0xb4, - 0xb8, 0xeb, 0xfd, 0xfa, 0xa7, 0x22, 0x7b, 0xda, 0xa4, 0xd6, 0x1d, 0x66, 0x18, 0x09, 0xed, 0x33, - 0x1e, 0x28, 0xad, 0xf6, 0x0b, 0x93, 0xbd, 0x7a, 0xee, 0x32, 0x69, 0x80, 0xff, 0x89, 0xff, 0x6f, - 0x41, 0x74, 0x16, 0x00, 0xd7, 0xb2, 0x1f, 0x51, 0xe2, 0x40, 0xa2, 0x74, 0xbd, 0x7f, 0xa0, 0x3e, - 0x7a, 0x06, 0x62, 0x56, 0x1f, 0x85, 0xf3, 0x90, 0xc7, 0xf0, 0xcf, 0x41, 0x2d, 0x18, 0x49, 0x4f, - 0x59, 0x6a, 0xc1, 0xa4, 0x91, 0x47, 0xe9, 0xca, 0x81, 0xf9, 0xa5, 0x69, 0xab, 0xc2, 0xb4, 0xab, - 0xf0, 0x72, 0xd6, 0x04, 0x18, 0x8b, 0xe2, 0xff, 0x29, 0xa0, 0xd8, 0xad, 0xa3, 0x86, 0xd7, 0x0e, - 0xdc, 0x9b, 0x76, 0x34, 0xf5, 0xa5, 0x95, 0x3e, 0x51, 0xa4, 0xc5, 0x37, 0x85, 0xc5, 0x6b, 0x70, - 0x25, 0x7b, 0x97, 0x2b, 0xe6, 0x00, 0x51, 0xc3, 0x6b, 0x1f, 0x7c, 0xf1, 0x74, 0x5a, 0xf9, 0xf2, - 0xe9, 0xb4, 0xf2, 0xd7, 0xa7, 0xd3, 0xca, 0x27, 0xcf, 0xa6, 0x07, 0xbe, 0x7c, 0x36, 0x3d, 0xf0, - 0xc7, 0x67, 0xd3, 0x03, 0x77, 0x2f, 0xd5, 0x09, 0xdb, 0xd9, 0xdb, 0xae, 0x18, 0x4e, 0x43, 0xfe, - 0x77, 0x54, 0x87, 0xc4, 0x0b, 0xa1, 0xc4, 0xe6, 0xeb, 0xd5, 0x87, 0xb1, 0xa2, 0xbb, 0xe5, 0x62, - 0xba, 0x3d, 0x22, 0x06, 0x0c, 0xdf, 0xf9, 0x7f, 0x00, 0x00, 0x00, 0xff, 0xff, 0xe8, 0x53, 0x11, - 0xe9, 0xbd, 0x26, 0x00, 0x00, + 0xde, 0x1a, 0xbe, 0xf4, 0x94, 0x43, 0x0b, 0x24, 0x08, 0x7a, 0x6e, 0xce, 0x3d, 0x14, 0x45, 0x11, + 0xf4, 0x1f, 0xe8, 0x25, 0xb7, 0xa6, 0xe9, 0xa5, 0x48, 0x51, 0xb7, 0xb0, 0x5b, 0xa0, 0x97, 0x1e, + 0x9a, 0x16, 0x3d, 0x17, 0x33, 0x1c, 0x72, 0x97, 0x34, 0x57, 0x4b, 0x6a, 0x75, 0x5b, 0xce, 0xbc, + 0xf7, 0x9b, 0xf7, 0xde, 0xbc, 0xf7, 0xe6, 0xbd, 0x27, 0x81, 0x2a, 0xb1, 0x19, 0xf6, 0x8c, 0x1d, + 0x44, 0x6c, 0x9d, 0x62, 0x63, 0xcf, 0x23, 0xac, 0x55, 0x35, 0x8c, 0x66, 0xd5, 0xf5, 0x9c, 0x26, + 0x31, 0xb1, 0x57, 0x6d, 0x2e, 0x54, 0xef, 0xef, 0x61, 0xaf, 0x55, 0x71, 0x3d, 0x87, 0x39, 0xf0, + 0x6c, 0x02, 0x43, 0xc5, 0x30, 0x9a, 0x95, 0x80, 0xa1, 0xd2, 0x5c, 0x28, 0x9d, 0xae, 0x3b, 0x4e, + 0xdd, 0xc2, 0x55, 0xe4, 0x92, 0x2a, 0xb2, 0x6d, 0x87, 0x21, 0x46, 0x1c, 0x9b, 0xfa, 0x10, 0xa5, + 0x89, 0xba, 0x53, 0x77, 0xc4, 0xcf, 0x2a, 0xff, 0x25, 0x57, 0xcb, 0x92, 0x47, 0x7c, 0x6d, 0xef, + 0x7d, 0x54, 0x65, 0xa4, 0x81, 0x29, 0x43, 0x0d, 0x57, 0x12, 0x2c, 0xa6, 0x11, 0x35, 0x94, 0xc2, + 0xe7, 0x99, 0xef, 0xc6, 0xd3, 0x5c, 0xa8, 0xd2, 0x1d, 0xe4, 0x61, 0x53, 0x37, 0x1c, 0x9b, 0xee, + 0x35, 0x42, 0x8e, 0x73, 0xfb, 0x70, 0x3c, 0x20, 0x1e, 0x96, 0x64, 0xa7, 0x19, 0xb6, 0x4d, 0xec, + 0x35, 0x88, 0xcd, 0xaa, 0x86, 0xd7, 0x72, 0x99, 0x53, 0xdd, 0xc5, 0xad, 0x40, 0xc3, 0x53, 0x86, + 0x43, 0x1b, 0x0e, 0xd5, 0x7d, 0x25, 0xfd, 0x0f, 0xb9, 0xf5, 0xb2, 0xff, 0x55, 0xa5, 0x0c, 0xed, + 0x12, 0xbb, 0x5e, 0x6d, 0x2e, 0x6c, 0x63, 0x86, 0x16, 0x82, 0x6f, 0x49, 0x35, 0x27, 0xa9, 0xb6, + 0x11, 0xc5, 0xbe, 0xf9, 0x43, 0x42, 0x17, 0xd5, 0x89, 0x2d, 0xec, 0xe9, 0xd3, 0xaa, 0x97, 0xc1, + 0xd4, 0x7b, 0x9c, 0x62, 0x59, 0x2a, 0xb2, 0x86, 0x6d, 0x4c, 0x09, 0xd5, 0xf0, 0xfd, 0x3d, 0x4c, + 0x19, 0x2c, 0x83, 0x42, 0xa0, 0xa2, 0x4e, 0xcc, 0xa2, 0x32, 0xa3, 0xcc, 0x8e, 0x6a, 0x20, 0x58, + 0x5a, 0x37, 0xd5, 0x47, 0xe0, 0x74, 0x32, 0x3f, 0x75, 0x1d, 0x9b, 0x62, 0xf8, 0x21, 0x18, 0xab, + 0xfb, 0x4b, 0x3a, 0x65, 0x88, 0x61, 0x01, 0x51, 0x58, 0x9c, 0xaf, 0x74, 0xf3, 0x84, 0xe6, 0x42, + 0x25, 0x86, 0xb5, 0xc9, 0xf9, 0x6a, 0x43, 0x5f, 0x3e, 0x29, 0x0f, 0x68, 0x47, 0xeb, 0x1d, 0x6b, + 0xea, 0xaf, 0x14, 0x50, 0x8a, 0x9c, 0xbe, 0xcc, 0xf1, 0x42, 0xe1, 0xaf, 0x83, 0x61, 0x77, 0x07, + 0x51, 0xff, 0xcc, 0xf1, 0xc5, 0xc5, 0x4a, 0x0a, 0xef, 0x0b, 0x0f, 0xdf, 0xe0, 0x9c, 0x9a, 0x0f, + 0x00, 0x57, 0x01, 0x68, 0x5b, 0xae, 0x98, 0x13, 0x2a, 0x7c, 0xa7, 0x22, 0xaf, 0x86, 0x9b, 0xb9, + 0xe2, 0x7b, 0xb9, 0x34, 0x73, 0x65, 0x03, 0xd5, 0xb1, 0x94, 0x42, 0xeb, 0xe0, 0x54, 0x7f, 0xa9, + 0xc4, 0xcc, 0x1d, 0x08, 0x2c, 0xad, 0x55, 0x03, 0x23, 0x42, 0x3c, 0x5a, 0x54, 0x66, 0x06, 0x67, + 0x0b, 0x8b, 0x73, 0xe9, 0x44, 0xe6, 0xdb, 0x9a, 0xe4, 0x84, 0x6b, 0x09, 0xb2, 0x7e, 0xb7, 0xa7, + 0xac, 0xbe, 0x00, 0x11, 0x61, 0x3f, 0x1b, 0x06, 0xc3, 0x02, 0x1a, 0x9e, 0x02, 0x79, 0x5f, 0x84, + 0xd0, 0x05, 0x8e, 0x88, 0xef, 0x75, 0x13, 0x4e, 0x81, 0x51, 0xc3, 0x22, 0xd8, 0x66, 0x7c, 0x2f, + 0x27, 0xf6, 0xf2, 0xfe, 0xc2, 0xba, 0x09, 0x8f, 0x83, 0x61, 0xe6, 0xb8, 0xfa, 0xad, 0xe2, 0xe0, + 0x8c, 0x32, 0x3b, 0xa6, 0x0d, 0x31, 0xc7, 0xbd, 0x05, 0xe7, 0x00, 0x6c, 0x10, 0x5b, 0x77, 0x9d, + 0x07, 0xdc, 0xa7, 0x6c, 0xdd, 0xa7, 0x18, 0x9a, 0x51, 0x66, 0x07, 0xb5, 0xf1, 0x06, 0xb1, 0x37, + 0xf8, 0xc6, 0xba, 0xbd, 0xc5, 0x69, 0xe7, 0xc1, 0x44, 0x13, 0x59, 0xc4, 0x44, 0xcc, 0xf1, 0xa8, + 0x64, 0x31, 0x90, 0x5b, 0x1c, 0x16, 0x78, 0xb0, 0xbd, 0x27, 0x98, 0x96, 0x91, 0x0b, 0xe7, 0xc0, + 0x8b, 0xe1, 0xaa, 0x4e, 0x31, 0x13, 0xe4, 0x23, 0x82, 0xfc, 0x58, 0xb8, 0xb1, 0x89, 0x19, 0xa7, + 0x3d, 0x0d, 0x46, 0x91, 0x65, 0x39, 0x0f, 0x2c, 0x42, 0x59, 0xf1, 0xc8, 0xcc, 0xe0, 0xec, 0xa8, + 0xd6, 0x5e, 0x80, 0x25, 0x90, 0x37, 0xb1, 0xdd, 0x12, 0x9b, 0x79, 0xb1, 0x19, 0x7e, 0xc3, 0x89, + 0xc0, 0xb3, 0x46, 0x85, 0xc6, 0xd2, 0x4b, 0x3e, 0x00, 0xf9, 0x06, 0x66, 0xc8, 0x44, 0x0c, 0x15, + 0x81, 0xb0, 0xfb, 0x6b, 0x99, 0x5c, 0xee, 0xa6, 0x64, 0x96, 0xbe, 0x1e, 0x82, 0x71, 0x23, 0x73, + 0x93, 0xf1, 0x28, 0xc7, 0xc5, 0xc2, 0x8c, 0x32, 0x3b, 0xa4, 0xe5, 0x1b, 0xc4, 0xde, 0xe4, 0xdf, + 0xb0, 0x02, 0x8e, 0x0b, 0xa1, 0x75, 0x62, 0x23, 0x83, 0x91, 0x26, 0xd6, 0x9b, 0xc8, 0xa2, 0xc5, + 0xa3, 0x33, 0xca, 0x6c, 0x5e, 0x7b, 0x51, 0x6c, 0xad, 0xcb, 0x9d, 0x3b, 0xc8, 0xa2, 0xf1, 0x90, + 0x1e, 0x8b, 0x87, 0x34, 0x7c, 0x08, 0x4e, 0x85, 0x56, 0xc0, 0xa6, 0xee, 0xe1, 0x07, 0xc8, 0x33, + 0x75, 0x13, 0xdb, 0x4e, 0x83, 0x16, 0xc7, 0x85, 0x5e, 0xef, 0xa4, 0xd2, 0x6b, 0xa9, 0x8d, 0xa2, + 0x09, 0x90, 0x6b, 0x02, 0x43, 0x9b, 0x44, 0xc9, 0x1b, 0x50, 0x05, 0x47, 0x5d, 0x8f, 0x38, 0x1c, + 0x4c, 0x98, 0xfd, 0x98, 0x30, 0x7b, 0x64, 0x4d, 0xfd, 0x99, 0x02, 0xce, 0x88, 0x10, 0xba, 0x13, + 0xdc, 0x66, 0x60, 0xbe, 0x25, 0xd3, 0xf4, 0x82, 0xd0, 0xbf, 0x04, 0x5e, 0x08, 0x24, 0xd1, 0x91, + 0x69, 0x7a, 0x98, 0x52, 0xdf, 0x73, 0x6b, 0xf0, 0xdb, 0x27, 0xe5, 0xf1, 0x16, 0x6a, 0x58, 0x17, + 0x55, 0xb9, 0xa1, 0x6a, 0xc7, 0x02, 0xda, 0x25, 0x7f, 0x25, 0x6e, 0xa3, 0x5c, 0xdc, 0x46, 0x17, + 0xf3, 0x1f, 0x7f, 0x5e, 0x1e, 0xf8, 0xe7, 0xe7, 0xe5, 0x01, 0xf5, 0x36, 0x50, 0xf7, 0x13, 0x47, + 0x06, 0xf6, 0x2b, 0xe0, 0x85, 0x10, 0x30, 0x22, 0x8f, 0x76, 0xcc, 0xe8, 0xa0, 0xe7, 0xd2, 0x3c, + 0xaf, 0xe0, 0x46, 0x87, 0x74, 0x1d, 0x0a, 0x26, 0x03, 0x26, 0x2b, 0x18, 0x3b, 0xa4, 0x2f, 0x05, + 0xa3, 0xe2, 0xb4, 0x15, 0x4c, 0x36, 0xf8, 0x73, 0xc6, 0x55, 0xa7, 0xc0, 0x29, 0x01, 0xb8, 0xb5, + 0xe3, 0x39, 0x8c, 0x59, 0x58, 0xe4, 0x72, 0xa9, 0x97, 0xfa, 0x87, 0x20, 0xa5, 0xc7, 0x76, 0xe5, + 0x31, 0x65, 0x50, 0xa0, 0x16, 0xa2, 0x3b, 0x7a, 0x03, 0x33, 0xec, 0x89, 0x13, 0x06, 0x35, 0x20, + 0x96, 0x6e, 0xf2, 0x15, 0xb8, 0x08, 0x4e, 0x74, 0x10, 0xe8, 0xc2, 0xd3, 0x90, 0x6d, 0x60, 0xa1, + 0xe2, 0xa0, 0x76, 0xbc, 0x4d, 0xba, 0x14, 0x6c, 0xc1, 0x1f, 0x80, 0xa2, 0x8d, 0x1f, 0x32, 0xdd, + 0xc3, 0xae, 0x85, 0x6d, 0x42, 0x77, 0x74, 0x03, 0xd9, 0x26, 0x57, 0x16, 0x8b, 0xcc, 0x55, 0x58, + 0x2c, 0x55, 0xfc, 0xfa, 0xa2, 0x12, 0xd4, 0x17, 0x95, 0xad, 0xa0, 0xbe, 0xa8, 0xe5, 0x79, 0xb0, + 0x7e, 0xf2, 0xd7, 0xb2, 0xa2, 0x9d, 0xe4, 0x28, 0x5a, 0x00, 0xb2, 0x1c, 0x60, 0xa8, 0xaf, 0x82, + 0x39, 0xa1, 0x92, 0x86, 0xeb, 0xdc, 0xe7, 0x3d, 0x6c, 0x06, 0x3e, 0x12, 0x09, 0x0b, 0x69, 0x81, + 0x15, 0x70, 0x3e, 0x15, 0xb5, 0xb4, 0xc8, 0x49, 0x30, 0x22, 0x43, 0x53, 0x11, 0xd1, 0x22, 0xbf, + 0xd4, 0x77, 0xc1, 0x2b, 0x02, 0x66, 0xc9, 0xb2, 0x36, 0x10, 0xf1, 0xe8, 0x1d, 0x64, 0x71, 0x1c, + 0x7e, 0x09, 0xb5, 0x56, 0x1b, 0x31, 0xe5, 0x33, 0xff, 0x0b, 0x45, 0xea, 0xd0, 0x03, 0x4e, 0x0a, + 0x75, 0x1f, 0xbc, 0xe8, 0x22, 0xe2, 0xf1, 0x4c, 0xc4, 0x4b, 0x24, 0xe1, 0x11, 0xf2, 0x49, 0x5b, + 0x4d, 0x95, 0x3a, 0xf8, 0x19, 0xfe, 0x11, 0xfc, 0x84, 0xd0, 0xe3, 0xec, 0xb6, 0x2d, 0xc6, 0xdd, + 0x08, 0x89, 0xfa, 0x5f, 0x05, 0x9c, 0xe9, 0xc9, 0x05, 0x57, 0xbb, 0xe6, 0x85, 0xa9, 0x6f, 0x9f, + 0x94, 0x27, 0xfd, 0xb0, 0x89, 0x53, 0x24, 0x24, 0x88, 0xd5, 0x84, 0xf0, 0xcb, 0xc5, 0x71, 0xe2, + 0x14, 0x09, 0x71, 0x78, 0x05, 0x1c, 0x0d, 0xa9, 0x76, 0x71, 0x4b, 0xba, 0xdb, 0xe9, 0x4a, 0xbb, + 0x40, 0xac, 0xf8, 0x05, 0x62, 0x65, 0x63, 0x6f, 0xdb, 0x22, 0xc6, 0x0d, 0xdc, 0xd2, 0xc2, 0xab, + 0xba, 0x81, 0x5b, 0xea, 0x04, 0x80, 0xe2, 0x5e, 0x36, 0x90, 0x87, 0xda, 0x3e, 0xf4, 0x43, 0x70, + 0x3c, 0xb2, 0x2a, 0xaf, 0x65, 0x1d, 0x8c, 0xb8, 0x62, 0x45, 0x56, 0x61, 0xe7, 0x53, 0xde, 0x05, + 0x67, 0x91, 0x8f, 0x92, 0x04, 0x50, 0x6f, 0x4a, 0x7f, 0x88, 0x14, 0x32, 0xb7, 0x5d, 0x86, 0xcd, + 0x75, 0x3b, 0xcc, 0x14, 0xe9, 0xcb, 0xc8, 0xfb, 0xd2, 0xe9, 0x7b, 0xc1, 0x85, 0x75, 0xd2, 0x4b, + 0x9d, 0x75, 0x41, 0xec, 0xbe, 0x70, 0x10, 0x0b, 0x53, 0x1d, 0x05, 0x42, 0xf4, 0x02, 0x31, 0x55, + 0x97, 0xc0, 0x74, 0xe4, 0xc8, 0x03, 0x48, 0xfd, 0xe9, 0x11, 0x30, 0xd3, 0x05, 0x23, 0xfc, 0xd5, + 0xef, 0x53, 0x14, 0xf7, 0x90, 0x5c, 0x46, 0x0f, 0x81, 0x45, 0x30, 0x2c, 0x0a, 0x27, 0xe1, 0x5b, + 0x83, 0xb5, 0x5c, 0x51, 0xd1, 0xfc, 0x05, 0xf8, 0x16, 0x18, 0xf2, 0x78, 0x8e, 0x1b, 0x12, 0xd2, + 0x9c, 0xe3, 0xf7, 0xfb, 0xcd, 0x93, 0xf2, 0x94, 0x5f, 0x2a, 0x52, 0x73, 0xb7, 0x42, 0x9c, 0x6a, + 0x03, 0xb1, 0x9d, 0xca, 0xbb, 0xb8, 0x8e, 0x8c, 0xd6, 0x35, 0x6c, 0x14, 0x15, 0x4d, 0xb0, 0xc0, + 0x73, 0x60, 0x3c, 0x94, 0xca, 0x47, 0x1f, 0x16, 0xf9, 0x75, 0x2c, 0x58, 0x15, 0x05, 0x19, 0xbc, + 0x07, 0x8a, 0x21, 0x99, 0xe1, 0x34, 0x1a, 0x84, 0x52, 0xe2, 0xd8, 0xba, 0x38, 0x75, 0x44, 0x9c, + 0x7a, 0x36, 0xc5, 0xa9, 0xda, 0xc9, 0x00, 0x64, 0x39, 0xc4, 0xd0, 0xb8, 0x14, 0xf7, 0x40, 0x31, + 0x34, 0x6d, 0x1c, 0xfe, 0x48, 0x06, 0xf8, 0x00, 0x24, 0x06, 0x7f, 0x03, 0x14, 0x4c, 0x4c, 0x0d, + 0x8f, 0xb8, 0xa2, 0x94, 0xce, 0x0b, 0xcb, 0x9f, 0x0d, 0x4a, 0xe9, 0xa0, 0xe7, 0x0a, 0xea, 0xe8, + 0x6b, 0x6d, 0x52, 0x19, 0x2b, 0x9d, 0xdc, 0xf0, 0x1e, 0x38, 0x15, 0xca, 0xea, 0xb8, 0xd8, 0x13, + 0x05, 0x6a, 0xe0, 0x0f, 0xa2, 0x8c, 0xac, 0x9d, 0xf9, 0xfa, 0x8b, 0x0b, 0x2f, 0x49, 0xf4, 0xd0, + 0x7f, 0xa4, 0x1f, 0x6c, 0x32, 0x8f, 0xd8, 0x75, 0x6d, 0x32, 0xc0, 0xb8, 0x2d, 0x21, 0x02, 0x37, + 0x39, 0x09, 0x46, 0x7e, 0x84, 0x88, 0x85, 0x4d, 0x51, 0x79, 0xe6, 0x35, 0xf9, 0x05, 0x2f, 0x82, + 0x11, 0xde, 0x77, 0xed, 0x51, 0x51, 0x37, 0x8e, 0x2f, 0xaa, 0xdd, 0xc4, 0xaf, 0x39, 0xb6, 0xb9, + 0x29, 0x28, 0x35, 0xc9, 0x01, 0xb7, 0x40, 0xe8, 0x8d, 0x3a, 0x73, 0x76, 0xb1, 0xed, 0x57, 0x95, + 0xa3, 0xb5, 0xf3, 0xd2, 0xaa, 0x27, 0x9e, 0xb7, 0xea, 0xba, 0xcd, 0xbe, 0xfe, 0xe2, 0x02, 0x90, + 0x87, 0xac, 0xdb, 0x4c, 0x1b, 0x0f, 0x30, 0xb6, 0x04, 0x04, 0x77, 0x9d, 0x10, 0xd5, 0x77, 0x9d, + 0x31, 0xdf, 0x75, 0x82, 0x55, 0xdf, 0x75, 0x5e, 0x07, 0x93, 0x32, 0x7a, 0x31, 0xd5, 0x8d, 0x3d, + 0xcf, 0xe3, 0x3d, 0x06, 0x76, 0x1d, 0x63, 0x47, 0xd4, 0xa0, 0x79, 0xed, 0x44, 0xb8, 0xbd, 0xec, + 0xef, 0xae, 0xf0, 0x4d, 0xf5, 0x63, 0x05, 0x94, 0xbb, 0xc6, 0xb5, 0x4c, 0x1f, 0x18, 0x80, 0x76, + 0x66, 0x90, 0xef, 0xd2, 0x4a, 0xaa, 0x5c, 0xd8, 0x2b, 0xda, 0xb5, 0x0e, 0x60, 0xf5, 0x3e, 0x98, + 0x4f, 0x68, 0xf6, 0x42, 0xda, 0xeb, 0x88, 0x6e, 0x39, 0xf2, 0x0b, 0x1f, 0x4e, 0xe1, 0xaa, 0xde, + 0x01, 0x0b, 0x19, 0x8e, 0x94, 0xe6, 0x38, 0xd3, 0x91, 0x62, 0x88, 0x19, 0x24, 0xcf, 0x42, 0x3b, + 0xd1, 0x89, 0xa2, 0xf4, 0x7c, 0x72, 0x99, 0x1b, 0x8d, 0x99, 0xb4, 0xa9, 0x33, 0x51, 0xcf, 0x5c, + 0x7a, 0x3d, 0xeb, 0xe0, 0xd5, 0x74, 0xe2, 0x48, 0x15, 0xdf, 0x90, 0xa9, 0x4e, 0x49, 0x9f, 0x15, + 0x04, 0x83, 0xaa, 0xca, 0x0c, 0x5f, 0xb3, 0x1c, 0x63, 0x97, 0xbe, 0x6f, 0x33, 0x62, 0xdd, 0xc2, + 0x0f, 0x7d, 0x5f, 0x0b, 0x5e, 0xdb, 0xbb, 0xb2, 0x60, 0x4f, 0xa6, 0x91, 0x12, 0xbc, 0x06, 0x26, + 0xb7, 0xc5, 0xbe, 0xbe, 0xc7, 0x09, 0x74, 0x51, 0x71, 0xfa, 0xfe, 0xac, 0x88, 0x8e, 0x6e, 0x62, + 0x3b, 0x81, 0x5d, 0x5d, 0x92, 0xd5, 0xf7, 0x72, 0x68, 0xba, 0x55, 0xcf, 0x69, 0x2c, 0xcb, 0x0e, + 0x3b, 0x30, 0x77, 0xa4, 0x0b, 0x57, 0xa2, 0x5d, 0xb8, 0xba, 0x0a, 0xce, 0xee, 0x0b, 0xd1, 0x2e, + 0xad, 0xf7, 0x7f, 0xed, 0xde, 0x91, 0x75, 0x7b, 0xc4, 0xb7, 0x52, 0xbf, 0x95, 0xbf, 0x1b, 0x4c, + 0x9a, 0xd5, 0xa4, 0x3e, 0x3d, 0x32, 0x83, 0xc8, 0x45, 0x67, 0x10, 0x67, 0xc1, 0x98, 0xf3, 0xc0, + 0xee, 0x70, 0xa4, 0x41, 0xb1, 0x7f, 0x54, 0x2c, 0x06, 0x09, 0x32, 0x6c, 0xd9, 0x87, 0xba, 0xb5, + 0xec, 0xc3, 0x87, 0xd9, 0xb2, 0x7f, 0x04, 0x0a, 0xc4, 0x26, 0x4c, 0x97, 0xf5, 0xd6, 0x88, 0xc0, + 0x5e, 0xc9, 0x84, 0xbd, 0x6e, 0x13, 0x46, 0x90, 0x45, 0x7e, 0x2c, 0xc6, 0x31, 0xa2, 0x0a, 0xe3, + 0x7d, 0x0b, 0xd5, 0x00, 0x47, 0xf6, 0xab, 0x32, 0xd8, 0x00, 0x13, 0xfe, 0x58, 0x84, 0xee, 0x20, + 0x97, 0xd8, 0xf5, 0xe0, 0xc0, 0x23, 0xe2, 0xc0, 0xb7, 0xd3, 0x15, 0x78, 0x1c, 0x60, 0xd3, 0xe7, + 0xef, 0x38, 0x06, 0xba, 0xf1, 0x75, 0xaa, 0xd6, 0x62, 0xc9, 0x55, 0x8e, 0xe8, 0x78, 0x37, 0x94, + 0xda, 0x13, 0x76, 0x63, 0x45, 0x53, 0x04, 0x43, 0xba, 0xc3, 0x1a, 0x08, 0x26, 0x7d, 0x3a, 0x23, + 0x8d, 0x60, 0x6a, 0x98, 0xae, 0x0d, 0x2b, 0xd4, 0xdb, 0x80, 0x8b, 0xdf, 0x94, 0xc1, 0xb0, 0x38, + 0x0d, 0xfe, 0x43, 0x01, 0x13, 0x49, 0xe7, 0xc2, 0xab, 0xd9, 0x33, 0x7f, 0x74, 0x4a, 0x5a, 0x5a, + 0xea, 0x03, 0xc1, 0x57, 0x58, 0xbd, 0xfe, 0x93, 0x3f, 0xfe, 0xfd, 0xb3, 0x5c, 0x0d, 0x5e, 0xed, + 0x3d, 0x53, 0x0f, 0xad, 0x2b, 0xf5, 0xac, 0x3e, 0xea, 0xb0, 0xf7, 0x63, 0xf8, 0x67, 0x45, 0x16, + 0xff, 0xd1, 0x37, 0x00, 0x5e, 0xc9, 0x2e, 0x64, 0x64, 0x9c, 0x5a, 0xba, 0x7a, 0x70, 0x00, 0xa9, + 0xe4, 0x92, 0x50, 0xf2, 0x6d, 0xf8, 0x56, 0x06, 0x25, 0xfd, 0xa9, 0x66, 0xf5, 0x91, 0x88, 0xd7, + 0xc7, 0xf0, 0xd3, 0x9c, 0x4c, 0x23, 0x89, 0xf3, 0x16, 0xb8, 0x9a, 0x5e, 0xc6, 0xfd, 0xe6, 0x47, + 0xa5, 0xb5, 0xbe, 0x71, 0xa4, 0xca, 0xdb, 0x42, 0xe5, 0xef, 0xc3, 0xbb, 0x29, 0xfe, 0x56, 0x12, + 0xce, 0x2d, 0x23, 0x8d, 0x63, 0xf4, 0x7a, 0xab, 0x8f, 0xe2, 0xcf, 0x66, 0x92, 0x4d, 0x3a, 0xbb, + 0x9d, 0x03, 0xd9, 0x24, 0x61, 0xe4, 0x74, 0x20, 0x9b, 0x24, 0xcd, 0x8a, 0x0e, 0x66, 0x93, 0x88, + 0xda, 0x71, 0x9b, 0xc4, 0x3b, 0xed, 0xc7, 0xf0, 0xf7, 0x8a, 0x6c, 0x8c, 0x23, 0x73, 0x24, 0x78, + 0x39, 0xbd, 0x0e, 0x49, 0xe3, 0xa9, 0xd2, 0x95, 0x03, 0xf3, 0x4b, 0xdd, 0xdf, 0x14, 0xba, 0x2f, + 0xc2, 0xf9, 0xde, 0xba, 0x33, 0x09, 0xe0, 0xff, 0xe1, 0x04, 0xfe, 0x3c, 0x27, 0xdf, 0xf1, 0xfd, + 0x07, 0x43, 0xf0, 0x76, 0x7a, 0x11, 0x53, 0x0d, 0xa4, 0x4a, 0x1b, 0x87, 0x07, 0x28, 0x8d, 0x70, + 0x43, 0x18, 0x61, 0x05, 0x2e, 0xf7, 0x36, 0x82, 0x17, 0x22, 0xb6, 0xa3, 0x22, 0x32, 0x91, 0x86, + 0x3f, 0xcd, 0xc9, 0x12, 0x69, 0xdf, 0xd1, 0x14, 0xbc, 0x95, 0x5e, 0x8b, 0x34, 0x23, 0xb3, 0xd2, + 0xed, 0x43, 0xc3, 0x93, 0x46, 0x59, 0x11, 0x46, 0xb9, 0x02, 0x2f, 0xf5, 0x36, 0x8a, 0xf4, 0x72, + 0xdd, 0xe5, 0xa8, 0xb1, 0xf4, 0xff, 0x1b, 0x05, 0x14, 0x3a, 0x66, 0x3f, 0xf0, 0x8d, 0xf4, 0x72, + 0x46, 0x66, 0x48, 0xa5, 0x37, 0xb3, 0x33, 0x4a, 0x4d, 0xe6, 0x85, 0x26, 0x73, 0x70, 0xb6, 0xb7, + 0x26, 0x7e, 0xb5, 0xd2, 0xf6, 0xed, 0xfd, 0xe7, 0x3f, 0x59, 0x7c, 0x3b, 0xd5, 0x60, 0x2a, 0x8b, + 0x6f, 0xa7, 0x1b, 0x4d, 0x65, 0xf1, 0x6d, 0x87, 0x83, 0xe8, 0xc4, 0xd6, 0xdb, 0x3d, 0x63, 0xec, + 0x32, 0x7f, 0x9b, 0x93, 0x53, 0xdc, 0x34, 0xfd, 0x1c, 0x7c, 0xff, 0xa0, 0x0f, 0xf4, 0xbe, 0x2d, + 0x69, 0xe9, 0xce, 0x61, 0xc3, 0x4a, 0x4b, 0xdd, 0x15, 0x96, 0xda, 0x82, 0x5a, 0xe6, 0x6a, 0x40, + 0x77, 0xb1, 0xd7, 0x36, 0x5a, 0xd2, 0x93, 0xf8, 0xeb, 0x1c, 0x78, 0x39, 0x4d, 0x83, 0x08, 0x37, + 0xfa, 0x78, 0xe8, 0x13, 0x5b, 0xdf, 0xd2, 0x7b, 0x87, 0x88, 0x28, 0x2d, 0x65, 0x08, 0x4b, 0xdd, + 0x83, 0x1f, 0x66, 0xb1, 0x54, 0x74, 0x1e, 0xd6, 0xbb, 0x8a, 0xf8, 0xb7, 0x02, 0x26, 0xbb, 0x8c, + 0x37, 0xe0, 0x72, 0x3f, 0xc3, 0x91, 0xc0, 0x30, 0xd7, 0xfa, 0x03, 0xc9, 0x1e, 0x5f, 0xa1, 0xc6, + 0x5d, 0xe3, 0xeb, 0x5f, 0x8a, 0xec, 0x69, 0x93, 0x5a, 0x77, 0x98, 0x61, 0x24, 0xb4, 0xcf, 0x78, + 0xa0, 0xb4, 0xda, 0x2f, 0x4c, 0xf6, 0xea, 0xb9, 0xcb, 0xa4, 0x01, 0xfe, 0x27, 0xfe, 0xff, 0x07, + 0xd1, 0x59, 0x00, 0x5c, 0xcb, 0x7e, 0x45, 0x89, 0x03, 0x89, 0xd2, 0xf5, 0xfe, 0x81, 0xfa, 0xe8, + 0x19, 0x88, 0x59, 0x7d, 0x14, 0xce, 0x43, 0x1e, 0xc3, 0xbf, 0x04, 0xb5, 0x60, 0x24, 0x3d, 0x65, + 0xa9, 0x05, 0x93, 0x46, 0x1e, 0xa5, 0x2b, 0x07, 0xe6, 0x97, 0xaa, 0xad, 0x0a, 0xd5, 0xae, 0xc2, + 0xcb, 0x59, 0x13, 0x60, 0xcc, 0x8b, 0xff, 0xa7, 0x80, 0x62, 0xb7, 0x8e, 0x1a, 0x5e, 0x3b, 0x70, + 0x6f, 0xda, 0xd1, 0xd4, 0x97, 0x56, 0xfa, 0x44, 0x91, 0x1a, 0xdf, 0x14, 0x1a, 0xaf, 0xc1, 0x95, + 0xec, 0x5d, 0xae, 0x98, 0x03, 0x44, 0x15, 0xaf, 0x7d, 0xf0, 0xe5, 0xd3, 0x69, 0xe5, 0xab, 0xa7, + 0xd3, 0xca, 0xdf, 0x9e, 0x4e, 0x2b, 0x9f, 0x3c, 0x9b, 0x1e, 0xf8, 0xea, 0xd9, 0xf4, 0xc0, 0x9f, + 0x9e, 0x4d, 0x0f, 0xdc, 0xbd, 0x54, 0x27, 0x6c, 0x67, 0x6f, 0xbb, 0x62, 0x38, 0x0d, 0xf9, 0x1f, + 0x54, 0x1d, 0x27, 0x5e, 0x08, 0x4f, 0x6c, 0xbe, 0x5e, 0x7d, 0x18, 0x2b, 0xba, 0x5b, 0x2e, 0xa6, + 0xdb, 0x23, 0x62, 0xc0, 0xf0, 0xbd, 0xff, 0x07, 0x00, 0x00, 0xff, 0xff, 0x93, 0x7a, 0xb2, 0x53, + 0xe1, 0x26, 0x00, 0x00, } // Reference imports to suppress errors if they are not otherwise used. @@ -2964,6 +2977,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]) @@ -4310,6 +4332,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 } @@ -5573,6 +5601,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:])